public HtmlInstructionsViewModel(TKRoute route)
 {
     this.Instructions = new HtmlWebViewSource();
     this.Instructions.Html = @"<html><body>";
     foreach (var s in route.Steps)
     {
         this.Instructions.Html += string.Format("<b>{0}km:</b> {1}<br /><hr />", s.Distance / 1000, s.Instructions);
     }
     this.Instructions.Html += @"</body></html>";
 }
        /// <summary>
        /// Sets the route calculation data
        /// </summary>
        /// <param name="route">The PCL route</param>
        /// <param name="routeResult">The rourte api result</param>
        private void SetRouteData(TKRoute route, GmsRouteResult routeResult)
        {
            var latLngBounds = new LatLngBounds(
                    new LatLng(routeResult.Bounds.SouthWest.Latitude, routeResult.Bounds.SouthWest.Longitude),
                    new LatLng(routeResult.Bounds.NorthEast.Latitude, routeResult.Bounds.NorthEast.Longitude));

            var apiSteps = routeResult.Legs.First().Steps;
            var steps = new TKRouteStep[apiSteps.Count()];
            var routeFunctions = (IRouteFunctions)route;

            
            for (int i = 0; i < steps.Length; i++)
            {
                steps[i] = new TKRouteStep();
                var stepFunctions = (IRouteStepFunctions)steps[i];
                var apiStep = apiSteps.ElementAt(i);

                stepFunctions.SetDistance(apiStep.Distance.Value);
                stepFunctions.SetInstructions(apiStep.HtmlInstructions);
            }
            routeFunctions.SetSteps(steps);
            routeFunctions.SetDistance(routeResult.Legs.First().Distance.Value);
            routeFunctions.SetTravelTime(routeResult.Legs.First().Duration.Value);
            routeFunctions.SetBounds(
                MapSpan.FromCenterAndRadius(
                    latLngBounds.Center.ToPosition(),
                    Distance.FromKilometers(
                        new Position(latLngBounds.Southwest.Latitude, latLngBounds.Southwest.Longitude)
                        .DistanceTo(
                            new Position(latLngBounds.Northeast.Latitude, latLngBounds.Northeast.Longitude)))));

        }
        /// <summary>
        /// Calculates and adds the route to the map
        /// </summary>
        /// <param name="route">The route to add</param>
        private async void AddRoute(TKRoute route)
        {
            route.PropertyChanged += OnRoutePropertyChanged;

            GmsDirectionResult routeData = null;
            try
            {
                routeData = await GmsDirection.Instance.CalculateRoute(route.Source, route.Destination, route.TravelMode.ToGmsTravelMode());
                
                if (routeData == null || routeData.Routes == null) return;

                var r = routeData.Routes.FirstOrDefault();
                if (r == null || r.Polyline.Positions == null || !r.Polyline.Positions.Any()) return;

                this.SetRouteData(route, r);

                var routeOptions = new PolylineOptions();

                if (route.Color != Color.Default)
                {
                    routeOptions.InvokeColor(route.Color.ToAndroid().ToArgb());
                }
                if (route.LineWidth > 0)
                {
                    routeOptions.InvokeWidth(route.LineWidth);
                }
                routeOptions.Add(r.Polyline.Positions.Select(i => i.ToLatLng()).ToArray());

                this._routes.Add(route, this._googleMap.AddPolyline(routeOptions));

                if (this.FormsMap.RouteCalculationFinishedCommand != null && this.FormsMap.RouteCalculationFinishedCommand.CanExecute(route))
                {
                    this.FormsMap.RouteCalculationFinishedCommand.Execute(route);
                }
            }
            finally
            {
                if ((routeData == null || routeData.Status != GmsDirectionResultStatus.Ok) && this.FormsMap.RouteCalculationFailedCommand != null)
                {
                    if (this.FormsMap.RouteCalculationFailedCommand.CanExecute(route))
                    {
                        this.FormsMap.RouteCalculationFailedCommand.Execute(route);
                    }
                }
            }
        }
        /// <summary>
        /// Sets the route data
        /// </summary>
        /// <param name="route">PCL route</param>
        /// <param name="nativeRoute">Native route</param>
        private void SetRouteData(TKRoute route, MKRoute nativeRoute)
        {
            var routeFunctions = (IRouteFunctions)route;
            var steps = new TKRouteStep[nativeRoute.Steps.Count()];

            for (int i = 0; i < steps.Length; i++)
            {
                steps[i] = new TKRouteStep();
                var stepFunction = (IRouteStepFunctions)steps[i];
                var nativeStep = nativeRoute.Steps.ElementAt(i);

                stepFunction.SetInstructions(nativeStep.Instructions);
                stepFunction.SetDistance(nativeStep.Distance);
            }

            routeFunctions.SetSteps(steps);
            routeFunctions.SetDistance(nativeRoute.Distance);
            routeFunctions.SetTravelTime(nativeRoute.ExpectedTravelTime);
            routeFunctions.SetBounds(
                MapSpan.FromCenterAndRadius(
                    new Position(
                        nativeRoute.Polyline.BoundingMapRect.MidX,
                        nativeRoute.Polyline.BoundingMapRect.MidY),
                    Distance.FromKilometers(
                        route.Source.DistanceTo(route.Destination))));
        }
        /// <summary>
        /// Adds a route to the map
        /// </summary>
        /// <param name="route">The route to add</param>
        private void AddRoute(TKRoute route)
        {
            MKDirectionsRequest req = new MKDirectionsRequest();
            req.Source = new MKMapItem(new MKPlacemark(route.Source.ToLocationCoordinate(), new MKPlacemarkAddress()));
            req.Destination = new MKMapItem(new MKPlacemark(route.Destination.ToLocationCoordinate(), new MKPlacemarkAddress()));
            req.TransportType = route.TravelMode.ToTransportType();

            MKDirections directions = new MKDirections(req);
            directions.CalculateDirections(new MKDirectionsHandler((r, e) => 
            {
                if (r != null && r.Routes != null && r.Routes.Any())
                {
                    var nativeRoute = r.Routes.First();

                    this.SetRouteData(route, nativeRoute);

                    this._routes.Add(nativeRoute.Polyline, new TKOverlayItem<TKRoute, MKPolylineRenderer>(route));
                    this.Map.AddOverlay(nativeRoute.Polyline);

                    route.PropertyChanged += OnRoutePropertyChanged;

                    if (this.FormsMap.RouteCalculationFinishedCommand != null && this.FormsMap.RouteCalculationFinishedCommand.CanExecute(route))
                    {
                        this.FormsMap.RouteCalculationFinishedCommand.Execute(route);
                    }
                }
                else
                {
                    if (this.FormsMap.RouteCalculationFailedCommand != null && this.FormsMap.RouteCalculationFailedCommand.CanExecute(route))
                    {
                        this.FormsMap.RouteCalculationFailedCommand.Execute(route);
                    }
                }
            }));
        }
        public HtmlInstructionsPage(TKRoute route)
        {
            InitializeComponent();

            this.BindingContext = new HtmlInstructionsViewModel(route);
        }