/// <summary> /// <para>Completes the response with schedule information, considering that the client informed the <see cref="Door2DoorCore.Types.Door2DoorRequest.D2dRequestTripDateKind"/> attributes as the departing dates.</para> /// <para>This method also takes into account any external flight option that might have been informed in the request.</para> /// </summary> /// <param name="route"> /// Route: <see cref="Door2DoorCore.Types.Door2DoorResponse.Route"/>. /// </param> /// <param name="departureDateTime"> /// Desired departure date. /// </param> /// <param name="flightChosen"> /// If an external flight was informed for this route. <see cref="Door2DoorCore.Types.Door2DoorRequest.OuterFlightOption"/> /// </param> /// <param name="legIndex"> /// Whether this is the inbound(0) or outbound(1) leg of the trip /// </param> private void BuildItineraryScheduleDepartingAt(ref Route route, DateTime departureDateTime, bool flightChosen, int legIndex) { if (route.Segments != null && route.Segments.Length > 0) { // resumo com totais de tempo e precos da rota atual route.RouteTotals = new RouteTotals(); decimal routePrice = 0; int weeklyFrequency = 0; TimeSpan frequency = new TimeSpan(0, 0, 0); DateTime departureDateCurrent = new DateTime(departureDateTime.Ticks); route.Segments[0].DepartureDateTime = departureDateCurrent; for (int i = 0; i < route.Segments.Length; i++) { Segment seg = route.Segments[i]; if (seg.Kind.ToLower().Equals("flight")) { bool achouVoo = false; ItineraryDates itineraryDates = new ItineraryDates(); seg.ChosenItinerary = null; //escolhido automaticamente if (flightChosen) // é uma alteração de itinerario, um voo foi alterado { if (_req.chosenRoute[legIndex].segmentIndex == i) { // a opcao de voo escolhida tem que bater com o horario do schedule if (_req.chosenRoute[legIndex].flightSegment.flightLegs[0].departureDate >= departureDateCurrent) { achouVoo = true; BuildINewtinFromChosenRoute(ref seg, legIndex); seg.DepartureDateTime = _req.chosenRoute[legIndex].flightSegment.flightLegs[0].departureDate; seg.ArrivalDateTime = _req.chosenRoute[legIndex].flightSegment.flightLegs[_req.chosenRoute[legIndex].flightSegment.flightLegs.Length - 1].arrivalDate; TimeSpan nextDepTime = new TimeSpan(departureDateCurrent.Hour, departureDateCurrent.Minute, 0); for (int j = 0; j < seg.Itineraries.Length - 1; j++) { int hour = int.Parse(seg.Itineraries[j].Legs[0].Hops[seg.Itineraries[j].Legs[0].Hops.Length - 1].STime.Substring(0, 2)); int min = int.Parse(seg.Itineraries[j].Legs[0].Hops[seg.Itineraries[j].Legs[0].Hops.Length - 1].STime.Substring(3, 2)); TimeSpan hopArrivalTime = new TimeSpan(hour, min, 0); route.Segments[i].Itineraries[j].ValidForSchedule = hopArrivalTime >= nextDepTime; } departureDateCurrent = seg.ArrivalDateTime.Value.AddMinutes(_minutesAfterFlight); } } } else { DateTime originalDepDate = departureDateCurrent.AddMinutes(_flightAntecipation);//duas horas de antecedencia no aeroporto -> melhorar DateTime lastDepDate = departureDateCurrent.AddMinutes(_flightAntecipation);//duas horas de antecedencia no aeroporto -> melhorar for (int j = 0; j < seg.Itineraries.Length; j++) { Itinerary itinerary = seg.Itineraries[j]; Leg leg = itinerary.Legs[0]; // hora de partida do primeiro voo da opcao atual string[] sTime = leg.Hops[0].STime.Split(':'); //hora de chegada do ultimo voo da opcao atual string[] tTime = leg.Hops[leg.Hops.Length - 1].TTime.Split(':'); DateTime tempDepDate = new DateTime(originalDepDate.Year, originalDepDate.Month, originalDepDate.Day, int.Parse(sTime[0]), int.Parse(sTime[1]), 0); itinerary.ValidForSchedule = tempDepDate >= originalDepDate; // valido para horario de chegada informado? if ((!achouVoo && tempDepDate >= originalDepDate) || (achouVoo && tempDepDate < lastDepDate && tempDepDate >= originalDepDate)) { achouVoo = true; // sei q pelo menos um voo é valido if (!seg.DepartureDateTime.HasValue || tempDepDate < seg.DepartureDateTime.Value) { lastDepDate = tempDepDate; seg.DepartureDateTime = tempDepDate; seg.ChosenItinerary = j; int dayChange = 0; for (int k = 0; k < leg.Hops.Length; k++) { if (leg.Hops[k].DayChange.HasValue) { dayChange += leg.Hops[k].DayChange.Value; } } DateTime tempArrDate = new DateTime(originalDepDate.Year, originalDepDate.Month, originalDepDate.Day, int.Parse(tTime[0]), int.Parse(tTime[1]), 0); //eu peguei um erro na api, //em raros casos ele coloca a data de chegada antes da de saida mas nao acrescenta valor ao dayChange :-s if (tempArrDate <= tempDepDate && dayChange == 0) { dayChange = 1; } tempArrDate = tempArrDate.AddDays(dayChange); seg.ArrivalDateTime = tempArrDate; departureDateCurrent = tempArrDate.AddMinutes(_minutesAfterFlight); // tempo para sair do aeroporto; } } } } if (!achouVoo) { DateTime originalDepDate = departureDateCurrent.AddMinutes(_flightAntecipation); if (originalDepDate.Day == departureDateCurrent.Day) { originalDepDate = new DateTime(departureDateCurrent.Year, departureDateCurrent.Month, departureDateCurrent.Day, 0, 0, 0); originalDepDate = originalDepDate.AddDays(1); //originalDepDate = departureDateCurrent.Date; } DateTime lastDepDate = originalDepDate.Date; for (int j = 0; j < seg.Itineraries.Length; j++) { Itinerary itinerary = seg.Itineraries[j]; Leg leg = itinerary.Legs[0]; itinerary.ValidForSchedule = true; // valido para horario de chegada informado? // hora de partida do primeiro voo da opcao atual string[] sTime = leg.Hops[0].STime.Split(':'); //hora de chegada do ultimo voo da opcao atual string[] tTime = leg.Hops[leg.Hops.Length - 1].TTime.Split(':'); DateTime tempDepDate = new DateTime(originalDepDate.Year, originalDepDate.Month, originalDepDate.Day, int.Parse(sTime[0]), int.Parse(sTime[1]), 0); if (j == 0 || tempDepDate < lastDepDate) { itinerary.ValidForSchedule = true; achouVoo = true; // sei q pelo menos um voo é valido lastDepDate = tempDepDate; seg.DepartureDateTime = tempDepDate; seg.ChosenItinerary = j; int dayChange = 0; for (int k = 0; k < leg.Hops.Length; k++) { if (leg.Hops[k].DayChange.HasValue) { dayChange += leg.Hops[k].DayChange.Value; } } DateTime tempArrDate = new DateTime(originalDepDate.Year, originalDepDate.Month, originalDepDate.Day, int.Parse(tTime[0]), int.Parse(tTime[1]), 0); //eu peguei um erro na api, //em raros casos ele coloca a data de chegada antes da de saida mas nao acrescenta valor ao dayChange :-s if (tempArrDate <= tempDepDate && dayChange == 0) { dayChange = 1; } tempArrDate = tempArrDate.AddDays(dayChange); seg.ArrivalDateTime = tempArrDate; departureDateCurrent = tempArrDate.AddMinutes(_minutesAfterFlight); // tempo para sair do aeroporto } } } // calcula o preco do segmento if (seg.IndicativePrice != null) { if (seg.Itineraries[seg.ChosenItinerary.Value].Legs[0].IndicativePrice != null) { routePrice += seg.Itineraries[seg.ChosenItinerary.Value].Legs[0].IndicativePrice.Price; } } } else { // A API tem um bug, as vezes manda caminhar, 50 minutos, as vezes mais de uma hora // Eles ficaram de resolver, mas até lá, eu desconstruí a conta de taxi e caminhada deles. // Se for caminhada e tiver mais que x minutos, eu transformo em Taxi ;) if (seg.Kind.ToLower().Equals("walk") && seg.Duration > _maxWalkingMinutes && route.Segments.Length > 1) { WalkIntoTaxiTransformation(ref seg); } //faz o calculo do preco if (seg.IndicativePrice != null) { routePrice += seg.IndicativePrice.Price; } //calcula frequencia semanal weeklyFrequency = GetWeeklyFrequency(seg); //calcula a frequencia total do segmento em horas e minutos frequency = CalcFrequency(weeklyFrequency); seg.Frequency = GetSegmentFrequency(seg); //duracao total em minutos, somando frequencia int duration = seg.Duration + frequency.Minutes + (frequency.Hours * 60); //pega data do prox ponto (i + 1) ou do ponto de chegada DateTime departureDate = departureDateCurrent; departureDateCurrent = departureDateCurrent.AddMinutes(duration); DateTime arrivalDate = departureDateCurrent; seg.DepartureDateTime = departureDate; seg.ArrivalDateTime = arrivalDate; } // calcula o resumo da rota atual CalcRouteTotals(ref route, i, true); } route.IndicativePrice.Price = routePrice; } }
/// <summary> /// Total times and costs fo the informed segment /// </summary> /// <param name="route"> /// <see cref="Door2DoorCore.Types.Door2DoorResponse.Route"/> /// </param> /// <param name="segmentIndex"> /// Which segment of the informed route. /// </param> /// <param name="departingAt"> /// Is this a <see cref="Door2DoorCore.Types.Door2DoorRequest.D2dRequestTripDateKind"/> indicating a departure date or not? /// </param> private void CalcRouteTotals(ref Route route, int segmentIndex, bool departingAt) { Segment segment = route.Segments[segmentIndex]; route.RouteTotals.TotalDistance += segment.Distance; if (departingAt) { if (segmentIndex > 0) // não for o primeiro segmento { if (route.Segments[segmentIndex - 1].ArrivalDateTime.HasValue && segment.DepartureDateTime.HasValue) { route.RouteTotals.TotalTimeWaiting = route.RouteTotals.TotalTimeWaiting.Add(segment.DepartureDateTime.Value - route.Segments[segmentIndex - 1].ArrivalDateTime.Value); } } } else { if (segmentIndex < route.Segments.Length - 1) // não for o ultimo segmento { if (route.Segments[segmentIndex + 1].DepartureDateTime.HasValue && segment.ArrivalDateTime.HasValue) { route.RouteTotals.TotalTimeWaiting = route.RouteTotals.TotalTimeWaiting.Add(route.Segments[segmentIndex + 1].DepartureDateTime.Value - segment.ArrivalDateTime.Value); } } } switch (segment.Kind.ToLower()) { case "flight": if (segment.ChosenItinerary.HasValue) { route.RouteTotals.TotalPriceOfFlight += segment.Itineraries[segment.ChosenItinerary.Value].Legs[0].IndicativePrice.Price; int totalDuration = segment.Itineraries[segment.ChosenItinerary.Value].Legs[0].Hops.Sum(e => e.Duration); route.RouteTotals.TotalTimeOnFlight = route.RouteTotals.TotalTimeOnFlight.Add(new TimeSpan(0, totalDuration, 0)); } break; case "bus": if (segment.IndicativePrice != null) { route.RouteTotals.TotalPriceOfBus += segment.IndicativePrice.Price; } route.RouteTotals.TotalTimeOnBus = route.RouteTotals.TotalTimeOnBus.Add(new TimeSpan(0, segment.Duration, 0)); break; case "walk": route.RouteTotals.TotalTimeOnWalk = route.RouteTotals.TotalTimeOnWalk.Add(new TimeSpan(0, segment.Duration, 0)); break; case "car": if (segment.IndicativePrice != null) { route.RouteTotals.TotalPriceOfCar += segment.IndicativePrice.Price; } route.RouteTotals.TotalTimeOnCar = route.RouteTotals.TotalTimeOnCar.Add(new TimeSpan(0, segment.Duration, 0)); break; case "train": if (segment.IndicativePrice != null) { route.RouteTotals.TotalPriceOfTrain += segment.IndicativePrice.Price; } route.RouteTotals.TotalTimeOnTrain = route.RouteTotals.TotalTimeOnTrain.Add(new TimeSpan(0, segment.Duration, 0)); break; default: break; } }
/// <summary> /// <para>Completes the response with schedule information, considering that the client informed the <see cref="Door2DoorCore.Types.Door2DoorRequest.D2dRequestTripDateKind"/> attributes as the arrival dates.</para> /// <para>This method also takes into account any external flight option that might have been informed in the request.</para> /// </summary> /// <param name="route"> /// Route: <see cref="Door2DoorCore.Types.Door2DoorResponse.Route"/> /// </param> /// <param name="arrivalDateTime"> /// Desired arrival date at destination /// </param> /// <param name="flightChosen"> /// If an external flight was informed for this route. <see cref="Door2DoorCore.Types.Door2DoorRequest.OuterFlightOption"/> /// </param> /// <param name="legIndex"> /// Whether this is the inbound(0) or outbound(1) leg of the trip /// </param> private void BuildItineraryScheduleArrivingAt(ref Route route, DateTime arrivalDateTime, bool flightChosen, int legIndex) { if (route.Segments != null && route.Segments.Length > 0) { // resumo com totais de tempo e precos da rota atual route.RouteTotals = new RouteTotals(); // diferenca entre a data da viagem e agora // irá ajudar no calculo do tempo para sair da origem int weeklyFrequency = 0; TimeSpan frequency = new TimeSpan(0, 0, 0); decimal routePrice = 0; //adiciona data de chegada ao destino final route.Segments[route.Segments.Length - 1].ArrivalDateTime = null; route.Segments[route.Segments.Length - 1].DepartureDateTime = null; for (int i = route.Segments.Length - 1; i >= 0; i--) { //pega data do prox ponto (i + 1) ou do ponto de chegada DateTime arrivalDateNextStop = new DateTime(); arrivalDateNextStop = i == route.Segments.Length - 1 ? arrivalDateTime : route.Segments[i + 1].DepartureDateTime.Value; //route.Segments[i].Subkind = _path; // Se for voo procura um voo que possibilite chegada no horário // no futuro devera pegar de uma fonte externa /*voo*/ if (route.Segments[i].Kind.ToLower().Equals("flight")) { bool achouVoo = false; ItineraryDates itineraryDates = new ItineraryDates(); route.Segments[i].ChosenItinerary = null; //escolhido automaticamente if (flightChosen) // é uma alteração de itinerario, um voo foi alterado { if (_req.chosenRoute[legIndex].segmentIndex == i) { // a opcao de voo escolhida tem que bater com o horario do schedule if (_req.chosenRoute[legIndex].flightSegment.flightLegs[_req.chosenRoute[legIndex].flightSegment.flightLegs.Length - 1].arrivalDate <= arrivalDateNextStop) { achouVoo = true; BuildINewtinFromChosenRoute(ref route.Segments[i], legIndex); itineraryDates.departureDateTime = _req.chosenRoute[legIndex].flightSegment.flightLegs[0].departureDate; itineraryDates.arrivalDateTime = _req.chosenRoute[legIndex].flightSegment.flightLegs[_req.chosenRoute[legIndex].flightSegment.flightLegs.Length - 1].arrivalDate; TimeSpan nextArrivalTime = new TimeSpan(arrivalDateNextStop.Hour, arrivalDateNextStop.Minute, 0); for (int j = 0; j < route.Segments[i].Itineraries.Length - 1; j++) { int hour = int.Parse(route.Segments[i].Itineraries[j].Legs[0].Hops[route.Segments[i].Itineraries[j].Legs[0].Hops.Length - 1].TTime.Substring(0, 2)); int min = int.Parse(route.Segments[i].Itineraries[j].Legs[0].Hops[route.Segments[i].Itineraries[j].Legs[0].Hops.Length - 1].TTime.Substring(3, 2)); TimeSpan hopArrivalTime = new TimeSpan(hour, min, 0); route.Segments[i].Itineraries[j].ValidForSchedule = hopArrivalTime <= nextArrivalTime; } } } } else { // para cada opcao de voo for (int j = 0; j < route.Segments[i].Itineraries.Length; j++) { route.Segments[i].Itineraries[j].ValidForSchedule = false; // valido para horario de chegada informado? Leg itinerary = route.Segments[i].Itineraries[j].Legs[0]; //verifica se itinerario atual bate com o horario do proximo segmento ItineraryDates currentItineraryDates = MatchflightToSchedule(itinerary, arrivalDateNextStop); // pode ter ou nao voo chegando no dia para chegar no horario if (currentItineraryDates.arrivalDateTime != null) { achouVoo = true; route.Segments[i].Itineraries[j].ValidForSchedule = true;// valido para horario de chegada informado? if (itineraryDates.arrivalDateTime == null) { itineraryDates = currentItineraryDates; route.Segments[i].ChosenItinerary = j;//indice do itinerario escolhido automatico } else { if (currentItineraryDates.arrivalDateTime > itineraryDates.arrivalDateTime) { itineraryDates = currentItineraryDates; route.Segments[i].ChosenItinerary = j; //indice do itinerario escolhido automatico } } } } if (!achouVoo)// Nao tinha nenhum voo que chegaria no horario naquele dia, pegar o voo com maior horario de chegada e determinar que é no dia anterior { // acha o itinerario que tem a hora de chegada maior Leg latestItinerary = FindLatestItinerary(ref route.Segments[i]); itineraryDates = CalcItineraryArrivalDates(latestItinerary, arrivalDateNextStop); } } // seta segmento com datas de chegada e partida route.Segments[i].DepartureDateTime = itineraryDates.departureDateTime; route.Segments[i].ArrivalDateTime = itineraryDates.arrivalDateTime; // calcula o preco do segmento if (route.Segments[i].IndicativePrice != null) { if (route.Segments[i].Itineraries[route.Segments[i].ChosenItinerary.Value].Legs[0].IndicativePrice != null) { routePrice += route.Segments[i].Itineraries[route.Segments[i].ChosenItinerary.Value].Legs[0].IndicativePrice.Price; } } } /*nao voo*/ else { // A API tem um bug, as vezes manda caminhar, 50 minutos, as vezes mais de uma hora. // Eles ficaram de resolver, mas até lá, eu desconstruí a conta de taxi e caminhada deles. // Se for caminhada e tiver mais que x minutos, eu transformo em Taxi ;) if (route.Segments[i].Kind.ToLower().Equals("walk") && route.Segments[i].Duration > _maxWalkingMinutes && route.Segments.Length > 1) { WalkIntoTaxiTransformation(ref route.Segments[i]); } //faz o calculo do preco if (route.Segments[i].IndicativePrice != null) { routePrice += route.Segments[i].IndicativePrice.Price; } //calcula frequencia semanal weeklyFrequency = GetWeeklyFrequency(route.Segments[i]); //calcula a frequencia total do segmento em horas e minutos frequency = CalcFrequency(weeklyFrequency); route.Segments[i].Frequency = GetSegmentFrequency(route.Segments[i]); //duracao total em minutos, somando frequencia int duration = route.Segments[i].Duration + frequency.Minutes + (frequency.Hours * 60); int anticipation = 0; // em minutos // se o proximo segmento é voo, calcular chegada com antecipacao if (i < route.Segments.Length - 1 && route.Segments[i + 1].Kind.ToLower().Equals("flight")) { anticipation = _flightAntecipation; } //pega data do prox ponto (i + 1) ou do ponto de chegada DateTime departureDate = arrivalDateNextStop.AddMinutes(-duration); DateTime arrivalDate = departureDate.AddMinutes(duration); departureDate = departureDate.AddMinutes(-anticipation); arrivalDate = arrivalDate.AddMinutes(-anticipation); route.Segments[i].DepartureDateTime = departureDate; route.Segments[i].ArrivalDateTime = arrivalDate; } // calcula o resumo da rota atual CalcRouteTotals(ref route, i, false); } route.IndicativePrice.Price = routePrice; } }