using System;
using System.Drawing;
using System.Windows.Forms;

namespace Map_Extractor
{
    public partial class MapExtractor : Form
    {
        public MapExtractor()
        {
            InitializeComponent();

            Version v = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
            Text = String.Format("Map Extractor {0}.{1}", v.Major, v.Minor);

            Load_Parameters();
        }

        private void Load_Parameters()
        {
            Parameters.LoadParameters();

            sourceFiles.Text = Parameters.SourcePath;
            sourceMap.SelectedIndex = Parameters.SourceMap;
            destinationFiles.Text = Parameters.DestinationPath;
            destinationMap.SelectedIndex = Parameters.DestinationMap;
            copyStatics.Checked = Parameters.CopyStatics;
            entireMap.Checked = Parameters.EntireMap;
            portion.Checked = !Parameters.EntireMap;

            if (Parameters.SourceArea.X != -1)
                sX.Text = Parameters.SourceArea.X.ToString();

            if (Parameters.SourceArea.Y != -1)
                sY.Text = Parameters.SourceArea.Y.ToString();

            if (Parameters.SourceArea.Width != -1)
                sW.Text = Parameters.SourceArea.Width.ToString();

            if (Parameters.SourceArea.Height != -1)
                sH.Text = Parameters.SourceArea.Height.ToString();

            if (Parameters.DestinationLocation.X != -1)
                dX.Text = Parameters.DestinationLocation.X.ToString();

            if (Parameters.DestinationLocation.Y != -1)
                dY.Text = Parameters.DestinationLocation.Y.ToString();
        }

        private void Save_Parameters()
        {
            Parameters.SourcePath = sourceFiles.Text;
            Parameters.DestinationPath = destinationFiles.Text;
            Parameters.SourceMap = sourceMap.SelectedIndex;
            Parameters.DestinationMap = destinationMap.SelectedIndex;
            Parameters.CopyStatics = copyStatics.Checked;
            Parameters.EntireMap = entireMap.Checked;

            int sX = -1;
            int sY = -1;
            int sW = -1;
            int sH = -1;
            int dX = -1;
            int dY = -1;

            try { sX = (this.sX.Text == "" ? -1 : Convert.ToInt32(this.sX.Text)); }
            catch { }

            try { sY = (this.sY.Text == "" ? -1 : Convert.ToInt32(this.sY.Text)); }
            catch { }

            try { sW = (this.sW.Text == "" ? -1 : Convert.ToInt32(this.sW.Text)); }
            catch { }

            try { sH = (this.sH.Text == "" ? -1 : Convert.ToInt32(this.sH.Text)); }
            catch { }

            try { dX = (this.dX.Text == "" ? -1 : Convert.ToInt32(this.dX.Text)); }
            catch { }

            try { dY = (this.dY.Text == "" ? -1 : Convert.ToInt32(this.dY.Text)); }
            catch { }

            Parameters.SourceArea = new Rectangle(sX, sY, sW, sH);
            Parameters.DestinationLocation = new Point(dX, dY);

            Parameters.SaveParameters();
        }

        private void MapExtractor_FormClosing(object sender, FormClosingEventArgs e)
        {
            Save_Parameters();
        }

        private void mulFiles_DropDownClicked(object sender, EventArgs e)
        {
            FolderBrowserDialog dialog = new FolderBrowserDialog();
            dialog.ShowDialog(this);
            sourceFiles.Text = dialog.SelectedPath;
        }

        private void destinationFiles_DropDownClicked(object sender, EventArgs e)
        {
            FolderBrowserDialog dialog = new FolderBrowserDialog();
            dialog.ShowDialog(this);
            destinationFiles.Text = dialog.SelectedPath;
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            if (portion.Checked && (sX.Text == "" || sY.Text == "" || sW.Text == "" || sW.Text == "" || dX.Text == "" || dY.Text == ""))
            {
                MessageBox.Show("Please complete all of the coordinates to continue.");
                return;
            }

            Save_Parameters();

            Map sourcemap = null;
            Map destinationmap = null;
            Statics sourcestatics = null;
            Statics destinationstatics = null;

            Initialize_Map(sourceMap.SelectedIndex, ref sourcemap);
            Initialize_Map(destinationMap.SelectedIndex, ref destinationmap);

            if (Parameters.CopyStatics)
            {
                Initialize_Statics(sourceMap.SelectedIndex, ref sourcestatics);
                Initialize_Statics(destinationMap.SelectedIndex, ref destinationstatics);
            }

            if (sourceMap == null || destinationMap == null ||
                ((sourcestatics == null || destinationstatics == null) && Parameters.CopyStatics) ||
                sourceFiles.Text == "" || destinationFiles.Text == "")
                return;

            bool result = true;

            if (sourcemap.FileIndex == destinationmap.FileIndex && sourceFiles.Text == destinationFiles.Text)
                result = false;

            if (result)
            {
                result &= sourcemap.OpenMap(sourceFiles.Text, false);
                result &= destinationmap.OpenMap(destinationFiles.Text, true);

                if (Parameters.CopyStatics)
                {
                    result &= sourcestatics.OpenStatics(sourceFiles.Text, false);
                    result &= destinationstatics.OpenStatics(destinationFiles.Text, true);
                }
            }

            if (!result)
            {
                MessageBox.Show("Error opening files. Please verify your settings.");
                return;
            }

            Cursor = Cursors.WaitCursor;
            Extract(sourcemap, destinationmap, sourcestatics, destinationstatics);
            Cursor = Cursors.Default;

            sourcemap.Close();
            destinationmap.Close();

            if (Parameters.CopyStatics)
            {
                sourcestatics.Close();
                destinationstatics.Close();
            }

            MessageBox.Show("Extraction Complete!");
        }

