using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Xml;
using System.Globalization;
using System.Net;
using System.IO;
using System.Diagnostics;

namespace GoogleMaps
{

    public class GeoCoderTest
    {

        public static string MakeGeocoderListUrl(string keywords)
        {
            string key = keywords.Replace(' ', '+');
            return string.Format("http://maps.google.com/maps/geo?q={0}&output=xml", key);
        }

        public static GeoCoderResponse GetResponseFromGeocoderUrl(string url, bool useCache)
        {

            try
            {
                string urlEnd = url.Substring(url.IndexOf("geo?q="));

                //char[] ilg = Path.GetInvalidFileNameChars();
                //foreach (char c in ilg)
                //{
                //    urlEnd = urlEnd.Replace(c, '_');
                //}

                string geo = string.Empty; //useCache ? Cache.GetGeocoderFromCache(urlEnd) : string.Empty;

                if (string.IsNullOrEmpty(geo))
                {
                    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                    request.ServicePoint.ConnectionLimit = 50;
                    //request.Proxy = Proxy != null ? Proxy : WebRequest.DefaultWebProxy;

                    request.UserAgent = "Opera/9.62 (Windows NT 5.1; U; en) Presto/2.1.1";
                    request.Timeout = 10000;
                    request.ReadWriteTimeout = 10000 * 6;

                    //request.Accept = "text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1";
                    //request.Headers["Accept-Charset"] = "utf-8, utf-16, iso-8859-1, *;q=0.1";
                    //request.Referer = "http://maps.google.com/";
                    request.KeepAlive = true;

                    using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
                    {
                        using (Stream responseStream = response.GetResponseStream())
                        {
                            using (StreamReader read = new StreamReader(responseStream))
                            {
                                geo = read.ReadToEnd();
                            }
                        }
                    }

                    // cache geocoding
                    ////if (useCache)
                    ////{
                    ////    Cache.CacheGeocoder(urlEnd, geo);
                    ////}
                }

                // parse values
                // true : 200,4,56.1451640,22.0681787
                // false: 602,0,0,0
                {
                    if (!string.IsNullOrEmpty(geo))
                    {
                        //I couldn't find a way to simply deserializing the resonse in one go.
                        GeoCoderResponse r = new GeoCoderResponse();
                        XmlDocument doc = new XmlDocument();
                        doc.LoadXml(geo);
                        XmlNodeList xStatus = doc.GetElementsByTagName("Status");
                        if (xStatus.Count > 0)
                        {
                            foreach (XmlNode child in xStatus[0].ChildNodes)
                                if (child.LocalName == "code")
                                {
                                    r.Status = int.Parse(child.InnerText);
                                    break;
                                }
                        }
                        XmlNodeList xList = doc.GetElementsByTagName("Placemark");
                        foreach (XmlNode xNode in xList)
                        {
                            Placemark pm = Placemark.Deserialize(xNode.OuterXml);
                            if (pm != null)
                                r.Add(pm);
                        }
                        return r;
                    }
                }
            }
            catch (Exception ex)
            {
                Trace.WriteLine("GetLatLngFromUrl: " + ex.ToString());
            }
            return null;
        }

    }
    public class GeoCoderResponse : List<Placemark>
    {
        private string _name;
        private int _status;

        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        public int Status
        {
            get { return _status; }
            set { _status = value; }
        }

        //public virtual string Serialize()
        //{
        //    System.IO.MemoryStream str = new System.IO.MemoryStream();
        //    XmlSerializer ser = new XmlSerializer(typeof(GeoCoderResponse));
        //    ser.Serialize(str, this);
        //    str.Flush();
        //    str.Position = 0;
        //    System.IO.StreamReader sreader = new System.IO.StreamReader(str);
        //    return sreader.ReadToEnd();
        //}

