using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using battle;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.Serialization.Formatters.Binary;

namespace battle
{
    public class classMapEditor : Form
    {
        #region "objects"
        public Form callingForm;
        public classBattle cLibBattle;
        System.Windows.Forms.Panel pnlMap = new Panel();
        PictureBox picMap = new PictureBox();
        VScrollBar VSB = new VScrollBar();
        HScrollBar HSB = new HScrollBar();
        System.Windows.Forms.Timer tmrSizechange = new System.Windows.Forms.Timer();
        Graphics gr;
        public  classEditControls formEditControls;
        #endregion

        #region "structures"

        public class classInitUnitLoc
        {
            public classBattle.enuInitialUnitLocDirIndices typeLoc;
            public int intIndex;
            public bool flag;
        }

        public class classMapEditTerrain
        {
            public classBattle.enuTerrainTypes type;
            public classInitUnitLoc initUnitLoc;
        }
        public class class2DTerrain
        {
            public classMapEditTerrain[] Rows;
        }
        #endregion

        #region "enumerated types"
        public enum enuDrawingStyle { singleCell, brush, floodfill }
        public enum enuModes { Drawing, RedLaunchSet, BlueLaunchSet }
        #endregion

        #region "variables"
        const int intVerticalOffset = 40;
        const int intScrollBarMax = 1000;

        public class2DTerrain[] TerrainColumns;

        //public Point MapSize;
        public Size szMapSize = new Size(10, 10);
        public int intMapGridSize = 35;   // pixel size of each map square as they appear on the screen

        public Point udrMouseHoverIndex = new Point();

        public enuDrawingStyle DrawingStyle = enuDrawingStyle.singleCell;
        public  bool bolToggleBrush;
        bool bolKillEditForm = false;
        
        Point[] udrBlueLaunchLocs = new Point[(int)classBattle.intMaxInvasionForce];
        classInitLaunchDisplayLabel[] lblBlueLaunchLabels = new classInitLaunchDisplayLabel[classBattle.intMaxInvasionForce];
        
        classBattle.classRedLaunchLocations udrRedLaunchLocs = new classBattle.classRedLaunchLocations();
        classInitLaunchDisplayLabel[] lblRedLaunchLabels = new classInitLaunchDisplayLabel[classBattle.intMaxInvasionForce];
        public int intRedLaunchDirIndex = 0;
        public enuModes mode = enuModes.Drawing;
        public bool bolBlinkCursor, bolBlinkCursorImage;
        Cursor cRememberCursor;
        Timer tmrBlinkCurosr = new Timer();
        #endregion

        public classMapEditor(classBattle _cLibBattle, Form callingForm_local)
        {
            cLibBattle = _cLibBattle;
            callingForm = callingForm_local;
            Text = "Map Editor";

            Controls.Add(HSB);
            HSB.Visible = true;

            Controls.Add(VSB);
            VSB.Visible = true;

            Controls.Add(pnlMap);
            pnlMap.Visible = true;

            tmrSizechange.Tick += new EventHandler(tmrSizechange_Tick);
            SizeChanged += new EventHandler(classMapEditor_SizeChanged);

            Disposed += new EventHandler(classMapEditor_Disposed);

            VSB.ValueChanged += new EventHandler(VSB_ValueChanged);
            HSB.ValueChanged += new EventHandler(HSB_ValueChanged);

            setMenuStrip();
            pnlMap.Controls.Add(picMap);
            picMap.Dock = DockStyle.Fill;
            picMap.Visible = true;
            gr = picMap.CreateGraphics();
            szMapSize.Width = 15; szMapSize.Height = 15;
                        
            createEditForm();
            resizeMap();
            displayMap();
            resetScrollBars();
            tmrBlinkCurosr.Interval = 500;
            tmrBlinkCurosr.Tick += new EventHandler(tmrBlinkCurosr_Tick);
           
            picMap.MouseMove += new MouseEventHandler(picMap_MouseMove);
            picMap.Click += new EventHandler(picMap_Click);
            picMap.Paint += new PaintEventHandler(picMap_Paint);
            Activated += new EventHandler(classMapEditor_Activated);
        }

        void picMap_Paint(object sender, PaintEventArgs e)
        {
            PictureBox thisPic = (PictureBox)sender;

            //thisPic.Image = e.Graphics.
        }

        void classMapEditor_Activated(object sender, EventArgs e) 
        {
        //    displayMap(); 
        }

        void picMap_MouseMove(object sender, MouseEventArgs e)
        {
            PictureBox picMap = (PictureBox)sender;
            Point udrLoc_New = determineMapGridLocByObjectLoc(e.X, e.Y);
            if (ptOnMap (udrLoc_New))
            {
            Text = "(" + udrLoc_New.X.ToString() + ", " + udrLoc_New.Y.ToString() + ")";
            
            if (udrLoc_New.X != udrMouseHoverIndex.X
                || udrLoc_New.Y != udrMouseHoverIndex.Y)
            {
                displayMapLoc(udrMouseHoverIndex, classBattle.enuTerrainImageSetting.normal);
                udrMouseHoverIndex = udrLoc_New;
                displayMapLoc(udrMouseHoverIndex, classBattle.enuTerrainImageSetting.shaded);
             
            }
            if (DrawingStyle == enuDrawingStyle.brush && bolToggleBrush)
            {
                TerrainColumns[udrMouseHoverIndex.X].Rows[udrMouseHoverIndex.Y].type = formEditControls.SelectedNewTerrainType;
            }
            showHoverOverTerrainInfo();
            }
            picMap.Refresh();
        }

        void displayMapLoc(Point udrLoc,classBattle. enuTerrainImageSetting terrainImageSetting)
        {
            if (ptOnMap(udrLoc))
            {
                Point pt = new Point(getGridMapObjectLeft(udrLoc.X), getGridMapObjectTop(udrLoc));
                gr.DrawImage(cLibBattle.getTerrainImage(TerrainColumns[udrLoc.X].Rows[udrLoc.Y].type, terrainImageSetting), pt.X, pt.Y, intMapGridSize, intMapGridSize);
            }
        }

        Image ResizeImage(Image imgInput) { return ResizeImage(intMapGridSize, imgInput); }
        Image ResizeImage(int intSizeSquare, Image imgInput) { return ResizeImage(cLibBattle.getPos(intSizeSquare, intSizeSquare), imgInput); }
        Image ResizeImage(Point udrNewDimensions, Image imgInput) { return new Bitmap(imgInput, udrNewDimensions.X, udrNewDimensions.Y); }
 
        void picMap_Click(object sender, EventArgs e)
        {
            switch (mode)
            {
                case enuModes.Drawing:
                    if (DrawingStyle == enuDrawingStyle.singleCell)
                        TerrainColumns[udrMouseHoverIndex.X].Rows[udrMouseHoverIndex.Y].type = formEditControls.SelectedNewTerrainType;
                    else if (DrawingStyle == enuDrawingStyle.floodfill)
                        floodFill();
                    else if (DrawingStyle == enuDrawingStyle.brush)
                    {
                        bolToggleBrush = !bolToggleBrush;
                        displayBolToggleBrush();
                    }
                    break;

                case enuModes.BlueLaunchSet:
                    if (TerrainColumns[udrMouseHoverIndex.X].Rows[udrMouseHoverIndex.Y].initUnitLoc.flag)
                        return;
                    resetTerrainInitUnitLoc(udrBlueLaunchLocs[formEditControls.intCurrentBlueLaunchLabelCounter]);
                    udrBlueLaunchLocs[formEditControls.intCurrentBlueLaunchLabelCounter] = udrMouseHoverIndex;
                    setTerrainInitUnitLoc(udrMouseHoverIndex, classBattle.enuInitialUnitLocDirIndices.Blue, formEditControls.intCurrentBlueLaunchLabelCounter);
                    formEditControls.intCurrentBlueLaunchLabelCounter = (formEditControls.intCurrentBlueLaunchLabelCounter + 1) % classBattle.intMaxInvasionForce;
                    displayBlueLaunchLabels();
                    break;

                case enuModes.RedLaunchSet:
                    if (TerrainColumns[udrMouseHoverIndex.X].Rows[udrMouseHoverIndex.Y].initUnitLoc.flag)
                        return;
                    resetTerrainInitUnitLoc(udrRedLaunchLocs.dir[intRedLaunchDirIndex].pt[formEditControls.intCurrentRedLaunchLabelCounter]);
                    udrRedLaunchLocs.dir[intRedLaunchDirIndex].pt[formEditControls.intCurrentRedLaunchLabelCounter] = udrMouseHoverIndex;
                    setTerrainInitUnitLoc(udrMouseHoverIndex, (classBattle.enuInitialUnitLocDirIndices)formEditControls.intCurrentRedLaunchLabelCounter, formEditControls.intCurrentRedLaunchLabelCounter);
                    formEditControls.intCurrentRedLaunchLabelCounter = (formEditControls.intCurrentRedLaunchLabelCounter + 1) % classBattle.intMaxInvasionForce;
                    displayRedLaunchLabels();
                    break;
            }
            picMap.Refresh();
        }

