using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Shapes;
using System.Xml.Linq;

namespace System.Windows.Controls
{
    public class AbstractView
    {
        public String Id { get; set; }
        public Double Longitude { get; set; }
        public Double Latitude { get; set; }
        public Double Altitude { get; set; }
        public String AltitudeMode { get; set; }
        public Double Range { get; set; }
        public Double Tilt { get; set; }
        public Double Heading { get; set; }
       

        public AbstractView()
        {

        }

        public AbstractView(XElement item)
        {
            if (item.Attribute("id") != null) Id = item.Attribute("id").Value;
            if (item.Element("longitude") != null) Longitude = Convert.ToDouble(item.Element("longitude").Value);
            if (item.Element("latitude") != null) Latitude = Convert.ToDouble(item.Element("latitude").Value);
            if (item.Element("altitude") != null) Altitude = Convert.ToDouble(item.Element("altitude").Value);
            if (item.Element("altitudeMode") != null) AltitudeMode = item.Element("altitudeMode").Value;
            if (item.Element("range") != null) Range = Convert.ToDouble(item.Element("range").Value);
            if (item.Element("tilt") != null) Tilt = Convert.ToDouble(item.Element("tilt").Value);
            if (item.Element("heading") != null) Heading = Convert.ToDouble(item.Element("heading").Value);
        }
    }

    /// <summary>
    /// C# representation of a KML placemark
    /// </summary>
    public class KmlPlacemark
    {
        public String Id { get; set; }
        public String Name { get; set; }
        public String Description { get; set; }

        public String Address { get; set; }
        public String AddressDetails { get; set; }
        public String Author { get; set; }

        public String ExtendedData { get; set; }
        public String Link { get; set; }
        public AbstractView LookAt { get; set; }
        public Boolean Open { get; set; }
        public String PhoneNumber { get; set; }
        public String Region { get; set; }
        public String Snippet { get; set; }
        public String StyleUrl { get; set; }
        public String StyleSelector { get; set; }
        public String TimePrimitive { get; set; }
        public Boolean Visibility { get; set; }

        /// <summary>
        /// The polygon outer and innerboundries that make up this placemark
        /// </summary>
        public List<KmlGeometry> KmlGeometries { get; set; }

        public KmlPlacemark()
        {
            KmlGeometries = new List<KmlGeometry>();
        }

        public KmlPlacemark(XElement item)
        {
            if (item.Attribute("id")!=null) Id = item.Attribute("id").Value;

            if (item.Element("name") != null) Name = item.Element("name").Value;
            if (item.Element("description") != null) Description = item.Element("description").Value;

            if (item.Element("address") != null) Address = item.Element("address").Value;
            if (item.Element("AddressDetails") != null) AddressDetails = item.Element("AddressDetails").Value;
            if (item.Element("author") != null) Author = item.Element("author").Value;

            if (item.Element("ExtendedData") != null) ExtendedData = item.Element("ExtendedData").Value;
            if (item.Element("link") != null) Link = item.Element("link").Value;

            if (item.Element("LookAt") != null) LookAt = new AbstractView(item.Element("LookAt"));
            if (item.Element("Camera") != null) LookAt = new AbstractView(item.Element("Camera"));

            if (item.Element("longitude") != null && item.Element("latitude") != null)
            { 
                LookAt = new AbstractView();
                LookAt.Longitude = Convert.ToDouble(item.Element("longitude").Value);
                LookAt.Latitude = Convert.ToDouble(item.Element("latitude").Value);
            }

            if (item.Element("open") != null) Open = Convert.ToBoolean(item.Element("open").Value);
            if (item.Element("phoneNumber") != null) PhoneNumber = item.Element("phoneNumber").Value;
            if (item.Element("Region") != null) Region = item.Element("Region").Value;

            if (item.Element("Snippet") != null) Snippet = item.Element("Snippet").Value;
            if (item.Element("styleUrl") != null) StyleUrl = item.Element("styleUrl").Value;
            if (item.Element("StyleSelector") != null) StyleSelector = item.Element("StyleSelector").Value;
            if (item.Element("TimePrimitive") != null) TimePrimitive = item.Element("TimePrimitive").Value;
            if (item.Element("visibility") != null) Visibility = Convert.ToBoolean(item.Element("visibility").Value);

            KmlGeometries = new List<KmlGeometry>();

            if (item.Element("MultiGeometry") != null)
            {
                KmlGeometries = KmlHelper.KmlMultiGeometryToGeometryList(item.Element("MultiGeometry"));
            }
            else
            {
                if (item.Element("Polygon") != null)
                {
                    KmlGeometries.Add(KmlHelper.KmlPolygonToGeometry(item.Element("Polygon")));
                }
            }

        }
    
    }




