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 Microsoft.Maps.MapControl;

namespace Route
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }

        //walther-rathenau-str. 18b, troisdorf, deutschland
        //holzweg 2, Köln, deutschland

        // This method accepts a geocode query string as well as a ‘waypoint index’, which will be used to track each asynchronous geocode request.
        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)myMap.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 Button_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(txtStart.Text, 0);
            Geocode(txtEnd.Text, 1);
        }

        // This method makes the initial CalculateRoute asynchronous request using the results of the Geocode Service.
        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 credentials.
            RouteService.RouteRequest routeRequest = new RouteService.RouteRequest();
            routeRequest.Credentials = new Credentials();
            routeRequest.Credentials.ApplicationId = ((ApplicationIdCredentialsProvider)myMap.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 = 5.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 Location(p.Latitude, p.Longitude));
                }

                // Add a map layer in which to draw the route.
                MapLayer myRouteLayer = new MapLayer();
                myMap.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 = new LocationRect(routeLine.Locations[0], routeLine.Locations[routeLine.Locations.Count - 1]);

                // 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(gr.Locations[0].Latitude, gr.Locations[0].Longitude);
                    MapLayer.SetPosition(point, location);
                    MapLayer.SetPositionOrigin(point, PositionOrigin.Center);

                    // Add the drawn point to the route layer.                    
                    myRouteLayer.Children.Add(point);
                }

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


