using System;
using System.Device.Location;
using System.Threading;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Controls.Maps;
using Microsoft.Phone.Controls.Maps.Platform;

namespace BingMaps
{
    public partial class MainPage : PhoneApplicationPage
    {
        // Constructor
        public MainPage()
        {
            InitializeComponent();
            Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("de-DE");
            Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("de-DE");
        }

        private void btnZoomIn_Click(object sender, RoutedEventArgs e)
        {
            bingMap.ZoomLevel++;
        }

        private void btnZoomOut_Click(object sender, RoutedEventArgs e)
        {
            bingMap.ZoomLevel--;
        }


        private void btnAerial_Click(object sender, EventArgs e)
        {
            bingMap.Mode = new AerialMode();
        }

        private void btnAerialLbl_Click(object sender, EventArgs e)
        {
            bingMap.Mode = new AerialMode(true);
        }

        private void btnRoad_Click(object sender, EventArgs e)
        {
            bingMap.Mode = new RoadMode();
        }

        private void btnZoomBar_Click(object sender, EventArgs e)
        {
            if (bingMap.ZoomBarVisibility == System.Windows.Visibility.Collapsed)
            {
                bingMap.ZoomBarVisibility = System.Windows.Visibility.Visible;
            }
            else
            {
                bingMap.ZoomBarVisibility = System.Windows.Visibility.Collapsed;
            }
        }

        private void btnScale_Click(object sender, EventArgs e)
        {
            if (bingMap.ScaleVisibility == System.Windows.Visibility.Collapsed)
            {
                bingMap.ScaleVisibility = System.Windows.Visibility.Visible;
            }
            else
            {
                bingMap.ScaleVisibility = System.Windows.Visibility.Collapsed;
            }
        }

        private void btnLogo_Click(object sender, EventArgs e)
        {
            if (bingMap.LogoVisibility == System.Windows.Visibility.Collapsed)
            {
                bingMap.LogoVisibility = System.Windows.Visibility.Visible;
            }
            else
            {
                bingMap.LogoVisibility = System.Windows.Visibility.Collapsed;
            }
        }

        private void btnJump_Click(object sender, EventArgs e)
        {
            bingMap.Center = new System.Device.Location.GeoCoordinate(51.46177, 7.01372); //Cafe Nord Essen
            bingMap.ZoomLevel = 19;
        }             


        
        /// <summary>
        /// MapLayer zum Erstellen eigener Pushpins
        /// </summary>
        private MapLayer PushpinLayer = new MapLayer();

        private void btnPushPin_Click(object sender, EventArgs e)
        {
            if (!bingMap.Children.Contains(PushpinLayer))
            {
                bingMap.Children.Add(PushpinLayer);
                Pushpin pin = new Pushpin();
                pin.Location = new System.Device.Location.GeoCoordinate(51.46177, 7.01372);
                pin.Content = "Cafe Nord Essen";
                pin.MouseLeftButtonDown += Pushpin_MouseLeftButtonDown;

                PushpinLayer.Children.Add(pin);
            }
        }

        private void btnRemovePushPin_Click(object sender, EventArgs e)
        {
            if (bingMap.Children.Contains(PushpinLayer))
            {
                bingMap.Children.Remove(PushpinLayer);
            }
        }
        private void Pushpin_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            bingMap.Center = (sender as Pushpin).Location;
            bingMap.ZoomLevel = 15;
        }

        private void btnCalculateRoute_Click(object sender, RoutedEventArgs e)
        {
            // Initialize the length of the results array. In this sample we have two waypoints.
            geocodeResults = new GeocodeService.GeocodeResult[2];

            // Make the two Geocode requests using the values of the text boxes. Also pass the waypoint indexes 
            //   of these two values within the route.
            Geocode("Mülheim", 0);
            Geocode("Essen", 1);
        }


        private void Geocode(string strAddress, int waypointIndex)
        {
            // Create the service variable and set the callback method using the GeocodeCompleted property.
            GeocodeService.GeocodeServiceClient geocodeService = new GeocodeService.GeocodeServiceClient("BasicHttpBinding_IGeocodeService");
            geocodeService.GeocodeCompleted += new EventHandler<GeocodeService.GeocodeCompletedEventArgs>(geocodeService_GeocodeCompleted);

            // Set the credentials and the geocode query, which could be an address or location.
            GeocodeService.GeocodeRequest geocodeRequest = new GeocodeService.GeocodeRequest();
            geocodeRequest.Credentials = new Credentials();
            geocodeRequest.Credentials.ApplicationId = ((ApplicationIdCredentialsProvider)bingMap.CredentialsProvider).ApplicationId;
            geocodeRequest.Query = strAddress;

            // Make the asynchronous Geocode request, using the ‘waypoint index’ as 
            //   the user state to track this request and allow it to be identified when the response is returned.
            geocodeService.GeocodeAsync(geocodeRequest, waypointIndex);
        }
        // This is the global internal variable where results are stored. These are accessed later to calculate the route.
        internal GeocodeService.GeocodeResult[] geocodeResults;