    public class KmlGeometry
    {
        public Polygon OuterBoundry { get; set; }
        public List<Polygon> InnerBoundries { get; set; }

        public KmlGeometry()
        {
            OuterBoundry = new Polygon();
            InnerBoundries = new List<Polygon>();
        }
    }


    public static class KmlHelper
    {
        public static List<KmlGeometry> KmlMultiGeometryToGeometryList(XElement item)
        {
            List<KmlGeometry> geos = new List<KmlGeometry>();
            foreach (XElement polygon in item.Elements("Polygon"))
            {
                geos.Add(KmlPolygonToGeometry(polygon));
            }
            return geos;
        }

        public static KmlGeometry KmlPolygonToGeometry(XElement item)
        {
            KmlGeometry geo = new KmlGeometry();
            Polygon outerPoly = KmlCoordinatesToPolygon(item.Element("outerBoundaryIs").Element("LinearRing").Element("coordinates"));
            outerPoly.Stroke = System.Windows.Media.Brushes.Blue;
            outerPoly.StrokeThickness = 3;
            outerPoly.Fill = System.Windows.Media.Brushes.Red;
            geo.OuterBoundry = outerPoly;

            // Parse innerBoundries
            foreach (XElement inner in item.Elements("innerBoundaryIs"))
            {
                Polygon iPoly = KmlCoordinatesToPolygon(inner.Element("LinearRing").Element("coordinates"));
                geo.InnerBoundries.Add(iPoly);
            }
            return geo;
        }

        public static Polygon KmlCoordinatesToPolygon(XElement item)
        {
            String tmp = ""; // item.ToString();
            Polygon p = new Polygon();


            //tmp = item.Value.Replace("\r\n", "\n");
            //string[] ps = System.Text.RegularExpressions.Regex.Split(tmp, "\n");
            tmp = item.Value.Trim().Replace("\r\n", " ").Replace("\n", " ").Replace("  ", " ");
            string[] ps = System.Text.RegularExpressions.Regex.Split(tmp, " ");
            for (int i = 0; i < ps.Length-1; i += 1)
            {
                if (String.IsNullOrEmpty(ps[i])) continue;
                string[] line = ps[i].Split(',');
                Double x = Convert.ToDouble(line[0]);
                Double y = Convert.ToDouble(line[1]);
                p.Points.Add(new System.Windows.Point { X = x, Y = y });
            }

            p.Stroke = System.Windows.Media.Brushes.Blue;
            p.StrokeThickness = 3;
            p.Fill = System.Windows.Media.Brushes.Red;
            return p;
        }

        //public static Polygon GeoRssPolygonToPolygon(XElement item)
        //{

        //    String tmp = item.ToString();
        //    item = XElement.Parse(tmp.Replace("georss:", ""));
        //    Polygon p = new Polygon();

        //    tmp = item.Element("polygon").Value;

        //    String[] ps = tmp.Split(' ');
        //    for (int i = 0; i < ps.Length - 1; i += 2)
        //    {
        //        Double x = Convert.ToDouble(ps[i + 1]);
        //        Double y = Convert.ToDouble(ps[i]);

        //        p.Points.Add(new System.Windows.Point { X = x, Y = y });
        //    }

        //    p.Stroke = System.Windows.Media.Brushes.Blue;
        //    p.StrokeThickness = 3;
        //    p.Fill = System.Windows.Media.Brushes.Red;
        //    return p;
        //}


        public static Boolean IsPointInPolygon(Point point, Polygon polygon)
        {
            Boolean isPointInPolygon = false;

            Double lng = point.X;
            Double lat = point.Y;

            int j = polygon.Points.Count - 1;

            for (int i = 0; i < polygon.Points.Count; i++)
            {
                /////////////////////////////////
                if (polygon.Points[i].X < lng && polygon.Points[j].X >= lng
                    || polygon.Points[j].X < lng && polygon.Points[i].X >= lng)
                {
                    if (polygon.Points[i].Y + (lng - polygon.Points[i].X) /
                      (polygon.Points[j].X - polygon.Points[i].X) * (polygon.Points[j].Y - polygon.Points[i].Y) < lat)
                    {
                        isPointInPolygon = !isPointInPolygon;
                       // break;
                    }
                }
                j = i; 
                /////////////////////////////////
            }
            return isPointInPolygon;
        }

    }
}