        //public static GeoCoderResponse Deserialize(string state)
        //{
        //    try
        //    {
        //        if (state != null)
        //        {
        //            System.IO.StringReader sReader = new System.IO.StringReader(state);
        //            XmlSerializer ser = new XmlSerializer(typeof(GeoCoderResponse));
        //            GeoCoderResponse tmp = null;
        //            XmlTextReader rdr = new XmlTextReader(sReader);
        //            rdr.WhitespaceHandling = WhitespaceHandling.Significant;
        //            tmp = (GeoCoderResponse)ser.Deserialize(rdr);
        //            return tmp;
        //        }
        //    }
        //    catch (Exception ex)
        //    {
        //        System.Diagnostics.Debug.WriteLine(ex.ToString());
        //    }

        //    return new GeoCoderResponse();
        //}
    }

    public class Placemark
    {

        private string _address;
        private gAddressDetails _addressDetails;
        private gPoint _point;

        public string address
        {
            get { return _address;}
            set { _address = value;}
        }

        public gAddressDetails AddressDetails
        {
            get { return _addressDetails; }
            set { _addressDetails = value; }
        }

        public gPoint Point
        {
            get { return _point; }
            set { _point = value; }
        }

        public static Placemark Deserialize(string state)
        {
            try
            {
                if (state != null)
                {
                    System.IO.StringReader sReader = new System.IO.StringReader(state);
                    XmlSerializer ser = new XmlSerializer(typeof(Placemark));
                    Placemark tmp = null;
                    XmlTextReader rdr = new XmlTextReader(sReader);
                    rdr.Namespaces = false;
                    rdr.WhitespaceHandling = WhitespaceHandling.Significant;
                    tmp = (Placemark)ser.Deserialize(rdr);
                    return tmp;
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.ToString());
            }

            return null;
        }

    }

    public class gPoint
    {
        private string _gPoint;

        public string coordinates
        {
            get { return _gPoint; }
            set { _gPoint = value; }
        }

        public GMapNET.PointLatLng? LatLng
        {
            get
            {
                try
                {
                    string[] coords = _gPoint.Split(',');
                    if (coords.Length > 1)
                        return new GMapNET.PointLatLng(double.Parse(coords[1], CultureInfo.InvariantCulture), double.Parse(coords[1], CultureInfo.InvariantCulture));
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex.ToString());
                }
                return null;
            }
        }
    }
    public class gAddressDetails
    {
        private gCountry _country;

        public gCountry Country
        {
            get { return _country;}
            set { _country = value;}
        }
    }

    public class gCountry
    {
        private string _countryNameCode;
        private string _countryName;
        private gAdministrativeArea _administrativeArea;

        public string CountryNameCode
        {
            get { return _countryNameCode;}
            set { _countryNameCode = value;}
        }

        public string CountryName
        {
            get { return _countryName;}
            set { _countryName = value;}
        }

        public gAdministrativeArea AdministrativeArea
        {
            get { return _administrativeArea; }
            set { _administrativeArea = value; }
        }

    }

    public class gAdministrativeArea
    {

        private string _administrativeAreaName;
        private gSubAdministrativeArea _subAdministrativeArea;

        public string AdministrativeAreaName
        {
            get { return _administrativeAreaName; }
            set { _administrativeAreaName = value; }
        }

        public gSubAdministrativeArea SubAdministrativeArea
        {
            get { return _subAdministrativeArea; }
            set { _subAdministrativeArea = value; }
        }
    }

    public class gSubAdministrativeArea
    {
        private gLocality _locality;

        public gLocality Locality
        {
            get { return _locality; }
            set { _locality = value; }
        }
    }

    public class gLocality
    {
        private string _localityName;
        private gThroughfare _throughfare;
        private gPostalCode _postalCode;

        public string LocalityName
        {
            get { return _localityName; }
            set { _localityName = value; }
        }

        public gThroughfare Throughfare
        {
            get { return _throughfare; }
            set { _throughfare = value; }
        }

        public gPostalCode PostalCode
        {
            get { return _postalCode; }
            set { _postalCode = value; }
        }
    }

    public class gThroughfare
    {
        private string _throughfareName;

        public string ThroughfareName
        {
            get { return _throughfareName; }
            set { _throughfareName = value; }
        }
    }

    public class gPostalCode
    {
        private string _postalCodeNumber;

        public string PostalCodeNumber
        {
            get { return _postalCodeNumber; }
            set { _postalCodeNumber = value; }
        }
    }

}