        private void Initialize_Map(int fileIndex, ref Map map)
        {
            switch (fileIndex)
            {
                case 0:
                    map = new Map(0, 6144, 4096);
                    break;
                case 1:
                    map = new Map(0, 7168, 4096);
                    break;
                case 2:
                    map = new Map(1, 6144, 4096);
                    break;
                case 3:
                    map = new Map(1, 7168, 4096);
                    break;
                case 4:
                    map = new Map(2, 2304, 1600);
                    break;
                case 5:
                    map = new Map(3, 2560, 2048);
                    break;
                case 6:
                    map = new Map(4, 1448, 1448);
                    break;
                case 7:
                    map = new Map(5, 1280, 4096);
                    break;
            }
        }

        private void Initialize_Statics(int fileIndex, ref Statics statics)
        {
            switch (fileIndex)
            {
                case 0:
                    statics = new Statics(0, 6144, 4096);
                    break;
                case 1:
                    statics = new Statics(0, 7168, 4096);
                    break;
                case 2:
                    statics = new Statics(1, 6144, 4096);
                    break;
                case 3:
                    statics = new Statics(1, 7168, 4096);
                    break;
                case 4:
                    statics = new Statics(2, 2304, 1600);
                    break;
                case 5:
                    statics = new Statics(3, 2560, 2048);
                    break;
                case 6:
                    statics = new Statics(4, 1448, 1448);
                    break;
                case 7:
                    statics = new Statics(5, 1280, 4096);
                    break;
            }
        }

        private void Extract(Map sourcemap, Map destinationmap, Statics sourcestatics, Statics destinationstatics)
        {
            if (portion.Checked)
            {
                ExtractPartial(sourcemap, destinationmap, sourcestatics, destinationstatics);
                return;
            }

            progress.Value = 0;
            progress.Maximum = destinationmap.Width * destinationmap.Height;
            progress.Visible = true;

            for (int x = 0; x < destinationmap.Width; x++)
            {
                for (int y = 0; y < destinationmap.Height; y++)
                {
                    if (x < sourcemap.Width && y < sourcemap.Height)
                    {
                        Block b = sourcemap.ReadBlock(x, y);
                        destinationmap.WriteBlock(b, x, y);

                        if (Parameters.CopyStatics)
                        {
                            IDX idx = sourcestatics.ReadBlock(x, y);
                            destinationstatics.WriteBlock(idx, x, y);
                        }
                    }
                    else
                    {
                        destinationmap.WriteEmptyBlock(x, y);

                        if (Parameters.CopyStatics)
                            destinationstatics.WriteEmptyBlock(x, y);
                    }

                    progress.Increment(1);
                }
            }

            progress.Visible = false;
        }

        private void ExtractPartial(Map sourcemap, Map destinationmap, Statics sourcestatics, Statics destinationstatics)
        {
            int sX = Parameters.SourceArea.X / 8;
            int sY = Parameters.SourceArea.Y / 8;
            int sW = Parameters.SourceArea.Width / 8;
            int sH = Parameters.SourceArea.Height / 8;

            int dX = Parameters.DestinationLocation.X / 8;
            int dY = Parameters.DestinationLocation.Y / 8;

            int sXe = sX + sW;
            int sYe = sY + sH;

            progress.Value = 0;
            progress.Maximum = destinationmap.Width * destinationmap.Height;
            progress.Visible = true;

            for (int x = sX; x < sXe; x++)
            {
                for (int y = sY; y < sYe; y++)
                {
                    if (sX < sourcemap.Width && sY < sourcemap.Height)
                    {
                        Block b = sourcemap.ReadBlock(x, y);
                        destinationmap.WriteBlock(b, x + (dX - sX), y + (dY - sY));

                        if (Parameters.CopyStatics)
                        {
                            IDX idx = sourcestatics.ReadBlock(x, y);
                            destinationstatics.WriteBlock(idx, x + (dX - sX), y + (dY - sY));
                        }
                    }
                    else
                    {
                        destinationmap.WriteEmptyBlock(x + (dX - sX), y + (dY - sY));

                        if (Parameters.CopyStatics)
                            destinationstatics.WriteEmptyBlock(x + (dX - sX), y + (dY - sY));
                    }

                    progress.Increment(1);
                }
            }

            progress.Visible = false;
        }

        private void portion_CheckedChanged(object sender, EventArgs e)
        {
            coordBox.Visible = portion.Checked;
        }

        private void conversionButton_Click(object sender, EventArgs e)
        {
            ConversionTable ct = new ConversionTable();
            ct.Initialize();
            ct.ShowDialog(this);
        }
    }
}
