using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Shapes;
using System.Windows.Input;
using System.Windows.Media;
using GMapNET;
using System.Xml.Linq;

namespace System.Windows.Controls
{
    public class GMapKmlPolygon : GMapOverlay
    {
        public Brush Fill
        {
            get
            {
                return OverlayGeometry.Brush;
            }
            set
            {
                OverlayGeometry.Brush = value;
            }
        }
        public Brush Stroke
        {
            get
            {
                return OverlayGeometry.Pen.Brush;
            }
            set
            {
                OverlayGeometry.Pen.Brush = value;
            }
        }
        public Double StrokeThickness
        {
            get
            {
                return OverlayGeometry.Pen.Thickness;
            }
            set
            {
                OverlayGeometry.Pen.Thickness = value;
            }
        }

        public override FrameworkElement MarkerElement
        {
            get
            {
                return OverlayImage;
            }
        }

        public List<PointLatLng> OuterBoundry { get; set; }
        public List<Point> LocalOuterBoundry { get; set; }
        public List<List<PointLatLng>> InnerBoundries { get; set; }

        public XElement KMLPolygon { get; set; }
        public Image OverlayImage = new Image();
        private GeometryDrawing OverlayGeometry = new GeometryDrawing();
        private Rect GeometryRect;

        public GMapKmlPolygon(GMap Map, String kmlPolygon)
        {
            this.Map = Map;
            KMLPolygon = XElement.Parse(kmlPolygon);
            DoStartupTasks();
        }

        public GMapKmlPolygon(GMap Map, XElement kmlPolygon)
        {
            this.Map = Map;
            KMLPolygon = kmlPolygon;
            DoStartupTasks();
        }


        private void DoStartupTasks()
        {
            base.SetMarkerMouseEvents(); // don't do standard Overlay events
            OverlayImage.MouseEnter += new MouseEventHandler(el_MouseEnter);
            OverlayImage.MouseLeave += new MouseEventHandler(el_MouseLeave);
            //////////////el.MouseUp += new MouseButtonEventHandler(el_MouseUp);
            OverlayImage.Opacity = 0.2d;

            
            //BrushConverter conv = new BrushConverter();
            OverlayGeometry.Brush = Brushes.Yellow;//conv.ConvertFromString("#64FFEE00") as SolidColorBrush;
            OverlayGeometry.Pen = new Pen(Brushes.Black, 2);

            OverlayImage.SnapsToDevicePixels = true;
            OverlayImage.HorizontalAlignment = HorizontalAlignment.Left;
            OverlayImage.VerticalAlignment = VerticalAlignment.Top;

            LoadKml();

            SetShapeCenter();
        }

        private void LoadKml()
        {
            KmlGeometry geo = KmlHelper.KmlPolygonToGeometry(KMLPolygon);
            // the poly should now hold all the actual latlng of the kml data
            // Get that data into out into our lngLat outerboundry
            OuterBoundry = new List<PointLatLng>();
            InnerBoundries = new List<List<PointLatLng>>();

            LocalOuterBoundry = new List<Point>();
            foreach (Point p in geo.OuterBoundry.Points)
            {
                OuterBoundry.Add(new PointLatLng(p.Y, p.X));
            }

            foreach (Polygon innerPoly in geo.InnerBoundries)
            {
                List<PointLatLng> iPoints = new List<PointLatLng>();
                foreach (Point p in innerPoly.Points)
                {
                    iPoints.Add(new PointLatLng(p.Y, p.X));
                }
                InnerBoundries.Add(iPoints);
            }
        }

        /// <summary>
        /// Takes the PointLatLngs and changes them to local Polygon points
        /// </summary>
        /// <returns></returns>
        private void SetLocalPoints()
        {
            if (OuterBoundry == null) return;
            if (Map.IsDragging) return;

            // Test if anything is changed
            if (LocalOuterBoundry.Count > 0 && OuterBoundry.Count > 0)
            {
                GMapNET.Point test1 = Map.FromLatLngToLocal(OuterBoundry[0]);
                if (LocalOuterBoundry[0] == new Point(test1.X, test1.Y)) return;
            }

            LocalOuterBoundry.Clear();
            foreach (PointLatLng p in OuterBoundry)
            {
                GMapNET.Point p1 = Map.FromLatLngToLocal(p);
                Point pnt = new Point(p1.X, p1.Y);
                LocalOuterBoundry.Add(pnt);
            }

            StreamGeometry g = new StreamGeometry();
            using (StreamGeometryContext context = g.Open())
            {
                Point p1 = LocalOuterBoundry[0];
                context.BeginFigure(p1, true, true);

                for (int i = 1; i < LocalOuterBoundry.Count; i++)
                {
                    context.LineTo(LocalOuterBoundry[i], true, true);
                }
            }
            OverlayGeometry.Geometry = g;

            // remove any innerBoundries
            if (InnerBoundries.Count > 0)
            {
                Geometry geo1 = OverlayGeometry.Geometry;
                foreach (List<PointLatLng> innerBoundry in InnerBoundries)
                {
                    PathGeometry ipg = null;
                    ipg = new PathGeometry();
                    PathFigure pf = new PathFigure();
                    foreach (PointLatLng p in innerBoundry)
                    {
                        GMapNET.Point p1 = Map.FromLatLngToLocal(p);
                        Point pnt = new Point(p1.X, p1.Y);
                        pf.Segments.Add(new LineSegment(pnt,true));
                    }

                    ipg.Figures.Add(pf);

                    geo1 = new CombinedGeometry(GeometryCombineMode.Exclude,geo1,ipg);        
                }

                OverlayGeometry.Geometry = geo1;
            }


            DrawingImage di = new DrawingImage();
            di.Drawing = OverlayGeometry;
            OverlayImage.Source = di;

            GeometryRect = OverlayGeometry.Geometry.GetRenderBounds(OverlayGeometry.Pen);
            Position = Map.FromLocalToLatLng((int)(GeometryRect.Left + (GeometryRect.Width / 2)), (int)(GeometryRect.Top + (GeometryRect.Height / 2)));
        }


        public override void SetShapeCenter()
        {
            SetLocalPoints();
            Objects[MarkerElement] = new Point(-GeometryRect.Width / 2, -GeometryRect.Height / 2);
        }

        void el_MouseUp(object sender, MouseButtonEventArgs e)
        {
            if (e.ChangedButton == MouseButton.Middle)
            {
                base.UpdateLocalPosition(Map);
            }
        }

        void el_MouseLeave(object sender, MouseEventArgs e)
        {
            //el.Opacity = 1d;
        }

        void el_MouseEnter(object sender, MouseEventArgs e)
        {
            //el.Opacity = 0.6d;
        }


      
    }
}