        public void blinkCursor()
        {
            cRememberCursor = Cursor;
            bolBlinkCursor = true;
            tmrBlinkCurosr.Enabled = true;
        }

        void tmrBlinkCurosr_Tick(object sender, EventArgs e)
        {
            tmrBlinkCurosr.Enabled = bolBlinkCursor;
            if (bolBlinkCursorImage)
                Cursor = cRememberCursor;
            else
                Cursor = Cursors.Arrow;

            bolBlinkCursorImage = !bolBlinkCursorImage;
        }

        void initLaunchLocs()
        {
            // Red
            udrRedLaunchLocs.dir = new classBattle.Point_Array[(int)classBattle.enuInitialUnitLocDirIndices._num_RedInitialLocIndices];
            int intMidRangeValue = classBattle.intMaxInvasionForce/2;
            int intEdgeStart_X = (szMapSize.Width - intMidRangeValue ) / 2;
            int intEdgeStart_Y = (szMapSize.Height - intMidRangeValue ) / 2;
            Point udrCorner = new Point();
            Point udrCornerSigns = new Point();
            int[] intCornerShift_X = { 0, 0, 1, 0, 1, 2, 0, 1, 2, 3 };
            int[] intCornerShift_Y = { 0, 1, 0, 2, 1, 0, 3, 2, 1, 0 };

            for (int intX = 0; intX < szMapSize.Width; intX++)
                for (int intY = 0; intY < szMapSize.Height; intY++)
                    TerrainColumns[intX].Rows[intY].initUnitLoc.flag = false;

            for (classBattle.enuInitialUnitLocDirIndices dirCounter = 0; dirCounter < classBattle.enuInitialUnitLocDirIndices._num_RedInitialLocIndices; dirCounter++)
            {
                udrRedLaunchLocs.dir[(int)dirCounter] = new classBattle.Point_Array();
                udrRedLaunchLocs.dir[(int)dirCounter].pt = new Point[classBattle.intMaxInvasionForce];
                switch (dirCounter)
                {
                    case classBattle.enuInitialUnitLocDirIndices.Red_NE:
                        udrCorner.X = szMapSize.Width - 1;
                        udrCorner.Y = 0;
                        udrCornerSigns.X = -1;
                        udrCornerSigns.Y = 1;
                        break;

                    case classBattle.enuInitialUnitLocDirIndices.Red_NW:
                        udrCorner.X = 0;
                        udrCorner.Y = 0;
                        udrCornerSigns.X = 1;
                        udrCornerSigns.Y = 1;
                        break;

                    case classBattle.enuInitialUnitLocDirIndices.Red_SE:
                        udrCorner.X = szMapSize.Width - 1;
                        udrCorner.Y = szMapSize.Height - 1;
                        udrCornerSigns.X = -1;
                        udrCornerSigns.Y = -1;
                        break;

                    case classBattle.enuInitialUnitLocDirIndices.Red_SW:
                        udrCorner.X = 0;
                        udrCorner.Y = szMapSize.Height - 1;
                        udrCornerSigns.X = 1;
                        udrCornerSigns.Y = -1;
                        break;
                }
                for (int intLocCounter = 0; intLocCounter < classBattle.intMaxInvasionForce; intLocCounter++)
                {
                    int intMidRange_Offset = (intLocCounter >= (classBattle.intMaxInvasionForce / 2) ? 1 : 0);
                    switch (dirCounter)
                    {
                        case classBattle.enuInitialUnitLocDirIndices.Red_N:
                            udrRedLaunchLocs.dir[(int)dirCounter].pt[intLocCounter].X = intEdgeStart_X + intLocCounter - (intLocCounter >= intMidRangeValue ? intMidRangeValue : 0);
                            udrRedLaunchLocs.dir[(int)dirCounter].pt[intLocCounter].Y = intMidRange_Offset;
                            break;

                        case classBattle.enuInitialUnitLocDirIndices.Red_E:
                            udrRedLaunchLocs.dir[(int)dirCounter].pt[intLocCounter].Y = intEdgeStart_Y + intLocCounter - (intLocCounter >= intMidRangeValue ? intMidRangeValue : 0);
                            udrRedLaunchLocs.dir[(int)dirCounter].pt[intLocCounter].X = szMapSize.Width -1 - intMidRange_Offset;
                            break;

                        case classBattle.enuInitialUnitLocDirIndices.Red_S:
                            udrRedLaunchLocs.dir[(int)dirCounter].pt[intLocCounter].X = intEdgeStart_X + intLocCounter - (intLocCounter >= intMidRangeValue ? intMidRangeValue : 0);
                            udrRedLaunchLocs.dir[(int)dirCounter].pt[intLocCounter].Y = szMapSize.Height -1 - intMidRange_Offset;
                            break;

                        case classBattle.enuInitialUnitLocDirIndices.Red_W:
                            udrRedLaunchLocs.dir[(int)dirCounter].pt[intLocCounter].Y = intEdgeStart_Y + intLocCounter - (intLocCounter >= intMidRangeValue ? intMidRangeValue : 0);
                            udrRedLaunchLocs.dir[(int)dirCounter].pt[intLocCounter].X = intMidRange_Offset;
                            break;

                        case classBattle.enuInitialUnitLocDirIndices.Red_NE:
                        case classBattle.enuInitialUnitLocDirIndices.Red_SE:
                        case classBattle.enuInitialUnitLocDirIndices.Red_SW:
                        case classBattle.enuInitialUnitLocDirIndices.Red_NW:
                            udrRedLaunchLocs.dir[(int)dirCounter].pt[intLocCounter].X = udrCorner.X + udrCornerSigns.X * intCornerShift_X[intLocCounter];
                            udrRedLaunchLocs.dir[(int)dirCounter].pt[intLocCounter].Y = udrCorner.Y + udrCornerSigns.Y * intCornerShift_Y[intLocCounter];
                            break;
                    }
                    setTerrainInitUnitLoc(udrRedLaunchLocs.dir[(int)dirCounter].pt[intLocCounter], dirCounter, intLocCounter);
                }
            }

            //Blue
            int[] intTurnCounter = { 1, 2, 4, 6, 9 };
            Point udrPos = cLibBattle.getPos(szMapSize.Width / 2, szMapSize.Height / 2);
            classBattle.enuDirections[] dirArray = { 
                                                       classBattle.enuDirections.NE,
                                                       classBattle.enuDirections.NW ,
                                                       classBattle.enuDirections.SW,
                                                       classBattle.enuDirections.S_,
                                                       classBattle.enuDirections.SE,
                                                       classBattle.enuDirections.NE,
                                                       classBattle.enuDirections.NE,
                                                       classBattle.enuDirections.N_,
                                                       classBattle.enuDirections.NW,
                                                       classBattle.enuDirections.NW 
                                                   };
            for (int intLocCounter = 0; intLocCounter < udrBlueLaunchLocs.Length; intLocCounter++)
            {
                udrBlueLaunchLocs[intLocCounter] = udrPos;
                setTerrainInitUnitLoc(udrPos, classBattle.enuInitialUnitLocDirIndices.Blue);
                udrPos = getNextPos(udrPos, dirArray[intLocCounter]);
            }



        }

