using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using SLAdvanced.LocalData.GeoDataService;
using Microsoft.Maps.MapControl;
using SLCommon.MapElements.Pushpins;
using SLCommon.Entities;
using SLAdvanced.Translators;
using SLCommon.TileLayers.Custom;

namespace SLAdvanced
{
    public partial class MainPage : UserControl
    {
        #region Private field

        GeoCityExpositionServiceClient client = new GeoCityExpositionServiceClient();
        List<ClientGeoCity> nearByCities = new List<ClientGeoCity>();

        MapTileLayer customTileLayer;

        #endregion

        #region Constructors

        public MainPage()
        {
            InitializeComponent();

            // Associate the controls load events
            this.map.Loaded += new RoutedEventHandler(map_Loaded);

            // Associate async WS client events
            this.client.GetAllNearbyCitiesCompleted += new EventHandler<GetAllNearbyCitiesCompletedEventArgs>(client_GetAllNearbyCitiesCompleted);
            this.client.GetCitiesBoundedCompleted += new EventHandler<GetCitiesBoundedCompletedEventArgs>(client_GetCitiesBoundedCompleted);
        }

        void client_GetCitiesBoundedCompleted(object sender, GetCitiesBoundedCompletedEventArgs e)
        {
            if (e.Result != null)
            {
                if (e.Result.Any())
                {
                    // Clear all previous point
                    layerPin.Children.Clear();

                    double maxPop = e.Result.Max(c => c.DemographicInformation);
                    double ratio = 30 / maxPop;
                    double ratioStroke = 2 / maxPop;
                    double ratioColor = 255 / maxPop;


                    this.nearByCities = e.Result.OrderByDescending(c => c.DemographicInformation)
                                                .Select(c => ClientGeoCityTranslator.ToClientEntity(c))
                                                .ToList();

                    bindCities(ratio, ratioStroke, ratioColor, false);
                }
            }
        }

        #endregion

        #region Async WS Client Events

        void client_GetAllNearbyCitiesCompleted(object sender, GetAllNearbyCitiesCompletedEventArgs e)
        {
            // Check if the result it received
            if (e.Result != null)
            {
                // Check if it contains at least one result
                if (e.Result.Any())
                {
                    // Clear all previous point
                    layerPin.Children.Clear();                    

                    double maxPop = e.Result.Max(c => c.DemographicInformation);
                    double ratio = 30 / maxPop;
                    double ratioStroke = 2 / maxPop;
                    double ratioColor = 255 / maxPop;


                    this.nearByCities = e.Result.OrderByDescending(c => c.DemographicInformation)
                                                .Select(c => ClientGeoCityTranslator.ToClientEntity(c))
                                                .ToList();

                    bindCities(ratio, ratioStroke, ratioColor, true);
                }
            }
        }

        #endregion

        #region Map Events

        void map_Loaded(object sender, RoutedEventArgs e)
        {
            // Associate the mouse events
            this.map.MouseClick += new EventHandler<Microsoft.Maps.MapControl.MapMouseEventArgs>(map_MouseClick);

            // Associate the map events
            //this.map.ViewChangeEnd += new EventHandler<Microsoft.Maps.MapControl.MapEventArgs>(map_ViewChangeEnd);
        }

        // Cluster server on view change
        void map_ViewChangeEnd(object sender, Microsoft.Maps.MapControl.MapEventArgs e)
        {
            if (isOk)
            {
                // Get the bouding rect of the current view
                LocationRect rect = this.map.BoundingRectangle;

                // Call WS
                this.client.GetCitiesBoundedAsync(rect.Northwest.Latitude, 
                                                  rect.Northwest.Longitude,
                                                  rect.Southeast.Latitude, 
                                                  rect.Southeast.Longitude);
            }
        }
        
        #endregion

        bool isOk = false;

        #region UI events

        // Proximity search on click
        void map_MouseClick(object sender, Microsoft.Maps.MapControl.MapMouseEventArgs e)
        {
            isOk = true;

            // Get clicked point corresponding coordinates
            Location clickedLocation = null;
            this.map.TryViewportPointToLocation(e.ViewportPoint, out clickedLocation);

            // Check if the clicked location is correct
            if (clickedLocation != null)
            {
                // Call the client - with a radius of 50km=50000 meters
                this.client.GetAllNearbyCitiesAsync(clickedLocation.Latitude,
                                                    clickedLocation.Longitude,
                                                    50000);
            }


            //if (this.map.Children.Contains(customTileLayer))
            //{
            //    this.map.Children.Remove(customTileLayer);
            //}

            //customTileLayer = new MapTileLayer();
            //this.map.Children.Add(customTileLayer);

            //// Add the Tile Source to the Tile Layer
            //customTileLayer.TileSources.Add(new CityTileLayer());
        }

        #endregion

        #region UI Private helper methods

        private void bindCities(double ratio, double ratioStroke, double ratioColor, bool setZoom)
        {
            List<Location> locs = new List<Location>();

            // Get every point and convert them then add to the map control
            foreach (var curClientCity in this.nearByCities)
            {
                // Create the temp pushpin
                ucScalablePushpin pinTemp = new ucScalablePushpin();
                pinTemp.Tag = curClientCity;
                Location curLoc = new Location()
                {
                    Latitude = curClientCity.Latitude,
                    Longitude = curClientCity.Longitude
                };

                // Adapt the presentation
                pinTemp.PinSize = (ratio * curClientCity.Population);
                pinTemp.PinStrokeThickness = (ratioStroke * curClientCity.Population);
                pinTemp.PinFillColor = new SolidColorBrush(
                    Color.FromArgb(
                        255,
                        255,
                        (byte)(255 - (curClientCity.Population * ratioColor)),
                        (byte)(255 - (curClientCity.Population * ratioColor))
                    )
                );
                pinTemp.PinStrokeColor = new SolidColorBrush(Colors.DarkGray);

                locs.Add(curLoc);

                // Add result to the layer on the map control
                //if (curCity.DemographicInformation != 0)
                layerPin.AddChild(pinTemp, curLoc);
            }

            // Set best map view
            if(setZoom)
                this.map.SetView(new LocationRect(locs));
        }

        #endregion
    }
}
