/// <summary>
        /// Shows the <see cref="DrawingRulesEditor"/> window and load the rules file for editing.
        /// </summary>
        /// <param name="filename">The xml rule file to be edited.</param>
        private void EditDrawingRule(string filename)
        {
            var window = DrawingRulesEditor.ShowAutoMaterialCreationWindow();

            window.SetFilename(filename);
            window.LoadData(false);
        }
        /// <summary>
        /// Adds a new drawing rule(s) by allowing the user to select a xml rule file.
        /// </summary>
        private void AddDrawingRule()
        {
            // get reference to localization manager
            var local = LocalizationManager.Instance;

            // prompt user to select a sync file
            var file = EditorUtility.OpenFilePanel(local.Get("SelectRuleFile"), string.Empty, "xml");

            if (file.Length == 0)
            {
                return;
            }

            // enforce directory separation characters (no alt chars)
            file = file.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);

            // check if already added rule
            if (this.drawingRules.ContainsKey(file))
            {
                EditorUtility.DisplayDialog(local.Get("Information"), local.Get("RuleSetAddedAlready"), local.Get("Close"));
                return;
            }

            // try to load rules from the file
            var rules = DrawingRulesEditor.LoadRulesFromFile(file, true);

            // if returned a result add the rules to the list
            if (rules != null)
            {
                this.drawingRules.Add(file, new DrawingRuleListItem {
                    IsChecked = true, Rules = rules
                });
                this.map.DrawingRules.Add(file);
            }
        }
        /// <summary>
        /// Called when the tool is set as the active tool.
        /// </summary>
        /// <param name="mapEditor">A reference to the editor that this tool should work against.</param>
        public void Startup(GridMapEditor mapEditor)
        {
            if (this.isActive)
            {
                return;
            }

            this.map    = (GridMap)mapEditor.target;
            this.editor = mapEditor;

            // load drawing rules
            this.drawingRules.Clear();
            foreach (var file in this.map.DrawingRules)
            {
                var rules = DrawingRulesEditor.LoadRulesFromFile(file, true);
                this.drawingRules.Add(
                    file,
                    new DrawingRuleListItem
                {
                    LastLoaded = DateTime.Now,
                    IsChecked  = true,
                    Rules      = rules
                });
            }

            var settings     = SettingsManager.Instance;
            var texturesPath = Path.Combine(settings.GetSetting(CoreGlobalConstants.ResourceFolderKey, "Codefarts.Unity"), "Textures");

            texturesPath = texturesPath.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);

            var getPath = new Func <string, string>(x => Path.Combine(texturesPath, x).Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));

            this.deleteRuleContent = new GUIContent(Resources.Load(getPath("Delete"), typeof(Texture2D)) as Texture2D);

            this.isActive = true;
            this.editor.MarkerHasStartPosition = false;

            Tools.current  = Tool.View;
            Tools.viewTool = ViewTool.FPS;
        }
        /// <summary>
        /// Applies drawing rules to the prefab.
        /// </summary>
        /// <param name="prefab">The prefab to apply the drawing rules against.</param>
        /// <param name="gridPosition">The grid position where the prefab will be drawn at.</param>
        /// <param name="layer">The destination layer where the prefab will be drawn to.</param>
        /// <returns>Returns the original prefab or a new prefab that should be drawn.</returns>
        private GameObject ApplyDrawingRules(GameObject prefab, Point gridPosition, int layer)
        {
            // get reference to localization manager
            var local = LocalizationManager.Instance;

            var prefabToReturn = prefab;
            var random         = new Random((int)DateTime.Now.Ticks);
            var settings       = SettingsManager.Instance;
            var consoleOutput  = settings.GetSetting(GlobalConstants.DrawingRulesOutputToConsoleKey, false);
            var consoleText    = string.Empty;

            // for each enabled rule
            foreach (var pair in this.drawingRules)
            {
                if (!pair.Value.IsChecked)
                {
                    continue;
                }

                // check if xml rule file has changed since last read
                if (File.GetLastWriteTime(pair.Key) > pair.Value.LastLoaded)
                {
                    consoleText += local.Get("LoadingUpdatedRulesFromDisk") + "\r\n";

                    // reload the rules
                    var rules = DrawingRulesEditor.LoadRulesFromFile(pair.Key, false);

                    // if returned null there may have been an error reading the file
                    if (rules == null)
                    {
                        return(null);
                    }

                    pair.Value.Rules      = rules;
                    pair.Value.LastLoaded = DateTime.Now;
                }

                foreach (var rule in pair.Value.Rules)
                {
                    consoleText += string.Format(local.Get("PerformingRuleCheck") + "\r\n", rule.Name);

                    // skip if rule not enabled
                    if (!rule.Enabled)
                    {
                        consoleText += string.Format(local.Get("InitialRuleCheckFailedNotEnabled") + "\r\n", rule.Name);
                        continue;
                    }

                    // skip if there are no alternates and not allowed to use original
                    if (rule.Alternates == null || (rule.Alternates.Count == 0 && !rule.AllowOriginal))
                    {
                        consoleText += string.Format(local.Get("InitialRuleCheckFailedOriginalNotAllowed") + "\r\n", rule.Name);
                        continue;
                    }

                    // check if prefabs have a reference and there asset paths match
                    var sourceRulePrefab = GridMapping.Helpers.GetSourcePrefab(rule.Prefab);
                    var sourcePrefab     = GridMapping.Helpers.GetSourcePrefab(prefab);
                    if (sourceRulePrefab != sourcePrefab)
                    {
                        var text = string.Format(local.Get("InitialRuleCheckFailedAssetPaths"), rule.Name);
                        text        += "\r\n" + local.Get("RuleSource") + sourceRulePrefab;
                        text        += "\r\n" + local.Get("PrefabSource") + sourcePrefab;
                        consoleText += text + "\r\n";
                        continue;
                    }

                    consoleText += local.Get("InitialCheckPassed") + "\r\n";

                    // callback for checking the existence of a prefab at a given grid location
                    var callback = new Func <int, int, int, GameObject>((column, row, layerIndex) => this.editor.GameObjects.Get(column, row, layerIndex));

                    // check if presence of neighbors match
                    var lower  = !rule.NeighborsUpperEnabled || Helpers.CheckNeighborsPassed(gridPosition, layer - 1, false, rule, callback);
                    var upper  = !rule.NeighborsUpperEnabled || Helpers.CheckNeighborsPassed(gridPosition, layer + 1, false, rule, callback);
                    var passed = Helpers.CheckNeighborsPassed(gridPosition, layer, true, rule, callback);

                    consoleText +=
                        string.Format(
                            local.Get("RulePassed") + "\r\n",
                            rule.Name,
                            passed & lower & upper,
                            passed,
                            lower,
                            upper);

                    // check if passed the neighbor tests
                    if (passed && lower && upper)
                    {
                        if ((rule.Alternates == null || rule.Alternates.Count == 0) && !rule.AllowOriginal)
                        {
                            if (consoleOutput)
                            {
                                consoleText += string.Format(local.Get("ReturningOriginal") + "\r\n", prefabToReturn.name);
                                Debug.Log(consoleText);
                            }

                            return(prefabToReturn);
                        }

                        // select from a random alternative prefab
                        var index = random.Next(rule.Alternates.Count + (rule.AllowOriginal ? 1 : 0));

                        // return the alternate prefab
                        var gameObject = index > rule.Alternates.Count - 1 ? prefabToReturn : rule.Alternates[index].Prefab;
                        if (gameObject == null)
                        {
                            if (consoleOutput)
                            {
                                consoleText += local.Get("ReturningNullResponseNoPrefabToReturn") + "\r\n";
                                Debug.Log(consoleText);
                            }

                            return(null);
                        }

                        prefabToReturn = GridMapping.Helpers.PerformInstantiation(gameObject);
                        var prefabType = PrefabUtility.GetPrefabType(gameObject);
                        consoleText += string.Format(local.Get("ReturningAlternatePrefab") + "\r\n", index, gameObject.name, prefabType);
                        if (consoleOutput && !string.IsNullOrEmpty(consoleText.Trim()))
                        {
                            Debug.Log(consoleText);
                        }

                        return(prefabToReturn);
                    }
                }
            }

            if (consoleOutput && !string.IsNullOrEmpty(consoleText.Trim()))
            {
                Debug.Log(consoleText);
            }

            return(prefabToReturn);
        }