using System;
using System.Collections.Generic;
using System.Text;
using GMap.NET.Internals;
using GMap.NET;
using GMap.NET.WindowsForms;
using GMap.NET.WindowsForms.Markers;
using System.Globalization;
using System.Xml;
using System.IO;
using System.Net;

namespace WindowsFormsApplication3
{
    class XmlType
    {
        public string Version;
        public string Encoding;
    }

    class StyleType
    {
        public string ID;
        public string Color;
        public int Width;
    }

    public enum PMarkType
    {
        Route,
        WayPoint
    }

    class KmlPlacemark
    {
        public PMarkType PMType;
        public string Name;
        public List<string> Description = new List<string>();
        public string Address;
        public List<Pair> StyleMap = new List<Pair>();
        public PointType Point = new PointType();
        public LookAtType LookAt = new LookAtType();
        public GeometricType GeometryCollection = new GeometricType();
        public string StyleURL;
    }

    class GeometricType
    {
        public List<GeoCoordinates> LineString = new List<GeoCoordinates>();
    }

    class GeoCoordinates
    {
        public List<CoordinatesType> Coordinates = new List<CoordinatesType>();
    }

    class CoordinatesType
    {
        public float Lontitude, Latitude, Altitude;
    }

    class LookAtType
    {
        public float Lontitude, Latitude, Range, Tilt, Heading;
    }
    class PointType
    {
        public CoordinatesType Coordinates = new CoordinatesType();
    }

    class Pair
    {
        public string Key;
        public StyleMType Style = new StyleMType();

    }
    class StyleMType
    {
        public IconStyleType IconStyle = new IconStyleType();
        public ListStyleType ListStyle = new ListStyleType();
    }

    class ListStyleType
    {
        public ItemIconStyle ItemIcon = new ItemIconStyle();
    }

    class ItemIconStyle
    {
        public string HRef;
    }

    class IconStyleType
    { 
        public IconStyle Icon = new IconStyle();
        public HotSpotStyle HotSpot = new HotSpotStyle();
 
    }

    class IconStyle
    {
        public string HRef;
    }
    class HotSpotStyle
    { 
        public string x,y,xunits,yunits;
    }

    class SnippetType
    {
        public int MaxLines;
        public List<string> Lines = new List<string>();
    }

    class KmlRoute
    {  
        public string UserAgent = "Opera/9.62 (Windows NT 5.1; U; en) Presto/2.1.1";
        /// <summary>
        /// timeout for map connections
        /// </summary>
        public int Timeout = 30 * 1000;

        /// <summary>
        /// proxy for net access
        /// </summary>
        public WebProxy Proxy;

        public XmlType Xml = new XmlType();
        public string XmlNameSpace;
        public string name;
        public string Language = "da";
        public PointLatLng Start;
        public PointLatLng End;
        public StyleType Style = new StyleType();
        public SnippetType Snippet = new SnippetType();
        public List<KmlPlacemark> Placemarks = new List<KmlPlacemark>();
        public List<string> RAWKml = new List<string>();
       

        private string[] t = new string[10000];
        private int lsCount = 0;
        private int StCount = 0;
        private string line;
        private KmlPlacemark PrvPlaceMark = new KmlPlacemark();
        private GeoCoordinates PrvGeoCoordinates = new GeoCoordinates();
        private CoordinatesType PrvCordinates = new CoordinatesType();
        private Pair PrvPair = new Pair();
        

        public KmlRoute()
        { 

        }

        public KmlRoute(PointLatLng start, PointLatLng end, string language, bool avoidHighways)
        {
            Language = language;
            Start = start;
            End = end;
            GetRouteBetweenPointsKml(start, end, avoidHighways);
        }

        internal string MakeRouteAndDirectionsKmlUrl(string start, string end, string language, bool avoidHighways)
        {
            string highway = avoidHighways ? "&mra=ls&dirflg=dh" : "&mra=ls&dirflg=d";

            return string.Format("http://maps.google.com/maps?output=kml&hl={0}{1}&q=&saddr=@{2}&daddr=@{3}", language, highway, start.Replace(' ', '+'), end.Replace(' ', '+'));
        } // http://maps.google.com/maps?f=l&output=Kml&doflg=p&hl={0}{1}&q=&saddr=@{2}&daddr=@{3}


