/// <summary>
        /// Draws a prefab at the pre-calculated mouse hit position
        /// </summary>
        private void DrawThePrefab()
        {
#if PERFORMANCE
            var perf = PerformanceTesting <PerformanceID> .Instance;
            perf.Start(PerformanceID.Draw);
#endif

            // do not draw if not the view tool
            if (Tools.current != Tool.View)
            {
#if PERFORMANCE
                perf.Stop(PerformanceID.Draw);
#endif
                return;
            }

            // checked if layer locked or not visible
            var layerModel = this.map.Layers[this.editor.ActiveLayer];
            if (layerModel.Locked || !layerModel.Visible || !this.isDrawing)
            {
#if PERFORMANCE
                perf.Stop(PerformanceID.Draw);
#endif
                return;
            }

            // Calculate the position of the mouse over the grid layer
            var gridPosition = this.editor.GetMouseGridPosition();

            // if grid position is the same as the last just exit
            if (gridPosition == this.lastPosition || this.drawRecord[gridPosition.X, gridPosition.Y] == Color.White)
            {
#if PERFORMANCE
                perf.Stop(PerformanceID.Draw);
#endif
                return;
            }

            // record last position
            this.lastPosition = gridPosition;

            // create the prefab
            var prefab = Helpers.CreatePrimitivePrefab(this.editor);
            Undo.RegisterCreatedObjectUndo(prefab, prefab.name);

            // apply drawing rules to the prefab
            var rulePrefab = this.ApplyDrawingRules(prefab, gridPosition, this.editor.ActiveLayer);

            // get grid mapping service
            var gridMappingService = GridMappingService.Instance;

            // if rulePrefab is null we check if prefab is null and destroy it if necessary
            GameObject existing;
            if (rulePrefab == null)
            {
                if (prefab != null)
                {
                    UnityEngine.Object.DestroyImmediate(prefab);
                }

                // destroy existing prefab
                existing = this.editor.GameObjects.Get(gridPosition.X, gridPosition.Y, this.editor.ActiveLayer);
                if (existing != null)
                {
                    Undo.DestroyObjectImmediate(prefab);
                }

                // make sure to erase before exiting
                this.editor.GameObjects.Set(gridPosition.X, gridPosition.Y, this.editor.ActiveLayer, null);

                // records the erase action in the draw record
                this.drawRecord[gridPosition.X, gridPosition.Y] = Color.White;

                // we can now exit
#if PERFORMANCE
                perf.Stop(PerformanceID.Draw);
#endif
                return;
            }

            // get reference to the settings manager
            var settings = SettingsManager.Instance;

            // check if original prefab and returned rulePrefab are not the same reference
            if (prefab != null && rulePrefab.GetInstanceID() != prefab.GetInstanceID())
            {
                // check if users wants output rule information to console
                if (settings.GetSetting(GlobalConstants.DrawingRulesOutputToConsoleKey, false))
                {
                    Debug.Log(LocalizationManager.Instance.Get("DestroyingOriginallyCreatedPrefab"));
                }

                // destroy originally created prefab
                UnityEngine.Object.DestroyImmediate(prefab);
            }

            // assign prefab the reference to rulePrefab
            prefab = rulePrefab;

            // make sure to erase any existing prefab before drawing any new prefab
            existing = this.editor.GameObjects.Get(gridPosition.X, gridPosition.Y, this.editor.ActiveLayer);

            if (existing != null)
            {
                Undo.DestroyObjectImmediate(existing);
            }

            var nameFormat = settings.GetSetting(GlobalConstants.PrefabNameFormatKey, "{0}_l{1}_c{2}_r{3}");

            // give the prefab a name that represents it's location within the grid map
            prefab.name = string.Format(nameFormat, prefab.name, this.editor.ActiveLayer, gridPosition.X, gridPosition.Y);

            // set local rotation first so the GetBoundWithChildren calculates properly
            var transform = prefab.transform;
            transform.localEulerAngles = new Vector3(
                this.editor.GetSelectedRotationValue(this.editor.SelectedXRotationIndex),
                this.editor.GetSelectedRotationValue(this.editor.SelectedYRotationIndex),
                this.editor.GetSelectedRotationValue(this.editor.SelectedZRotationIndex));

            // position the prefab on the map
            this.map.PositionPrefabOnMap(this.editor.ActiveLayer, gridPosition.X, gridPosition.Y, prefab, this.editor.AutoCenterPrefab, this.editor.AutoScalePrefab);

            // update game object tracker
            this.editor.GameObjects.Set(gridPosition.X, gridPosition.Y, this.editor.ActiveLayer, prefab);

            // determine whether to hide the prefab in the hierarchy based on settings
            if (!SettingsManager.Instance.GetSetting(GlobalConstants.ShowPrefabsInHierarchyKey, true))
            {
                prefab.hideFlags |= HideFlags.HideInHierarchy;
                EditorApplication.RepaintHierarchyWindow();
            }

            EditorUtility.SetDirty(prefab);

            // get grid mapping service
            gridMappingService.OnPrefabDrawn(this.map, gridPosition.X, gridPosition.Y, this.editor.ActiveLayer, prefab);

#if PERFORMANCE
            perf.Stop(PerformanceID.Draw);
#endif
        }
        /// <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);
        }