        void setMenuStrip()
        {
            MenuStrip ms = new MenuStrip();
                        
            ToolStripMenuItem mnuFile = new ToolStripMenuItem("&File");
            ms.Items.Add(mnuFile);
            mnuFile.Visible = true;

            ToolStripMenuItem mnuFileLoad = new ToolStripMenuItem("&Load", null, new EventHandler(mnuLoad_Click));
            mnuFile.DropDownItems.Add(mnuFileLoad);
            mnuFileLoad.Visible = true;
            
            ToolStripMenuItem mnuFileSave = new ToolStripMenuItem("&Save", null, new EventHandler(mnuSave_Click));
            mnuFile.DropDownItems.Add(mnuFileSave);
            mnuFileSave.Visible = true;
            
            ToolStripMenuItem mnuFileNew = new ToolStripMenuItem("&New", null, new EventHandler(mnuNew_Click));
            mnuFile.DropDownItems.Add(mnuFileNew);
            mnuFileNew.Visible = true;
            
            ToolStripMenuItem mnuFileQuit = new ToolStripMenuItem("&Quit", null, new EventHandler(mnuQuit_Click));
            mnuFile.DropDownItems.Add(mnuFileQuit);
            mnuFileQuit.Visible = true;
            
            Controls.Add(ms);
            ms.Visible = true;
            ms.BringToFront();
        }

        void mnuQuit_Click(object sender, EventArgs e) { Dispose(); }
        void mnuNew_Click(object sender, EventArgs e) { initMap(); }
        void mnuSave_Click(object sender, EventArgs e)
        {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.InitialDirectory = System.IO.Directory.GetCurrentDirectory();
            sfd.Filter = "Map files (*.map)|*.map";
            if (sfd.ShowDialog() == DialogResult.OK)
            {
                string strFilename = sfd.FileName;
                // /*/   // save for 2019 data

                if (strFilename.Contains("."))
                    strFilename = strFilename.Substring(0, strFilename.Length - ".map".Length);

                strFilename += ".map";
                
                BinaryFormatter formatter = new BinaryFormatter();

                FileStream fs;
                fs = new FileStream(strFilename, FileMode.Create);
                formatter.Serialize(fs, (byte)szMapSize.Width);
                formatter.Serialize(fs, (byte)szMapSize.Height);

                for (int intY = 0; intY < szMapSize.Height; intY++)
                {
                    string strTerrain = "";
                    for (int intX = 0; intX < szMapSize.Width; intX++)
                        strTerrain += TerrainColumns[intX].Rows[intY].type.ToString().Substring(0, 1).ToUpper();
                    formatter.Serialize(fs, strTerrain);
                }

                for (classBattle.enuInitialUnitLocDirIndices dirCounter = 0; dirCounter < classBattle.enuInitialUnitLocDirIndices._num_RedInitialLocIndices; dirCounter++)
                    for (int intLocCounter = 0; intLocCounter < classBattle.intMaxInvasionForce; intLocCounter++)
                    {
                        formatter.Serialize(fs, (byte)udrRedLaunchLocs.dir[(byte)dirCounter].pt[intLocCounter].X);
                        formatter.Serialize(fs, (byte)udrRedLaunchLocs.dir[(byte)dirCounter].pt[intLocCounter].Y);
                    }

                for (int intLocCounter = 0; intLocCounter < classBattle.intMaxInvasionForce; intLocCounter++)
                {
                    formatter.Serialize(fs, (byte)udrBlueLaunchLocs[intLocCounter].X);
                    formatter.Serialize(fs, (byte)udrBlueLaunchLocs[intLocCounter].Y);
                }

                fs.Close();
            }
        }

        public void resetTerrainInitUnitLoc(Point udrLoc) { TerrainColumns[udrLoc.X].Rows[udrLoc.Y].initUnitLoc.flag = false; }
        public void setTerrainInitUnitLoc(Point udrLoc, classBattle.enuInitialUnitLocDirIndices initUnitLocType)
        {
            setTerrainInitUnitLoc(udrLoc, initUnitLocType, (initUnitLocType == classBattle.enuInitialUnitLocDirIndices.Blue)
                                      ? formEditControls.intCurrentBlueLaunchLabelCounter
                                      : formEditControls.intCurrentRedLaunchLabelCounter);
        }
            public void setTerrainInitUnitLoc(Point udrLoc, classBattle.enuInitialUnitLocDirIndices initUnitLocType, int intIndex)
        {
            TerrainColumns[udrLoc.X].Rows[udrLoc.Y].initUnitLoc.flag = true;
            TerrainColumns[udrLoc.X].Rows[udrLoc.Y].initUnitLoc.intIndex = intIndex ;                 
            TerrainColumns[udrLoc.X].Rows[udrLoc.Y].initUnitLoc.typeLoc = initUnitLocType;
        }

