using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Reflection;

using ProLatNet;

namespace ProLatCalcCSharp
{
    public partial class Form1 : Form
    {
        List<string> GroupsA, GroupsB, GroupDesc, GroupDefDatum;
        List<string> SystemsA, SystemDescA;
        List<string> SystemsB, SystemDescB;
        List<string> DatumsA, DatumsB, DatumDesc, UnitsA, UnitsB, UnitDesc;

        public Form1()
        {
            InitializeComponent();
        }
        
        private void Form1_Load(object sender, EventArgs e)
        {
            // Fill the combo boxes with defaults
            try
            {
                // Change this to your local installation path
                CoordSys.AddFileLocationFolder("c:\\eng\\prolatnet\\geodesy");

                // Get the geodesy lists of groups, datums, and units
                GroupsA = CoordSys.GetGroups(out GroupDesc, out GroupDefDatum);
                DatumsA = CoordSys.GetDatums(out DatumDesc);
                UnitsA = CoordSys.GetUnits(out UnitDesc);
                // Set combo box data sources first before setting any indexes (except system boxes which get filled when group is selected).
                ComboAGroup.DataSource = GroupsA;
                ComboADatum.DataSource = DatumsA;
                ComboAUnits.DataSource = UnitsA;
                // Set the default A coordinate system
                ComboAGroup.SelectedItem = "LAT_LONG";  // This causes the system combo box to be filled
                ComboASystem.SelectedItem = "LAT-LONG";
                ComboADatum.SelectedItem = "WGS84";
                ComboAUnits.SelectedItem = "METERS";     // Even though it is actually degrees lat/lon

                GroupsB = new List<string>(GroupsA);    // Get copies
                DatumsB = new List<string>(DatumsA);
                UnitsB = new List<string>(UnitsA);
                ComboBGroup.DataSource = GroupsB;       // Set data sources
                ComboBDatum.DataSource = DatumsB;
                ComboBUnits.DataSource = UnitsB;
                ComboBGroup.SelectedItem = "UTM";       // Causes system combo box to be filled
                ComboBSystem.SelectedItem = "UTM-17N";
                ComboBDatum.SelectedItem = "WGS84";
                ComboBUnits.SelectedItem = "METERS";

                
            }
            catch(CSConfigException ex)
            {
                MessageBox.Show(ex.Message);
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            
        }

        // Two function to enable and disable coordinate system controls depending on the radio buttons
        void UpdateCoordinateSystemControlsA()
        {
            if( RadioAGeodesy.Checked)
            {
                ComboAGroup.Enabled = true;
                ComboASystem.Enabled = true;
                ComboADatum.Enabled = true;
                ComboAUnits.Enabled = true;

                TextAProj.Enabled = false;
            }
            else
            {
                ComboAGroup.Enabled = false;
                ComboASystem.Enabled = false;
                ComboADatum.Enabled = false;
                ComboAUnits.Enabled = false;

                TextAProj.Enabled = true;
            }
        }

        void UpdateCoordinateSystemControlsB()
        {
            if (RadioBGeodesy.Checked)
            {
                ComboBGroup.Enabled = true;
                ComboBSystem.Enabled = true;
                ComboBDatum.Enabled = true;
                ComboBUnits.Enabled = true;

                TextBProj.Enabled = false;
            }
            else
            {
                ComboBGroup.Enabled = false;
                ComboBSystem.Enabled = false;
                ComboBDatum.Enabled = false;
                ComboBUnits.Enabled = false;

                TextBProj.Enabled = true;
            }
        }

        private void RadioAGeodesy_CheckedChanged(object sender, EventArgs e)
        {
            UpdateCoordinateSystemControlsA();
        }

        private void RadioAProj_CheckedChanged(object sender, EventArgs e)
        {
            UpdateCoordinateSystemControlsA();
        }

        private void RadioBGeodesy_CheckedChanged(object sender, EventArgs e)
        {
            UpdateCoordinateSystemControlsB();
        }

        private void RadioBProj_CheckedChanged(object sender, EventArgs e)
        {
            UpdateCoordinateSystemControlsB();
        }

        private void ComboAGroup_SelectedIndexChanged(object sender, EventArgs e)
        {
            LblAGroupDesc.Text = GroupDesc[ComboAGroup.SelectedIndex];
            SystemsA = CoordSys.GetSystems(ComboAGroup.Text, out SystemDescA);   // Get the systems for the new group
            ComboASystem.DataSource = SystemsA;                                  // Set the systems combo box
            ComboASystem.SelectedIndex = 0;                                      // Select the first system

            if ( !GroupDefDatum[ComboAGroup.SelectedIndex].Equals("Any"))
                ComboADatum.SelectedItem = GroupDefDatum[ComboAGroup.SelectedIndex]; // Set the datum to the group's default datum
            else
                ComboADatum.SelectedItem = "WGS84";
            FillProjA();
        }

        private void FillProjA()
        {
            try
            {
                CoordSys A = CoordSys.GetCS(ComboAGroup.Text, ComboASystem.Text, ComboADatum.Text, ComboAUnits.Text);
                string def = A.getDef();
                TextAProj.Text = def;
            }
            catch (Exception e)
            {
                // Do nothing 
            }
        }

        private void FillProjB()
        {
            try
            {
                CoordSys B = CoordSys.GetCS(ComboBGroup.Text, ComboBSystem.Text, ComboBDatum.Text, ComboBUnits.Text);
                string def = B.getDef();
                TextBProj.Text = def;
            }
            catch (Exception e)
            {
                // Do nothing 
            }
        }

        private void ComboASystem_SelectedIndexChanged(object sender, EventArgs e)
        {
            LblASystemDesc.Text = SystemDescA[ComboASystem.SelectedIndex];        // Set the description of the system
            FillProjA();
        }

        private void ComboADatum_SelectedIndexChanged(object sender, EventArgs e)
        {
            LblADatumDesc.Text = DatumDesc[ComboADatum.SelectedIndex];           // Set the description of the datum
            FillProjA();
        }

        private void ComboAUnits_SelectedIndexChanged(object sender, EventArgs e)
        {
            LblAUnitDesc.Text = UnitDesc[ComboAUnits.SelectedIndex];             // Set the description of the unit
            FillProjA();
        }

        private void ComboBGroup_SelectedIndexChanged(object sender, EventArgs e)
        {
            LblBGroupDesc.Text = GroupDesc[ComboBGroup.SelectedIndex];
            SystemsB = CoordSys.GetSystems(ComboBGroup.Text, out SystemDescB);   // Get the systems for the new group
            ComboBSystem.DataSource = SystemsB;                                  // Set the systems combo box
            ComboBSystem.SelectedIndex = 0;                                      // Select the first system

            if (!GroupDefDatum[ComboBGroup.SelectedIndex].Equals("Any"))
                ComboBDatum.SelectedItem = GroupDefDatum[ComboBGroup.SelectedIndex]; // Set the datum to the group's default datum
            else
                ComboBDatum.SelectedItem = "WGS84";
            FillProjB();
        }

        private void ComboBSystem_SelectedIndexChanged(object sender, EventArgs e)
        {
            LblBSystemDesc.Text = SystemDescB[ComboBSystem.SelectedIndex];
            FillProjB();
        }

        private void ComboBDatum_SelectedIndexChanged(object sender, EventArgs e)
        {
            LblBDatumDesc.Text = DatumDesc[ComboBDatum.SelectedIndex];
            FillProjB();
        }

        private void ComboBUnits_SelectedIndexChanged(object sender, EventArgs e)
        {
            LblBUnitDesc.Text = UnitDesc[ComboBUnits.SelectedIndex];
            FillProjB();
        }

        private void ButtonConvertAB_Click(object sender, EventArgs e)
        {
            if ( TextALonx.Text.Length == 0 || TextALaty.Text.Length == 0)
            {
                MessageBox.Show("Please enter input values in section A");
            }

            try
            {
                CoordSys A, B;
                if (RadioAGeodesy.Checked)
                    A = CoordSys.GetCS(ComboAGroup.Text, ComboASystem.Text, ComboADatum.Text, ComboAUnits.Text);
                else
                    A = CoordSys.GetCS(TextAProj.Text);
            
                if ( RadioBGeodesy.Checked )
                    B = CoordSys.GetCS(ComboBGroup.Text, ComboBSystem.Text, ComboBDatum.Text, ComboBUnits.Text);
                else
                    B = CoordSys.GetCS(TextBProj.Text);

                double[] LonX = new double[1];
                double[] LatY = new double[1];
                double[] Z    = new double[1];

                LonX[0] = DMS.GetLon(TextALonx.Text);
                LatY[0] = DMS.GetLat(TextALaty.Text);

                double valZ = 0;
                if (TextAz.Text.Length > 0)
                    valZ = Double.Parse(TextAz.Text);
                Z[0] = valZ;

                CoordSys.Transform(A, B, LonX, LatY, Z, 1);

                TextBLonx.Text = Math.Round(LonX[0], 9).ToString();
                TextBLaty.Text = Math.Round(LatY[0], 9).ToString();
                TextBz.Text = Math.Round(Z[0], 4).ToString();

                if (!B.is_geocent && !B.is_latlong) 
                {
                    // Calculate scale and convergence angle
                    double[] scale = new double[1];
                    double[] angle = new double[1];
                    B.ScaleConvergence(LonX, LatY, scale, angle, 1);
                    TextBScale.Text = Math.Round(scale[0], 6).ToString();
                    TextBAngle.Text = Math.Round(angle[0], 4).ToString();
                }
            }
            catch (CSConfigException ex)
            {
                MessageBox.Show(ex.Message, "ProLat message", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }

        private void ButtonConvertBA_Click(object sender, EventArgs e)
        {
            if ( TextBLonx.Text.Length == 0 || TextBLaty.Text.Length == 0)
            {
                MessageBox.Show("Please enter input values in section A");
            }

            try
            {
                CoordSys A, B;
                if (RadioAGeodesy.Checked)
                    A = CoordSys.GetCS(ComboAGroup.Text, ComboASystem.Text, ComboADatum.Text, ComboAUnits.Text);
                else
                    A = CoordSys.GetCS(TextAProj.Text);
            
                if ( RadioBGeodesy.Checked )
                    B = CoordSys.GetCS(ComboBGroup.Text, ComboBSystem.Text, ComboBDatum.Text, ComboBUnits.Text);
                else
                    B = CoordSys.GetCS(TextBProj.Text);

                double[] LonX = new double[1];
                double[] LatY = new double[1];
                double[] Z    = new double[1];

                LonX[0] = DMS.GetLon(TextBLonx.Text);
                LatY[0] = DMS.GetLat(TextBLaty.Text);

                double valZ = 0;
                if (TextBz.Text.Length > 0)
                    valZ = Double.Parse(TextBz.Text);
                Z[0] = valZ;

                CoordSys.Transform(B, A, LonX, LatY, Z, 1);

                TextALonx.Text = Math.Round(LonX[0], 9).ToString();
                TextALaty.Text = Math.Round(LatY[0], 9).ToString();
                TextAz.Text = Math.Round(Z[0], 4).ToString();
            }
            catch (CSConfigException ex)
            {
                MessageBox.Show(ex.Message, "ProLat message", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }

        private void ButtonDMS_Click(object sender, EventArgs e)
        {
            double[] Lon, Lat, Z;
            string sData = "80 25 49.12 W  35 41 29 N\r\n" +
                           "12 25 49.12 E  15 41 29 S  225.4";

            string msg;
            int ErrorCount = DMS.GetDMS(sData, 1, out Lon, out Lat, out Z, out msg);

            string Output = "GetDMS returned:\r\n";
            if (ErrorCount > 0)
                Output += "Errors detected: " + ErrorCount.ToString() + "\r\n";

            if (msg.Length > 0)
                Output += "Return message: " + msg + "\r\n";

            for (int i = 0; i<= 1; i++)
                Output += Lon[i].ToString() + " " + Lat[i].ToString() + "\r\n";

            MessageBox.Show(Output);
        }

        private void ButtonMGRS_Click(object sender, EventArgs e)
        {
            try
            {
                MGRS mgrs = new MGRS();  // Uses default WGS84 ellipsoid.  
                                         // For NAD27 ellipsoid use: new MGRS("datum=NAD27")
                double lon = 5;
                double lat = 57;
                string outMGRS = mgrs.ConvertFromGeodetic(lon, lat);
                MessageBox.Show("MGRS example:  lon/lat: " +
                    lon.ToString() + " " + lat.ToString() + 
                    "\r\nMGRS: " + outMGRS);
            }
            catch(CSConfigException ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        
    }
}