        internal string MakeRouteAndDirectionsKmlUrl(PointLatLng start, PointLatLng end, string language, bool avoidHighways)
        {
            string highway = avoidHighways ? "&mra=ls&dirflg=dh" : "&mra=ls&dirflg=d";

            return string.Format("http://maps.google.com/maps?output=kml&hl={0}{1}&q=&saddr=@{2},{3}&daddr=@{4},{5}", language, highway, start.Lat.ToString(CultureInfo.InvariantCulture), start.Lng.ToString(CultureInfo.InvariantCulture), end.Lat.ToString(CultureInfo.InvariantCulture), end.Lng.ToString(CultureInfo.InvariantCulture));
        }

        public void GetRouteBetweenPointsKml(string start, string end, bool avoidHighways)
        {
            GeoCode(MakeRouteAndDirectionsKmlUrl(start, end, Language, avoidHighways));
        }

        public void GetRouteBetweenPointsKml(PointLatLng start, PointLatLng end, bool avoidHighways)
        {
            GeoCode(MakeRouteAndDirectionsKmlUrl(start, end, Language, avoidHighways));
        }

        private void GeoCode(string url)
        {
            WebRequest req = HttpWebRequest.Create(url);
            WebResponse res = req.GetResponse();
            StreamReader sr = new StreamReader(res.GetResponseStream());



            try
            {
                string Kmls = sr.ReadToEnd();
                Kmls.Replace("&#160;", " ");
                
                t = Kmls.Split('>');

                foreach (string str in t)
                { 
                    if (str == "")
                    {
                        //line = "";
                    }
                    else if ((str.StartsWith("<")) & (str.Substring(0, 2) != "<!"))
                        RAWKml.Add(str + ">");
                    else if (str.Substring(0, 2) == "<!")
                    {
                        string[] j = str.Split('<');
                        if (j[1].Contains("]]"))
                            j[1]+= ">";
                        RAWKml.Add("<" + j[1]);
                        if (j.Length > 2)
                            RAWKml.Add('<' + j[2] + '>');
                    }
                    else if (str.Contains("]]"))
                        RAWKml.Add(str + ">");
                    else if (str != "")
                    {
                        string[] j = str.Split('<');
                        RAWKml.Add(j[0]);
                        RAWKml.Add('<' + j[1] + '>');
                    }
                }
        
                // Run through Arraylist to setup KmlDocument
                int Count = 0; // Place marker in Kml

                string[] xmlvc = RAWKml[Count].Split('"');
                this.Xml.Version = xmlvc[1];
                this.Xml.Encoding = xmlvc[3];

                do
                {
                    Count++;
                } while (!RAWKml[Count].StartsWith("<kml"));

                string[] ns = RAWKml[Count].Split('"');

                this.XmlNameSpace = ns[1];

                do
                {
                    #region Snippet
                    if (RAWKml[Count].ToString() == "<Snippet>")
                    {
                        //lsCount = 0;
                        while (RAWKml[Count].ToString() != "</Snippet>")
                        {
                            Count++;
                            this.Snippet.Lines.Add(RAWKml[Count]);
                            //lsCount++;
                        }
                        this.Snippet.MaxLines = lsCount;

                    }
                    #endregion
                    #region PlaceMark
                    if (RAWKml[Count].ToString() == "<Placemark>")
                    {
                        //Determine Placemark Type;
                        PrvPlaceMark = new KmlPlacemark();
                        PrvPlaceMark.PMType = PMarkType.WayPoint;
                        lsCount = Count;
                        while (RAWKml[Count].ToString() != "</Placemark>")
                        { 
                            Count++;
                            if (RAWKml[Count] == "<GeometryCollection>")
                                PrvPlaceMark.PMType = PMarkType.Route;
                        }
                        Count = lsCount;

                        while (RAWKml[Count].ToString() != "</Placemark>")
                        {
                            Count++;
                            #region PlaceMark Name
                            if (RAWKml[Count].ToString() == "<name>")
                            {
                                Count++;
                                PrvPlaceMark.Name = RAWKml[Count].ToString();
                                Count++;
                            }
                            #endregion
                            #region PlaceMark Description
                            else if (RAWKml[Count].ToString() == "<description>")
                            {
                                while (RAWKml[Count].ToString() != "</description>")
                                {
                                    Count++;
                                    PrvPlaceMark.Description.Add(RAWKml[Count].ToString());
                                }
                            }
                            #endregion
                            #region PlaceMark Address
                            else if (RAWKml[Count].ToString() == "<address>")
                            {
                                Count++;
                                PrvPlaceMark.Address = RAWKml[Count].ToString();
                                Count++;
                            }
                            #endregion
                            #region PlaceMark StyleMap
                            else if (RAWKml[Count].ToString() == "<StyleMap>")
                            {                             
                                while (RAWKml[Count].ToString() != "</StyleMap>")
                                {
                                    Count++;
                                    PrvPair = new Pair();
                                    if (RAWKml[Count].ToString() == "<Pair>")
                                    {
                                        while (RAWKml[Count].ToString() != "</Pair>")
                                        {
                                            Count++;
                                            if (RAWKml[Count].ToString() == "<key>")
                                            {
                                                Count++;                 
                                                PrvPair.Key = RAWKml[Count].ToString();
                                                Count++;
                                            }
                                            else if (RAWKml[Count].ToString() == "<Style>")
                                            {
                                                while (RAWKml[Count].ToString() != "</Style>")
                                                {
                                                    Count++;
                                                    if (RAWKml[Count].ToString() == "<IconStyle>")
                                                    {
                                                        while (RAWKml[Count].ToString() != "</IconStyle>")
                                                        {
                                                            Count++;
                                                            if (RAWKml[Count].ToString() == "<Icon>")
                                                            {
                                                                while (RAWKml[Count].ToString() != "</Icon>")
                                                                {
                                                                    Count++;
                                                                    if (RAWKml[Count].ToString() == "<href>")
                                                                    {
                                                                        Count++;
                                                                        PrvPair.Style.IconStyle.Icon.HRef = RAWKml[Count].ToString();
                                                                        Count++;
                                                                    }
                                                                }
                                                            }
                                                            else if (RAWKml[Count].ToString() == "<hotSpot>")    
                                                            {
                                                                t = RAWKml[Count].Split('"');
                                                                PrvPair.Style.IconStyle.HotSpot.x = t[1];
                                                                PrvPair.Style.IconStyle.HotSpot.y = t[3];
                                                                PrvPair.Style.IconStyle.HotSpot.xunits = t[5];
                                                                PrvPair.Style.IconStyle.HotSpot.yunits = t[7];
                                                                Count++;
                                                            }
                                                        }
                                                    }
                                                    else if (RAWKml[Count].ToString() == "<ListStyle>")
                                                    {
                                                        while (RAWKml[Count].ToString() != "</ListStyle>")
                                                        {
                                                            Count++;
                                                            if (RAWKml[Count].ToString() == "<ItemIcon>")
                                                            {
                                                                while (RAWKml[Count].ToString() != "</ItemIcon>")
                                                                {
                                                                    Count++;
                                                                    if (RAWKml[Count].ToString() == "<href>")
                                                                    {
                                                                        Count++;
                                                                        PrvPair.Style.ListStyle.ItemIcon.HRef = RAWKml[Count].ToString();
                                                                        Count++;
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }    
                                            }
                                            
                                        }
                                        PrvPlaceMark.StyleMap.Add(PrvPair);
                                    }
                                }
                            }
                            #endregion
                            #region PlaceMark Point
                            else if (RAWKml[Count].ToString() == "<Point>")
                            {
                                while (RAWKml[Count].ToString() != "</Point>")
                                {
                                    Count++;
                                    if (RAWKml[Count].ToString() == "<coordinates>")
                                    {
                                        Count++;
                                        t = RAWKml[Count].Split(',');
                                        PrvPlaceMark.Point.Coordinates.Lontitude = (float)Convert.ToDouble(t[0]);
                                        PrvPlaceMark.Point.Coordinates.Latitude = (float)Convert.ToDouble(t[1]);
                                        if (t.Length == 3)
                                            PrvPlaceMark.Point.Coordinates.Altitude = (float)Convert.ToDouble(t[2]);
                                        Count++;

                                    }
                                }
                            }
                            #endregion
                            #region PlaceMark LookAt
                            else if (RAWKml[Count].ToString() == "<LookAt>")
                            {
                                while (RAWKml[Count].ToString() != "</LookAt>")
                                {
                                    Count++;
                                    if (RAWKml[Count].ToString() == "<longitude>")
                                    {
                                        Count++;
                                        PrvPlaceMark.LookAt.Lontitude = (float)Convert.ToDouble(RAWKml[Count].ToString());
                                        Count++;
                                    }
                                    else if (RAWKml[Count].ToString() == "<latitude>")
                                    {
                                        Count++;
                                        PrvPlaceMark.LookAt.Latitude = (float)Convert.ToDouble(RAWKml[Count].ToString());
                                        Count++;
                                    }
                                    else if (RAWKml[Count].ToString() == "<range>")
                                    {
                                        Count++;
                                        PrvPlaceMark.LookAt.Range = (float)Convert.ToDouble(RAWKml[Count].ToString());
                                        Count++;
                                    }
                                    else if (RAWKml[Count].ToString() == "<tilt>")
                                    {
                                        Count++;
                                        PrvPlaceMark.LookAt.Tilt = (float)Convert.ToDouble(RAWKml[Count].ToString());
                                        Count++;
                                    }
                                    else if (RAWKml[Count].ToString() == "<heading>")
                                    {
                                        Count++;
                                        PrvPlaceMark.LookAt.Heading = (float)Convert.ToDouble(RAWKml[Count].ToString());
                                        Count++;
                                    }
                                }
                            }
                            #endregion
                            #region PlaceMark StyleUrl
                            else if (RAWKml[Count].ToString() == "<styleUrl>")
                            {
                                Count++;
                                PrvPlaceMark.StyleURL = RAWKml[Count].ToString();
                                Count++;
                            }
                            #endregion
                            #region PlaceMark Geometry Collection
                            else if (RAWKml[Count].ToString() == "<GeometryCollection>")
                            {
                                while (RAWKml[Count].ToString() != "</GeometryCollection>")
                                {
                                    Count++;
                                    if (RAWKml[Count].ToString() == "<LineString>")
                                    {
                                        Count++;
                                        if (RAWKml[Count].ToString() == "<coordinates>")
                                        {
                                            Count++;
                                            line = RAWKml[Count].TrimEnd();
                                            
                                            t = RAWKml[Count].TrimEnd().Split(' ');
                                            foreach (string str in t)
                                            {
                                                string[] k = str.Split(',');
                                                PrvCordinates.Lontitude = (float)Convert.ToDouble(k[0]);
                                                PrvCordinates.Latitude = (float)Convert.ToDouble(k[1]);
                                                PrvCordinates.Altitude = (float)Convert.ToDouble(k[2]);
                                                PrvGeoCoordinates.Coordinates.Add(PrvCordinates);
                                            }
                                            Count++;
                                            PrvPlaceMark.GeometryCollection.LineString.Add(PrvGeoCoordinates);
                                        }
                                        Count++;
                                    }
                                }
                            }
                            #endregion
                        }
                        this.Placemarks.Add(PrvPlaceMark);
                    }
                    #endregion
                    #region Name
                    else if (RAWKml[Count].ToString() == "<name>")
                    {
                        Count++;
                        this.name = RAWKml[Count].ToString();
                        Count++;
                    }
                    #endregion
                    #region StyleID
                    else if (RAWKml[Count].StartsWith("<Style id="))
                    {
                        string[] Style = RAWKml[Count].ToString().Split('"');
                        this.Style.ID = Style[1];
                        while (RAWKml[Count] != "</Style>")
                        {
                            while (RAWKml[Count].ToString() != "</Style>")
                            {
                                Count++;
                                if (RAWKml[Count] == "<LineStyle>")
                                {
                                    while (RAWKml[Count].ToString() != "</LineStyle>")
                                    {
                                        Count++;
                                        if (RAWKml[Count].ToString() == "<color>")
                                        {
                                            Count++;
                                            this.Style.Color = RAWKml[Count];
                                            Count++;
                                        }
                                        if (RAWKml[Count].ToString() == "<width>")
                                        {
                                            Count++;
                                            this.Style.Width = Convert.ToInt16(RAWKml[Count]);
                                            Count++;
                                        }

                                    }

                                }
                            }
                        }
                        
                        //item.Style[0].LineStyle[0].
                    }
                    #endregion
                    Count++;

                } while (Count < RAWKml.Count);
            }
            finally
            {
                sr.Close();
            }
        }

    }
}