        void mnuLoad_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.InitialDirectory = System.IO.Directory.GetCurrentDirectory();
            ofd.Filter = "map files (*.map)|*.map";
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                string strFilename = ofd.FileName;
                if (System.IO.File.Exists(strFilename))
                {
                    BinaryFormatter formatter = new BinaryFormatter();
                    if (File.Exists(strFilename))
                    {
                        FileStream fs = new FileStream(strFilename, FileMode.Open);
                        szMapSize.Width = (byte)formatter.Deserialize(fs);
                        szMapSize.Height = (byte)formatter.Deserialize(fs);
                        
                        formEditControls.nudHeight.Value = szMapSize.Height;
                        formEditControls.nudWidth.Value = szMapSize.Width;
                        string[] strTerrain = new string[szMapSize.Height+1];
                        for (int intY = 0; intY < szMapSize.Height; intY++)
                            strTerrain[intY] =((string)formatter.Deserialize(fs)).ToUpper();

                        if (strTerrain != null && strTerrain.Length > 0)
                        {
                            szMapSize.Height = strTerrain.Length - 1;
                            if (strTerrain[0].Length > 0)
                            {
                                string strTypeChar = "GFRWMC";// grass, forest, road, water, mountain, castle
                                szMapSize.Width = strTerrain[0].Length;
                                Array.Resize<class2DTerrain>(ref TerrainColumns, szMapSize.Width + 1);

                                for (int intX = 0; intX < szMapSize.Width; intX++)
                                {
                                    Array.Resize<classMapEditTerrain>(ref TerrainColumns[intX].Rows, szMapSize.Height);
                                    for (int intY = 0; intY < szMapSize.Height; intY++)
                                    {
                                        int intTerrainType = strTypeChar.IndexOf(strTerrain[intY].Substring(intX, 1));
                                        TerrainColumns[intX].Rows[intY].type = (classBattle.enuTerrainTypes)intTerrainType;
                                        TerrainColumns[intX].Rows[intY].initUnitLoc.flag = false;
                                    }
                                }
                            }
                            displayMap();
                        }

                        for (classBattle.enuInitialUnitLocDirIndices dirCounter = 0; dirCounter < classBattle.enuInitialUnitLocDirIndices._num_RedInitialLocIndices; dirCounter++)
                            for (int intLocCounter = 0; intLocCounter < classBattle.intMaxInvasionForce; intLocCounter++)
                            {
                                udrRedLaunchLocs.dir[(int)dirCounter].pt[intLocCounter].X = (byte )formatter.Deserialize(fs);
                                udrRedLaunchLocs.dir[(int)dirCounter].pt[intLocCounter].Y = (byte)formatter.Deserialize(fs);
                            }

                        for (int intLocCounter = 0; intLocCounter < classBattle.intMaxInvasionForce; intLocCounter++)
                        {
                            udrBlueLaunchLocs[intLocCounter].X = (byte)formatter.Deserialize(fs);
                            udrBlueLaunchLocs[intLocCounter].Y = (byte)formatter.Deserialize(fs);
                        }
                        
                        fs.Close();

                      
                    }
                }
            }
        }

        void initMap()
        {
            szMapSize.Width = 15; szMapSize.Height = 15;
            formEditControls.Dispose(); // will trip a new one
            resizeMap();

            for (int intX = 0; intX < szMapSize.Width; intX++)
            {
                for (int intY = 0; intY < szMapSize.Height; intY++)
                    TerrainColumns[intX].Rows[intY].type = classBattle.enuTerrainTypes.grass;
            }

            displayMap();
        }

        void classMapEditor_Disposed(object sender, EventArgs e) { killEditForm(); }

        void classMapEditor_SizeChanged(object sender, EventArgs e) { tmrSizechange.Enabled = true; }

        void tmrSizechange_Tick(object sender, EventArgs e)
        {
            tmrSizechange.Enabled = false;
            resetScrollBars();

            //displayMap();
        }

        void createEditForm()
        {
            formEditControls = new classEditControls(this,ref cLibBattle);
            formEditControls.Disposed += new EventHandler(formEditControls_Disposed);
        }

        public void resizeMap()
        {
            Array.Resize<class2DTerrain>(ref TerrainColumns, szMapSize.Width);
            for (int intColumncounter = 0; intColumncounter < TerrainColumns.Length; intColumncounter++)
            {
                TerrainColumns[intColumncounter] = new class2DTerrain();
                class2DTerrain cTerrain = TerrainColumns[intColumncounter];
                Array.Resize<classMapEditTerrain>(ref cTerrain.Rows, szMapSize.Height);
                for (int intRowCounter = 0; intRowCounter < cTerrain.Rows.Length; intRowCounter++)
                {
                    cTerrain.Rows[intRowCounter] = new classMapEditTerrain();
                    cTerrain.Rows[intRowCounter].initUnitLoc = new classInitUnitLoc();
                }
            }

            displayMap();
            initLaunchLocs();
        }

        //void displayMapLoc(Point udrLoc, classBattle.enuTerrainImageSetting terrainImageSetting)
        //{
        //    if (ptOnMap(udrLoc))
        //    {
        //        Point pt = new Point(getGridMapObjectLeft(udrLoc.X), getGridMapObjectTop(udrLoc));
        //        gr.DrawImage(getTerrainImage(TerrainColumns[udrLoc.X].Rows[udrLoc.Y].type, terrainImageSetting), pt.X, pt.Y, intMapGridSize, intMapGridSize);
        //    }
        //}

        public void displayMap()
        {
            Bitmap entireMap = new Bitmap(szMapSize.Width * intMapGridSize, (int)( (szMapSize.Height+.5) * intMapGridSize)); // make the bitmap large enough to contain all of your tiles.
            picMap.Image = entireMap;

            gr = Graphics.FromImage(entireMap);
            if (TerrainColumns != null && TerrainColumns[0].Rows != null)
                    for (int intY = 0; intY < szMapSize.Height; intY++)
                        for (int intX = 0; intX < szMapSize.Width; intX++)
                            displayMapLoc(cLibBattle.getPos(intX, intY),classBattle. enuTerrainImageSetting.normal);

                pnlMap.BackColor = Color.Black;
                pnlMap.Width = szMapSize.Width * intMapGridSize;
                pnlMap.Height = (int)(((double)szMapSize.Height + .5) * intMapGridSize);
            
        }

        public Cursor getTerrainTypeCursor(classBattle.enuTerrainTypes terrainType)
        {
            Bitmap btMap = new Bitmap(cLibBattle.getTerrainImage(terrainType), intMapGridSize/3, intMapGridSize/            3);
            IntPtr ptr = btMap.GetHicon();
            return new Cursor(ptr);
        }

        void displayBolToggleBrush()
        {
            formEditControls.rdbDrawingStyleBrush.ForeColor = (bolToggleBrush ? Color.Red : Color.Black);
            Cursor = (bolToggleBrush ? getTerrainTypeCursor(formEditControls.SelectedNewTerrainType   ) : Cursors.No);
        }
   
        void picMap_MouseClick(object sender, MouseEventArgs e)
        {
            switch (mode)
            {
                case enuModes.Drawing:
                    if (DrawingStyle == enuDrawingStyle.singleCell)
                        TerrainColumns[udrMouseHoverIndex.X].Rows[udrMouseHoverIndex.Y].type = formEditControls.SelectedNewTerrainType;
                    else if (DrawingStyle == enuDrawingStyle.floodfill)
                        floodFill();
                    else if (DrawingStyle == enuDrawingStyle.brush)
                    {
                        bolToggleBrush = !bolToggleBrush;
                        displayBolToggleBrush();
                    }
                    break;

                case enuModes.BlueLaunchSet:
                    if (TerrainColumns[udrMouseHoverIndex.X].Rows[udrMouseHoverIndex.Y].initUnitLoc.flag)
                        return;
                    resetTerrainInitUnitLoc(udrBlueLaunchLocs[formEditControls.intCurrentBlueLaunchLabelCounter]);
                    udrBlueLaunchLocs[formEditControls.intCurrentBlueLaunchLabelCounter] = udrMouseHoverIndex;
                    setTerrainInitUnitLoc(udrMouseHoverIndex, classBattle.enuInitialUnitLocDirIndices.Blue, formEditControls.intCurrentBlueLaunchLabelCounter);
                    formEditControls.intCurrentBlueLaunchLabelCounter = (formEditControls.intCurrentBlueLaunchLabelCounter + 1) % classBattle.intMaxInvasionForce;
                    displayBlueLaunchLabels();
                    break;

                case enuModes.RedLaunchSet:
                    if (TerrainColumns[udrMouseHoverIndex.X].Rows[udrMouseHoverIndex.Y].initUnitLoc.flag)
                        return;
                    resetTerrainInitUnitLoc(udrRedLaunchLocs.dir [intRedLaunchDirIndex ].pt [ formEditControls.intCurrentRedLaunchLabelCounter]);
                    udrRedLaunchLocs.dir[intRedLaunchDirIndex].pt[formEditControls.intCurrentRedLaunchLabelCounter] = udrMouseHoverIndex;
                    setTerrainInitUnitLoc(udrMouseHoverIndex, (classBattle.enuInitialUnitLocDirIndices)formEditControls.intCurrentRedLaunchLabelCounter, formEditControls.intCurrentRedLaunchLabelCounter);
                    formEditControls.intCurrentRedLaunchLabelCounter = (formEditControls.intCurrentRedLaunchLabelCounter + 1) % classBattle.intMaxInvasionForce;
                    displayRedLaunchLabels();
                    break;
            }
        }

       
        void killEditForm()
        {
            bolKillEditForm = true;
            formEditControls.Dispose();
        }

        void formEditControls_Disposed(object sender, EventArgs e)
        {
            if (bolKillEditForm)
                return;
            createEditForm();
        }

        bool ptOnMap(Point udrLoc)
        {
            return (udrLoc.X >= 0
                    && udrLoc.X < szMapSize.Width
                    && udrLoc.Y >= 0
                    && udrLoc.Y < szMapSize.Height);
        }

        void showHoverOverTerrainInfo()
        {
            if (ptOnMap(udrMouseHoverIndex))
                formEditControls.lblMouseInfo.Text = "("
                                                   + udrMouseHoverIndex.X.ToString()
                                                   + ", "
                                                   + udrMouseHoverIndex.Y.ToString()
                                                   + ") : "
                                                   + TerrainColumns[udrMouseHoverIndex.X].Rows[udrMouseHoverIndex.Y].type.ToString();
        }

        #region "scroll bars"
        void resetScrollBars()
        {
            VSB.Top = 5; VSB.Left = Width - VSB.Width - 15;
            VSB.Height = Height - intVerticalOffset - HSB.Height;
            VSB.Visible = true;

            HSB.Top = VSB.Top + VSB.Height;
            HSB.Left = 5;
            HSB.Width = Width - 35;
            HSB.Visible = true;

            VSB.BringToFront();
            HSB.BringToFront();

            // remember what was visible before size change
            Point udrVisiblePos = new Point();
            udrVisiblePos.X = -pnlMap.Left;
            udrVisiblePos.Y = -pnlMap.Top;

            Point udrVisibleMapSquare = determineMapGridLocByObjectLoc(udrVisiblePos);

            // adjust scroll bars to fit new size
            if (Width > pnlMap.Width)
                HSB.Visible = false;
            else
            {
                HSB.LargeChange = (int)(((double)Width / (double)pnlMap.Width) * intScrollBarMax / 2);
                HSB.Maximum = intScrollBarMax - HSB.LargeChange;
            }

            if (Height - intVerticalOffset > pnlMap.Height)
            {
                VSB.Visible = false;
                pnlMap.Top = intVerticalOffset;
            }
            else
            {
                VSB.LargeChange = (int)(((double)Height / (double)pnlMap.Height) * intScrollBarMax / 2);
                VSB.Maximum = intScrollBarMax - VSB.LargeChange;
            }

            try { HSB.Value = (int)((double)udrVisibleMapSquare.X / (double)szMapSize.Width * HSB.Maximum); }
            catch (Exception) { }
            try { VSB.Value = (int)((double)udrVisibleMapSquare.Y / (double)szMapSize.Height * VSB.Maximum); }
            catch (Exception) { }
        }

        void HSB_ValueChanged(object sender, EventArgs e)
        {
            int intMaxLeft = pnlMap.Width - VSB.Left;
            double dblPercentageLeft = (double)HSB.Value / (double)(HSB.Maximum - HSB.LargeChange);
            pnlMap.Left = -(int)((double)intMaxLeft * dblPercentageLeft);
            //displayMap();
        }

        void VSB_ValueChanged(object sender, EventArgs e)
        {
            int intMaxTop = pnlMap.Height + intVerticalOffset - HSB.Top;
            double dblPercentageTop = (double)VSB.Value / (double)(VSB.Maximum - VSB.LargeChange);
            pnlMap.Top = intVerticalOffset - (int)((double)intMaxTop * dblPercentageTop);
            //displayMap();
        }