        // This is the Geocode request callback method.
        private void geocodeService_GeocodeCompleted(object sender, GeocodeService.GeocodeCompletedEventArgs e)
        {
            // Retrieve the user state of this response (the ‘waypoint index’) to identify which geocode request 
            //   it corresponds to.
            int waypointIndex = System.Convert.ToInt32(e.UserState);

            // Retrieve the GeocodeResult for this response and store it in the global variable geocodeResults, using
            //   the waypoint index to position it in the array.
            geocodeResults[waypointIndex] = e.Result.Results[0];

            // Look at each element in the global gecodeResults array to figure out if more geocode responses still 
            //   need to be returned.

            bool doneGeocoding = true;

            foreach (GeocodeService.GeocodeResult gr in geocodeResults)
            {
                if (gr == null)
                {
                    doneGeocoding = false;
                }
            }

            // If the geocodeResults array is totally filled, then calculate the route.
            if (doneGeocoding)
                CalculateRoute(geocodeResults);

        }
        private void CalculateRoute(GeocodeService.GeocodeResult[] results)
        {
            // Create the service variable and set the callback method using the CalculateRouteCompleted property.
            RouteService.RouteServiceClient routeService = new RouteService.RouteServiceClient("BasicHttpBinding_IRouteService");
            routeService.CalculateRouteCompleted += new EventHandler<RouteService.CalculateRouteCompletedEventArgs>(routeService_CalculateRouteCompleted);

            // Set the token.
            RouteService.RouteRequest routeRequest = new RouteService.RouteRequest();
            routeRequest.Credentials = new Credentials();
            routeRequest.Credentials.ApplicationId = ((ApplicationIdCredentialsProvider)bingMap.CredentialsProvider).ApplicationId;

            // Return the route points so the route can be drawn.
            routeRequest.Options = new RouteService.RouteOptions();
            routeRequest.Options.RoutePathType = RouteService.RoutePathType.Points;

            // Set the waypoints of the route to be calculated using the Geocode Service results stored in the geocodeResults variable.
            routeRequest.Waypoints = new System.Collections.ObjectModel.ObservableCollection<RouteService.Waypoint>();
            foreach (GeocodeService.GeocodeResult result in results)
            {
                routeRequest.Waypoints.Add(GeocodeResultToWaypoint(result));
            }

            // Make the CalculateRoute asnychronous request.
            routeService.CalculateRouteAsync(routeRequest);
        }

        private RouteService.Waypoint GeocodeResultToWaypoint(GeocodeService.GeocodeResult result)
        {
            RouteService.Waypoint waypoint = new RouteService.Waypoint();
            waypoint.Description = result.DisplayName;
            waypoint.Location = new Location();
            waypoint.Location.Latitude = result.Locations[0].Latitude;
            waypoint.Location.Longitude = result.Locations[0].Longitude;
            return waypoint;
        }
        // This is the callback method for the CalculateRoute request.
        private void routeService_CalculateRouteCompleted(object sender, RouteService.CalculateRouteCompletedEventArgs e)
        {

            // If the route calculate was a success and contains a route, then draw the route on the map.
            if ((e.Result.ResponseSummary.StatusCode == RouteService.ResponseStatusCode.Success) & (e.Result.Result.Legs.Count != 0))
            {
                // Set properties of the route line you want to draw.
                Color routeColor = Colors.Blue;
                SolidColorBrush routeBrush = new SolidColorBrush(routeColor);
                MapPolyline routeLine = new MapPolyline();
                routeLine.Locations = new LocationCollection();
                routeLine.Stroke = routeBrush;
                routeLine.Opacity = 0.65;
                routeLine.StrokeThickness = 10.0;

                // Retrieve the route points that define the shape of the route.
                foreach (Location p in e.Result.Result.RoutePath.Points)
                {
                    routeLine.Locations.Add(new GeoCoordinate(p.Latitude, p.Longitude));
                }

                // Add a map layer in which to draw the route.
                MapLayer myRouteLayer = new MapLayer();
                bingMap.Children.Add(myRouteLayer);

                // Add the route line to the new layer.
                myRouteLayer.Children.Add(routeLine);

                // Figure the rectangle which encompasses the route. This is used later to set the map view.
                LocationRect rect = LocationRect.CreateLocationRect(routeLine.Locations);
                
                // For each geocode result (which are the waypoints of the route), draw a dot on the map.
                foreach (GeocodeService.GeocodeResult gr in geocodeResults)
                {
                    Ellipse point = new Ellipse();
                    point.Width = 10;
                    point.Height = 10;
                    point.Fill = new SolidColorBrush(Colors.Red);
                    point.Opacity = 0.65;
                    Location location = new Location();
                    location.Latitude = gr.Locations[0].Latitude;
                    location.Longitude = gr.Locations[0].Longitude;
                    // Add the drawn point to the route layer.                    
                    myRouteLayer.Children.Add(point);
                }

                // Set the map view using the rectangle which bounds the rendered route.
                bingMap.SetView(rect);
            }
        }
    }
}