#endregion

        #region "helper function"

        Point determineMapGridLocByObjectLoc(Point udrPos) { return determineMapGridLocByObjectLoc(udrPos.X, udrPos.Y); }
        Point determineMapGridLocByObjectLoc(int intLeft, int intTop)
        {
            Point udrRetVal = new Point();
            for (udrRetVal.X = 0; udrRetVal.X < szMapSize.Width; udrRetVal.X++)
                if (getGridMapObjectLeft(udrRetVal.X + 1) > intLeft)
                    break;
            for (udrRetVal.Y = 0; udrRetVal.Y < szMapSize.Height; udrRetVal.Y++)
                if (getGridMapObjectTop(udrRetVal.X, udrRetVal.Y + 1) > intTop)
                    break;

            return udrRetVal;
        }

        bool intIsEven(int intX) { return (intX % 2 == 0); }
        public Point getNextPos(Point unitPos, classBattle.enuDirections dir)
        {
            Point udrMoveVector = new Point();
            udrMoveVector.X = 0;
            udrMoveVector.Y = 0;
            if (intIsEven(unitPos.X))
            {
                switch (dir)
                {
                    case classBattle.enuDirections.NW:
                        udrMoveVector.X = -1;
                        udrMoveVector.Y = 0;
                        break;
                    case classBattle.enuDirections.N_:
                        udrMoveVector.X = 0;
                        udrMoveVector.Y = -1;
                        break;
                    case classBattle.enuDirections.NE:
                        udrMoveVector.X = 1;
                        udrMoveVector.Y = 0;
                        break;

                    case classBattle.enuDirections.SE:
                        udrMoveVector.X = 1;
                        udrMoveVector.Y = 1;
                        break;
                    case classBattle.enuDirections.S_:
                        udrMoveVector.X = 0;
                        udrMoveVector.Y = 1;
                        break;
                    case classBattle.enuDirections.SW:
                        udrMoveVector.X = -1;
                        udrMoveVector.Y = 1;
                        break;
                }
            }
            else
            {
                switch (dir)
                {
                    case classBattle.enuDirections.NW:
                        udrMoveVector.X = -1;
                        udrMoveVector.Y = -1;
                        break;
                    case classBattle.enuDirections.N_:
                        udrMoveVector.X = 0;
                        udrMoveVector.Y = -1;
                        break;
                    case classBattle.enuDirections.NE:
                        udrMoveVector.X = 1;
                        udrMoveVector.Y = -1;
                        break;

                    case classBattle.enuDirections.SE:
                        udrMoveVector.X = 1;
                        udrMoveVector.Y = 0;
                        break;
                    case classBattle.enuDirections.S_:
                        udrMoveVector.X = 0;
                        udrMoveVector.Y = 1;
                        break;
                    case classBattle.enuDirections.SW:
                        udrMoveVector.X = -1;
                        udrMoveVector.Y = 0;
                        break;
                }
            }
            unitPos.X += udrMoveVector.X;
            unitPos.Y += udrMoveVector.Y;
            return unitPos;
        }

        public int getGridMapObjectTop(Point pos) { return getGridMapObjectTop(pos.X, pos.Y); }
        public int getGridMapObjectTop(int intX, int intY)
        {
            return (int)((double)(intY + (intIsEven(intX) ? 0.5 : 0)) * (double)(intMapGridSize));
        }
        public int getGridMapObjectLeft(Point pos) { return getGridMapObjectLeft(pos.X); }
        public int getGridMapObjectLeft(int intX) { return intMapGridSize * intX; }
        public Point getGridLocation(Point pos)
        {
            Point udrRetVal = new Point();
            udrRetVal.X = getGridMapObjectLeft(pos);
            udrRetVal.Y = getGridMapObjectTop(pos);
            return udrRetVal;
        }
    
        public classBattle.enuDirections getDirFromString(string strDir)
        {
            switch (strDir)
            {
                case "NW":
                    return classBattle.enuDirections.NW;

                case "N_":
                    return classBattle.enuDirections.N_;

                case "NE":
                    return classBattle.enuDirections.NE;

                case "SW":
                    return classBattle.enuDirections.SW;

                case "S_":
                    return classBattle.enuDirections.S_;

                case "SE":
                    return classBattle.enuDirections.SE;

                default:
                    return classBattle.enuDirections._num_directions;
            }
        }
        #endregion

        #region "flood fill"

        void floodFill()
        {
            classBattle.enuTerrainTypes Type_Old = TerrainColumns[udrMouseHoverIndex.X].Rows[udrMouseHoverIndex.Y].type;
            classBattle.enuTerrainTypes Type_New = formEditControls.SelectedNewTerrainType;

            int intInfinity = (int)Math.Pow(10, 5);

            classBattleUnit.classPathMap[,] udrPathMap = new classBattleUnit.classPathMap[szMapSize.Width, szMapSize.Height];
            for (int intX = 0; intX < szMapSize.Width; intX++)
                for (int intY = 0; intY < szMapSize.Height; intY++)
                {
                    udrPathMap[intX, intY].direction = classBattle.enuDirections._num_directions;
                    udrPathMap[intX, intY].intMovementCost = intInfinity;
                }

            classFloodFillElement FFeleQ = null;

            classFloodFillElement firstQele = new classFloodFillElement(0, udrMouseHoverIndex);
            enQFloodFillElement(ref FFeleQ, ref firstQele);

            udrPathMap[firstQele.pos.X, firstQele.pos.Y].intMovementCost = 0;

            classFloodFillElement thisQEle = deQShortestPathElement(ref FFeleQ);

            while (thisQEle != null)
            {
                TerrainColumns[thisQEle.pos.X].Rows[thisQEle.pos.Y].type = Type_New;
                string strDir = "";
                for (classBattle.enuDirections dirCounter = 0; dirCounter < classBattle.enuDirections._num_directions; dirCounter++)
                {
                    Point udrNextPos = getNextPos(thisQEle.pos, dirCounter);
                    if (udrNextPos.X >= 0 && udrNextPos.Y >= 0 && udrNextPos.X < szMapSize.Width && udrNextPos.Y < szMapSize.Height)
                    {

                        int intNewMovementCost = thisQEle.intStepsFromStart + 1;
                        if (intNewMovementCost < udrPathMap[udrNextPos.X, udrNextPos.Y].intMovementCost)
                            strDir += dirCounter.ToString();
                    }
                }

                while (strDir.Length > 0)
                {
                    string strThisDir = strDir.Substring(0, 2);
                    strDir = strDir.Substring(2);
                    int intDistanceFromStart_New = intInfinity;

                    classBattle.enuDirections dir_new = dir_new = getDirFromString(strThisDir);
                    Point udrPos_new = getNextPos(thisQEle.pos, dir_new);
                    intDistanceFromStart_New = thisQEle.intStepsFromStart + 1;
                    if (intDistanceFromStart_New < udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost
                        && TerrainColumns[udrPos_new.X].Rows[udrPos_new.Y].type == Type_Old)
                    {
                        udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost = intDistanceFromStart_New;

                        classFloodFillElement NewQele = new classFloodFillElement(udrPathMap[udrPos_new.X, udrPos_new.Y].intStepsFromStart, udrPos_new);
                        enQFloodFillElement(ref FFeleQ, ref NewQele);
                    }
                }
                thisQEle = deQShortestPathElement(ref FFeleQ);
            }
            displayMap();
        }

        public classFloodFillElement deQShortestPathElement(ref classFloodFillElement FFele)
        {
            classFloodFillElement eleRetVal = FFele;
            if (FFele != null)
            {
                FFele = FFele.next;

                if (FFele != null)
                    FFele.previous = null;
                eleRetVal.next = null;
            }
            return eleRetVal;
        }

        public void enQFloodFillElement(ref classFloodFillElement FFele_thisQ, ref classFloodFillElement FFeleNew)
        {
            if (FFeleNew == null)
                return;

            if (FFele_thisQ == null)
            {
                FFele_thisQ = FFeleNew;
                FFeleNew.next = null;
                FFeleNew.previous = null;
            }
            else
            {  // rank by movement cost -> cheapest at the front
                if (FFele_thisQ.intStepsFromStart > FFeleNew.intStepsFromStart)
                {
                    FFeleNew.next = FFele_thisQ;
                    FFele_thisQ.previous = FFeleNew;

                    FFeleNew.previous = null;
                    FFele_thisQ = FFeleNew;
                }
                else
                {
                    classFloodFillElement thisElement = FFele_thisQ;
                    while (thisElement.next != null && thisElement.next.intStepsFromStart < FFeleNew.intStepsFromStart)
                        thisElement = thisElement.next;

                    FFeleNew.next = thisElement.next;
                    if (FFeleNew.next != null)
                        FFeleNew.next.previous = FFeleNew;

                    thisElement.next = FFeleNew;
                    FFeleNew.previous = thisElement;
                }
            }
        }
        #endregion

        public void eraseRedLaunchLabels() { eraseLaunchLabels(ref lblRedLaunchLabels); }
        public void displayRedLaunchLabels() { displayLaunchLabels(ref lblRedLaunchLabels, udrRedLaunchLocs.dir[intRedLaunchDirIndex].pt, classBattle.enuUnitColors.red); }
        public void eraseBlueLaunchLabels() { eraseLaunchLabels(ref lblBlueLaunchLabels); }
        public void displayBlueLaunchLabels() { displayLaunchLabels(ref lblBlueLaunchLabels, udrBlueLaunchLocs, classBattle.enuUnitColors.blue); }

        public void eraseLaunchLabels(ref classInitLaunchDisplayLabel[] lbls)
        {
            if (lbls != null)
                for (int intLabelCounter = 0; intLabelCounter < lbls.Length; intLabelCounter++)
                    if (lbls[intLabelCounter] != null)
                        lbls[intLabelCounter].Visible = false;
        }

        public void displayLaunchLabels(ref classInitLaunchDisplayLabel[] lbls, Point[] udrLocs, classBattle.enuUnitColors clr)
        {
            if (udrLocs != null
                && udrLocs.Length >0)
            {
                if (lbls == null)
                    lbls = new classInitLaunchDisplayLabel[classBattle.intMaxInvasionForce];
                for (int intLocCounter = 0; intLocCounter < lbls.Length; intLocCounter++)
                {
                    if (lbls[intLocCounter] == null)
                    {
                        classInitLaunchDisplayLabel lblNew = new classInitLaunchDisplayLabel();
                        lblNew.AutoSize = true;
                        lblNew.Text = intLocCounter.ToString();
                        picMap.Controls.Add(lblNew);
                        lbls[intLocCounter] = lblNew;
                    }
                    else
                    {
                        lbls[intLocCounter].Visible = false;
                        // replace old image beneath now invisible label
                        //gr.DrawImage(lbls[intLocCounter].oldImage, lbls[intLocCounter].Left, lbls[intLocCounter].Top, lbls[intLocCounter].Width, lbls[intLocCounter].Height);
                    }
                    lbls[intLocCounter].Top = getGridMapObjectTop(udrLocs[intLocCounter]) +  5;
                    lbls[intLocCounter].Left = getGridMapObjectLeft(udrLocs[intLocCounter]) + 5;
                    
                    //// DEBUGHERE START
                    //// record old image 
                    //Bitmap bmpImage = new Bitmap(picMap.Image);
                    //Bitmap bmpCrop = bmpImage.Clone(new Rectangle(lbls[intLocCounter].Left, lbls[intLocCounter].Top, lbls[intLocCounter].Width, lbls[intLocCounter].Height), bmpImage.PixelFormat);
                    //lbls[intLocCounter].oldImage = (Image)(bmpCrop);
                    //// DEBUGHERE END

                    lbls[intLocCounter].Visible = true;
                    lbls[intLocCounter].BringToFront();

                    if (intLocCounter == formEditControls.intCurrentRedLaunchLabelCounter)
                    {
                        lbls[intLocCounter].ForeColor = (clr == classBattle.enuUnitColors.blue ? Color.Blue : Color.Red);
                        lbls[intLocCounter].BackColor = Color.Black;
                    }
                    else
                    {
                        lbls[intLocCounter].ForeColor = Color.Black;
                        lbls[intLocCounter].BackColor = (clr == classBattle.enuUnitColors.blue ? Color.Blue : Color.Red); 
                    }
                }
            }
        }
    }

    public class classPicSelection : PictureBox
    {
        public classBattle.enuTerrainTypes myTerrainType;
    }

    public class classEditControls : Form
    {
        public NumericUpDown nudWidth;
        public NumericUpDown nudHeight;
        classMapEditor callingForm;
        classBattle cLibBattle;
        public Label lblMouseInfo;
        classDirLabel[] lblRedInvasionDirLabels = new classDirLabel[(int)classBattle.intMaxInvasionForce];
        public classPicSelection[] picSelection = new classPicSelection[(int)classBattle.enuTerrainTypes._numTerrainTypes];
        Panel pnlBackOfSelectedPic = new Panel();

        public classBattle.enuTerrainTypes SelectedNewTerrainType;
        public int intCurrentRedLaunchLabelCounter =0;
        public int intCurrentBlueLaunchLabelCounter = 0;

        const int intBlindRedLocResetCountdown_max = 10;
        int intBlinkRedLocResetCountdown = intBlindRedLocResetCountdown_max;
        Timer tmrRedLocReset = new Timer();
        GroupBox grbRedInvasionDirection = new GroupBox();
        public GroupBox grbDrawingStyle = new GroupBox();
        RadioButton rdbDrawingStyleSingleCell = new RadioButton();
        public RadioButton rdbDrawingStyleBrush = new RadioButton();
        RadioButton rdbDrawingStyleFloodFill = new RadioButton();
        Label lblBlueDefenseLaunch = new Label();
                   
        public classEditControls( classMapEditor callingForm_local,ref classBattle cLibBattle_local)
        {
            callingForm = callingForm_local;
            cLibBattle = cLibBattle_local;

            Text = "Edit Controls";

            Label lblWidth = new Label();
            lblWidth.Text = "Width";
            lblWidth.AutoSize = true;
            Controls.Add(lblWidth);
            lblWidth.Left = 5; lblWidth.Top = 5;
            lblWidth.Visible = true;

            Label lblHeight = new Label();
            lblHeight.Text = "Height";
            lblHeight.AutoSize = true;
            Controls.Add(lblHeight);
            lblHeight.Left = 5; lblHeight.Top = lblWidth.Top + lblWidth.Height + 5;
            lblHeight.Visible = true;

            nudWidth = new NumericUpDown();
            nudWidth.Minimum = 10;
            nudWidth.Maximum = 100;
            nudWidth.Value = 15;
            nudWidth.Left = lblWidth.Left + (lblWidth.Width > lblHeight.Width ? lblWidth.Width : lblHeight.Width) + 5;
            nudWidth.Top = lblWidth.Top;
            nudWidth.Width = 50;
            Controls.Add(nudWidth);
            nudWidth.Visible = true;

            nudHeight = new NumericUpDown();
            nudHeight.Minimum = 10;
            nudHeight.Maximum = 100;
            nudHeight.Value = 15;
            nudHeight.Left = lblHeight.Left + (lblWidth.Width > lblHeight.Width ? lblWidth.Width : lblHeight.Width) + 5;
            nudHeight.Top = lblHeight.Top;
            nudHeight.Width = nudWidth.Width;
            Controls.Add(nudHeight);
            nudHeight.Visible = true;         

            lblMouseInfo = new Label();
            lblMouseInfo.Text = "()";
            lblMouseInfo.Left = 5; lblMouseInfo.Top = lblHeight.Top + lblHeight.Height + 5;
            lblMouseInfo.AutoSize = true;
            Controls.Add(lblMouseInfo);
            lblMouseInfo.Visible = true;

            pnlBackOfSelectedPic.Width = pnlBackOfSelectedPic.Height = 45;
            pnlBackOfSelectedPic.BackColor = Color.Black;

            for (int intPicSelected = 0; intPicSelected <(int) classBattle.enuTerrainTypes._numTerrainTypes; intPicSelected++)
            {
                picSelection[intPicSelected] = new classPicSelection();
                picSelection[intPicSelected].myTerrainType = (classBattle.enuTerrainTypes)intPicSelected;
                picSelection[intPicSelected].Image = cLibBattle.getTerrainImage((classBattle.enuTerrainTypes)intPicSelected, classBattle.enuTerrainImageSetting.shaded);
                picSelection[intPicSelected].SizeMode = PictureBoxSizeMode.StretchImage;
                picSelection[intPicSelected].Width = picSelection[intPicSelected].Height = pnlBackOfSelectedPic.Width -10;
                picSelection[intPicSelected].Left = 10 + intPicSelected * (5 + picSelection[intPicSelected].Width);
                picSelection[intPicSelected].Top =  lblMouseInfo.Top + lblMouseInfo.Height + 5;
                picSelection[intPicSelected].MouseEnter += new EventHandler(picTerrainType_MouseEnter);
                picSelection[intPicSelected].MouseLeave += new EventHandler(picTerrainType_MouseLeave);
                picSelection[intPicSelected].MouseClick += new MouseEventHandler(picTerrainType_MouseClick);
                
                Controls.Add(picSelection[intPicSelected]);
                picSelection[intPicSelected].Visible = true;
            }
            picSelection[0].Image = callingForm.cLibBattle.getTerrainImage(picSelection[0].myTerrainType, classBattle.enuTerrainImageSetting.normal);
            SelectedNewTerrainType = picSelection[0].myTerrainType;
            setPnlBackSelectedType();
            
            grbDrawingStyle.Text = "Drawing Style";

            rdbDrawingStyleSingleCell.Text = "Single Cell";
            rdbDrawingStyleSingleCell.AutoSize = true;
            grbDrawingStyle.Controls.Add(rdbDrawingStyleSingleCell);
            rdbDrawingStyleSingleCell.Top = 15; rdbDrawingStyleSingleCell.Left = 5;
            rdbDrawingStyleSingleCell.Visible = true;
            rdbDrawingStyleSingleCell.CheckedChanged += new EventHandler(rdbDrawingStyleSingleCell_CheckedChanged);

            rdbDrawingStyleBrush.Text = "Brush";
            rdbDrawingStyleBrush.AutoSize = true;
            grbDrawingStyle.Controls.Add(rdbDrawingStyleBrush);
            rdbDrawingStyleBrush.Top = rdbDrawingStyleSingleCell.Top + rdbDrawingStyleSingleCell.Height + 5; rdbDrawingStyleBrush.Left = 5;
            rdbDrawingStyleBrush.Visible = true;
            rdbDrawingStyleBrush.CheckedChanged += new EventHandler(rdbDrawingStyleBrush_CheckedChanged);

            rdbDrawingStyleFloodFill.Text = "FloodFill";
            rdbDrawingStyleFloodFill.AutoSize = true;
            grbDrawingStyle.Controls.Add(rdbDrawingStyleFloodFill);
            rdbDrawingStyleFloodFill.Top = rdbDrawingStyleBrush.Top + rdbDrawingStyleBrush.Height + 5; rdbDrawingStyleFloodFill.Left = 5;
            rdbDrawingStyleFloodFill.Visible = true;
            rdbDrawingStyleFloodFill.CheckedChanged += new EventHandler(rdbDrawingStyleFloodFill_CheckedChanged);

            rdbDrawingStyleSingleCell.Checked = true;
            callingForm.DrawingStyle = classMapEditor.enuDrawingStyle.singleCell;
            grbDrawingStyle.Left = 5;
            grbDrawingStyle.Top = picSelection[0].Top + picSelection[0].Height + 5;
            grbDrawingStyle.Height = 95; grbDrawingStyle.Width = 100;
            Controls.Add(grbDrawingStyle);
            grbDrawingStyle.Visible = true;

            Point udrCenter = new Point();
            grbRedInvasionDirection.Text = "Red locs";
            grbRedInvasionDirection.BackColor = Color.White;
            grbRedInvasionDirection.Width = 80;
            grbRedInvasionDirection.Height = grbRedInvasionDirection.Width + 15;
            udrCenter.X = grbRedInvasionDirection.Width / 2;
            udrCenter.Y = udrCenter.X + 15;
            double dblRadius = udrCenter.X * 0.7;
            for (classBattle.enuInitialUnitLocDirIndices dirCounter = 0; dirCounter < classBattle.enuInitialUnitLocDirIndices._num_RedInitialLocIndices; dirCounter++)
            {
                classDirLabel dirLabel = new classDirLabel();
                grbRedInvasionDirection.Controls.Add(dirLabel);
                dirLabel.Visible = true;
                dirLabel.AutoSize = true;
                dirLabel.myDir = dirCounter;
                dirLabel.Text = dirCounter.ToString().Replace("Red_", "");
                double dblAngle =  (double)dirCounter / 8.0 * Math.PI * 2.0;
                Point udrAbsLoc = new Point();

                dirLabel.BackColor = Color.Red;
                udrAbsLoc.X = (int)(dblRadius * Math.Sin(dblAngle));
                udrAbsLoc.Y = -(int)(dblRadius * Math.Cos(dblAngle));
                dirLabel.Top = (int)(udrCenter.Y + udrAbsLoc.Y - (double)dirLabel.Height /2.0);
                dirLabel.Left = (int)(udrCenter.X + udrAbsLoc.X - (double)dirLabel.Width/2.0);
                dirLabel.Click += new EventHandler(dirRedInvasionDirectionLabel_Click);
                dirLabel.MouseEnter += new EventHandler(dirRedInvasionDirectionLabel_MouseEnter);
                dirLabel.MouseLeave += new EventHandler(dirRedInvasionDirectionLabel_MouseLeave);
                lblRedInvasionDirLabels[(int)dirCounter] = dirLabel;
            }
            Controls.Add(grbRedInvasionDirection);
            grbRedInvasionDirection.Left = grbDrawingStyle.Left;
            grbRedInvasionDirection.Top = grbDrawingStyle.Top + grbDrawingStyle.Height + 5;

            grbRedInvasionDirection.Click += new EventHandler(grbRedInvasionDirection_Click);

            lblBlueDefenseLaunch.Text = "Defense Launch";
            lblBlueDefenseLaunch.Width = grbRedInvasionDirection.Width;
            lblBlueDefenseLaunch.Height = grbRedInvasionDirection.Height;
            lblBlueDefenseLaunch.Left = grbRedInvasionDirection.Left + grbRedInvasionDirection.Width + 5;
            lblBlueDefenseLaunch.Top = grbRedInvasionDirection.Top;
            lblBlueDefenseLaunch.BackColor = Color.White;
            Controls.Add(lblBlueDefenseLaunch);
            lblBlueDefenseLaunch.Visible = true;

            lblBlueDefenseLaunch.Click += new EventHandler(lblBlueDefenseLaunch_Click);

            Width = 300;
            Height = 400;
            Visible = true;

            tmrRedLocReset.Tick += new EventHandler(tmrRedLocReset_Tick);
            tmrRedLocReset.Interval = 500;

            nudHeight.ValueChanged += new EventHandler(nudHeight_ValueChanged);
            nudWidth.ValueChanged += new EventHandler(nudWidth_ValueChanged);
        }

       

        void blink()
        {
            intBlinkRedLocResetCountdown = intBlindRedLocResetCountdown_max;
            tmrRedLocReset.Enabled = true;
        }

        void tmrRedLocReset_Tick(object sender, EventArgs e)
        {
            intBlinkRedLocResetCountdown--;
            if (intBlinkRedLocResetCountdown <= 0)
            {
                grbRedInvasionDirection.BackColor = Color.White;
                tmrRedLocReset.Enabled = false;
            }
            else
                if (grbRedInvasionDirection.BackColor == Color.White)
                    grbRedInvasionDirection.BackColor = Color.Red;
                else
                    grbRedInvasionDirection.BackColor = Color.White;
        }

        void setEnabledObjects()
        {
            bool bolPicEnabled = false;
            switch (callingForm.mode)
            {
                case classMapEditor.enuModes.BlueLaunchSet:
                    bolPicEnabled = grbRedInvasionDirection.Enabled = grbDrawingStyle.Enabled = nudHeight.Enabled = nudWidth.Enabled = false;
                    lblBlueDefenseLaunch.Enabled = true;
                    break;

                case classMapEditor.enuModes.RedLaunchSet:
                    bolPicEnabled = lblBlueDefenseLaunch.Enabled =  grbDrawingStyle.Enabled = nudHeight.Enabled = nudWidth.Enabled = false;
                    grbRedInvasionDirection.Enabled = true;
                    break;

                case classMapEditor.enuModes.Drawing:
                    bolPicEnabled = grbRedInvasionDirection.Enabled = lblBlueDefenseLaunch.Enabled = grbDrawingStyle.Enabled = nudHeight.Enabled = nudWidth.Enabled = true;
                    break;
            }

            for (int intPicCounter = 0; intPicCounter < picSelection.Length; intPicCounter++)
                picSelection[intPicCounter].Enabled = bolPicEnabled;
        }

        void grbRedInvasionDirection_Click(object sender, EventArgs e)
        {           
            GroupBox thisGrRedInvasionDir = (GroupBox)sender;
            intCurrentRedLaunchLabelCounter = 0;
            if (callingForm.mode == classMapEditor.enuModes.RedLaunchSet)
            {
                callingForm.mode = classMapEditor.enuModes.Drawing;
                callingForm.eraseRedLaunchLabels();
            }
            else
            {
                callingForm.mode = classMapEditor.enuModes.RedLaunchSet;
                callingForm.displayRedLaunchLabels();
            }
            thisGrRedInvasionDir.BackColor = (callingForm.mode == classMapEditor.enuModes.RedLaunchSet ? Color.Red : Color.White);

            setEnabledObjects();
        }

        void lblBlueDefenseLaunch_Click(object sender, EventArgs e)
        {
            Label  thisBlueDefenseLabel = (Label)sender;
            intCurrentBlueLaunchLabelCounter = 0;
            if (callingForm.mode == classMapEditor.enuModes.BlueLaunchSet)
            {
                callingForm.mode = classMapEditor.enuModes.Drawing;
                callingForm.eraseBlueLaunchLabels();
            }
            else
            {
                callingForm.mode = classMapEditor.enuModes.BlueLaunchSet;
                callingForm.displayBlueLaunchLabels();
            }
            thisBlueDefenseLabel.BackColor = (callingForm.mode == classMapEditor.enuModes.BlueLaunchSet ? Color.Blue : Color.White);

            setEnabledObjects();
        }

        void dirRedInvasionDirectionLabel_MouseLeave(object sender, EventArgs e)
        {
            if (callingForm.mode != classMapEditor.enuModes.RedLaunchSet)
                return;
            classDirLabel thisDirLabel = (classDirLabel)sender;
            if (thisDirLabel.myDir == (classBattle.enuInitialUnitLocDirIndices)callingForm.intRedLaunchDirIndex)
            {
                thisDirLabel.BackColor = Color.Black;
                thisDirLabel.ForeColor = Color.Red;
            }
            else
            {
                thisDirLabel.BackColor = Color.Red;
                thisDirLabel.ForeColor = Color.Black;
            }
        }

        void dirRedInvasionDirectionLabel_MouseEnter(object sender, EventArgs e)
        {
            if (callingForm.mode != classMapEditor.enuModes.RedLaunchSet)
                return;
            classDirLabel thisDirLabel = (classDirLabel)sender;

            thisDirLabel.BackColor = Color.Black;
            thisDirLabel.ForeColor = Color.Purple;
        }

        void dirRedInvasionDirectionLabel_Click(object sender, EventArgs e)
        {
            if (callingForm.mode != classMapEditor.enuModes.RedLaunchSet)
                return;
            lblRedInvasionDirLabels[callingForm.intRedLaunchDirIndex].BackColor = Color.Red;
            lblRedInvasionDirLabels[callingForm.intRedLaunchDirIndex].ForeColor = Color.Black;
            classDirLabel thisDirLabel = (classDirLabel)sender;
            callingForm.eraseRedLaunchLabels();
            intCurrentRedLaunchLabelCounter = 0;
            callingForm.intRedLaunchDirIndex = (int)thisDirLabel.myDir;
            callingForm.displayRedLaunchLabels();
        }

        void rdbDrawingStyleFloodFill_CheckedChanged(object sender, EventArgs e) 
        {
            if (rdbDrawingStyleFloodFill.Checked)
            {
                callingForm.DrawingStyle = classMapEditor.enuDrawingStyle.floodfill;
                callingForm.Cursor = callingForm.getTerrainTypeCursor(SelectedNewTerrainType);
                callingForm.blinkCursor();
            }
        }

        void rdbDrawingStyleBrush_CheckedChanged(object sender, EventArgs e)
        {
            if (rdbDrawingStyleBrush.Checked)
            {
                callingForm.DrawingStyle = classMapEditor.enuDrawingStyle.brush;
                callingForm.bolBlinkCursor  = false;
                callingForm.Cursor = Cursors.No;
            }
        }
        void rdbDrawingStyleSingleCell_CheckedChanged(object sender, EventArgs e) 
        {
            if (rdbDrawingStyleSingleCell.Checked)
            {
                callingForm.DrawingStyle = classMapEditor.enuDrawingStyle.singleCell;
                callingForm.Cursor = callingForm.getTerrainTypeCursor(SelectedNewTerrainType);
                callingForm.bolBlinkCursor = false;
            }
        }


        void setPnlBackSelectedType()
        {
            int intSelectedPic = (int)SelectedNewTerrainType;
            pnlBackOfSelectedPic.Left = picSelection[intSelectedPic].Left - 5;
            pnlBackOfSelectedPic.Top = picSelection[intSelectedPic].Top - 5;
            pnlBackOfSelectedPic.SendToBack();
        }

        void picTerrainType_MouseClick(object sender, MouseEventArgs e)
        {
            classPicSelection thisPic = (classPicSelection)sender;
            picSelection[(int)SelectedNewTerrainType].Image = callingForm.cLibBattle.getTerrainImage(picSelection[(int)SelectedNewTerrainType].myTerrainType, classBattle.enuTerrainImageSetting.shaded);
            SelectedNewTerrainType = thisPic.myTerrainType;
            callingForm.bolBlinkCursor = false;
            switch (callingForm.mode)
            {
                case classMapEditor.enuModes.Drawing:
                    switch (callingForm.DrawingStyle)
                    {
                        case classMapEditor.enuDrawingStyle.brush:
                            callingForm.Cursor = Cursors.No;
                            callingForm.bolToggleBrush = false;
                            break;

                        case classMapEditor.enuDrawingStyle.floodfill:
                            callingForm.Cursor = callingForm.getTerrainTypeCursor(SelectedNewTerrainType);
                            callingForm.blinkCursor();
                            break;

                        case classMapEditor.enuDrawingStyle.singleCell:
                            callingForm.Cursor = callingForm.getTerrainTypeCursor(SelectedNewTerrainType);
                            break;
                    }
                    break;

                default:
                    break;
            }
        }

        void picTerrainType_MouseLeave(object sender, EventArgs e)
        {
            classPicSelection thisPic = (classPicSelection)sender;
            if (thisPic.myTerrainType != SelectedNewTerrainType)
                thisPic.Image = callingForm.cLibBattle.getTerrainImage(thisPic.myTerrainType, classBattle.enuTerrainImageSetting.shaded);
        }

        void picTerrainType_MouseEnter(object sender, EventArgs e)
        {
            classPicSelection thisPic = (classPicSelection)sender;
            thisPic.Image = callingForm.cLibBattle.getTerrainImage(thisPic.myTerrainType, classBattle.enuTerrainImageSetting.normal);
        }

        void nudWidth_ValueChanged(object sender, EventArgs e)
        {
            callingForm.szMapSize.Width = (int)nudWidth.Value;
            callingForm.resizeMap();
            blink();
        }

        void nudHeight_ValueChanged(object sender, EventArgs e)
        {
            callingForm.szMapSize.Height = (int)nudHeight.Value;
            callingForm.resizeMap();
            blink();
        }
    }

    public class classFloodFillElement
    {
        public classFloodFillElement next;
        public classFloodFillElement previous;
        public int intStepsFromStart;
        public Point pos;
        public classBattleUnit unit;
        public bool flag;

        public classFloodFillElement(int intStepsFromStart_local,
                                         Point pos_local)
        {
            pos = pos_local;
            intStepsFromStart = intStepsFromStart_local;
            next = null;
            previous = null;
        }
    }

    public class classDirLabel : Label
    {
        public classBattle.enuInitialUnitLocDirIndices myDir;
        public classDirLabel()
        {
            AutoSize = true;
        }
    }

    public class classInitLaunchDisplayLabel : Label
    {
        public Image oldImage;
    }


}
