/// <summary> /// The get flight price. /// </summary> /// <param name="flight"> /// The flight. /// </param> /// <param name="targetCurrency"> /// The target currency. /// </param> /// <returns> /// The <see cref="string"/>. /// </returns> internal string GetFlightPrice(Flight flight, string targetCurrency) { double price = flight.Price; string flightCurrency = flight.JourneyData.Currency; string currencyCode = flightCurrency; var currencyProvider = AppContext.MonitorEnvironment.CurrencyProvider; if (currencyProvider != null) { if (string.IsNullOrEmpty(targetCurrency) || string.Equals(flightCurrency, targetCurrency, StringComparison.OrdinalIgnoreCase)) { price = flight.Price; } else { if (currencyProvider.Convert(flight.Price, flightCurrency, targetCurrency, out price)) { flightCurrency = targetCurrency; } } currencyCode = currencyProvider.GetCurrencyInfo(flightCurrency).Symbol; } string result = price.ToString("#,0.0 ") + currencyCode; return result; }
/// <summary> /// The get list view item. /// </summary> /// <param name="flight"> /// The flight. /// </param> /// <param name="targetCurrency"> /// The target currency. /// </param> /// <returns> /// The <see cref="ListViewItem"/>. /// </returns> internal ListViewItem GetListViewItem(Flight flight, string targetCurrency) { List<string> data = this.GetPresentationStrings(flight, targetCurrency); var item = new ListViewItem { UseItemStyleForSubItems = false, Tag = flight, Text = data[0] }; var subItems = new ListViewItem.ListViewSubItem[data.Count - 1]; for (int i = 1; i < data.Count; i++) { var sub = new ListViewItem.ListViewSubItem(item, data[i]); subItems[i - 1] = sub; if (i == 5) { sub.Font = new Font(sub.Font, FontStyle.Bold); } } item.SubItems.AddRange(subItems); return item; }
/// <summary> /// Check if the flight detail is the same as the other flight (ignore the price and travel agency) /// </summary> /// <param name="otherFLight"> /// The other F Light. /// </param> /// <returns> /// The <see cref="bool"/>. /// </returns> public bool IsSameFlight(Flight otherFLight) { bool result = string.Equals(this.Operator, otherFLight.Operator, StringComparison.OrdinalIgnoreCase); // Operator if (result) { if (result = this.OutboundLeg != null && otherFLight.OutboundLeg != null) { // Outbound leg if (result = this.OutboundLeg.IsSame(otherFLight.OutboundLeg)) { if (result = this.InboundLeg != null && otherFLight.InboundLeg != null) { // Inbound leg result = this.InboundLeg.IsSame(otherFLight.InboundLeg); } else { result = this.InboundLeg == null && otherFLight.InboundLeg == null; } } } else { result = this.OutboundLeg == null && otherFLight.OutboundLeg == null; } } return result; }
/// <summary> /// The filter flight. /// </summary> /// <param name="flight"> /// The flight. /// </param> /// <param name="filter"> /// The filter. /// </param> /// <returns> /// The <see cref="bool"/>. /// </returns> private bool FilterFlight(Flight flight, ListViewFilter filter) { var data = this._lvFlightItemAdaptor.GetPresentationStrings(flight, this.ActiveCurrency); if (!data[filter.Column].IsMatch(filter.FilterString)) { return false; } return true; }
/// <summary> /// The can buy. /// </summary> /// <param name="flight"> /// The flight. /// </param> /// <returns> /// The <see cref="bool"/>. /// </returns> private bool CanBuy(Flight flight) { var result = flight != null && flight.TravelAgency != null && !string.IsNullOrEmpty(flight.TravelAgency.Url) && !(flight.OutboundLeg != null && flight.OutboundLeg.Departure.Date <= DateTime.Now.Date); return result; }
/// <summary> /// Add flight to the journey's fare data /// </summary> /// <param name="flight"> /// The flight. /// </param> public void AddFlight(Flight flight) { if (flight != null) { this.Flights.Add(flight); flight.JourneyData = this; } }
/// <summary> /// The parse web archive. /// </summary> /// <param name="webDocument"> /// The web document. /// </param> /// <returns> /// The <see cref="RouteDataResult"/>. /// </returns> internal RouteDataResult ParseWebArchive(HtmlDocument webDocument) { HtmlNode originInput = webDocument.GetElementbyId("flight_places"); if (originInput == null) { // Data is not ready yet return new RouteDataResult(DataResult.NotReady, null); } var resultDivs = webDocument.DocumentNode.SelectNodes("//div[@id='results_list']//div[@class='flights_a']"); if (resultDivs == null || resultDivs.Count < 1) { // Data is not ready yet return new RouteDataResult(DataResult.NotReady, null); } var route = new TravelRoute(0, this.Departure, this.Destination); foreach (var resultSection in resultDivs) { // Each result set DateTime dataDate = DateTime.Now; var operatorData = new Dictionary<string, List<Flight>>(); var newData = new JourneyData(0, "EUR", dataDate); FlightLeg outboundLeg = null, inboundLeg = null; string flightOperator = null; TravelAgency travelAgency = null; double price = 0.0; List<Fare> fares = new List<Fare>(); var priceContainers = resultSection.SelectNodes(".//div[@class='f_price_container']//div[@class='row']"); if (priceContainers == null || priceContainers.Count < 1) { continue; } foreach (var priceContainer in priceContainers) { string onClickStr = priceContainer.GetAttributeValue("onclick", string.Empty); travelAgency = this.TryGetTravelAgency(onClickStr, false); var priceNode = priceContainer.SelectSingleNode(".//div[@class='f_price']"); if (priceNode == null) { continue; } string priceStr = Regex.Match(priceNode.InnerText.Replace(",", "."), @"\d+(.\d+)?").Value; double.TryParse(priceStr, NumberStyles.Any, NamingRule.NumberCulture, out price); fares.Add(new Fare { TravelAgency = travelAgency, Price = price }); } // Loop through each column in table var flightNode = resultSection.SelectSingleNode(".//div[@class='f_normal_info']"); if (flightNode == null) { continue; } foreach (HtmlNode flightDetailNode in flightNode.ChildNodes) { // Fetch the flight detail from the row if (flightDetailNode.Name != "div") { continue; } string className = flightDetailNode.GetAttributeValue("class", string.Empty); switch (className) { case "f_outbound": case "f_outbound_only": case "f_return": var divNodes = flightDetailNode.Descendants("div"); if (divNodes != null) { string depDatePartStr = null, depTimePartStr = null, stopStr = null, arrDatePartStr = null, arrTimePartStr = null; TimeSpan duration = TimeSpan.Zero; foreach (var dataNode in divNodes) { // Each flight string dataClass = dataNode.GetAttributeValue("class", string.Empty); switch (dataClass) { case "f_dep_date": depDatePartStr = dataNode.InnerText; break; case "f_departure": depTimePartStr = dataNode.InnerText; break; case "f_arr_date": arrDatePartStr = dataNode.InnerText; break; case "f_arrival": arrTimePartStr = dataNode.InnerText; break; case "f_duration": duration = this.TryGetDuration(dataNode.InnerText); break; case "f_stops": stopStr = TryGetNumberString(dataNode.InnerText); break; } } // Validate that we got all required data string depDateStr = string.Format(CultureInfo.InvariantCulture, "{0} {1}", depDatePartStr, depTimePartStr), arrDateStr = string.Format(CultureInfo.InvariantCulture, "{0} {1}", arrDatePartStr, arrTimePartStr); DateTime deptDate, arrDate; if (DateTime.TryParseExact( depDateStr, "dd.MM.yy HH:mm", CultureInfo.InvariantCulture, DateTimeStyles.None, out deptDate) && deptDate.IsDefined() && DateTime.TryParseExact( arrDateStr, "dd.MM.yy HH:mm", CultureInfo.InvariantCulture, DateTimeStyles.None, out arrDate) && arrDate.IsDefined()) { if (duration > TimeSpan.Zero) { int transit; int.TryParse(stopStr, out transit); // This might fail for straight flight: Just ignore it var flightLeg = new FlightLeg(deptDate, arrDate, duration, transit); if (className == "f_return") { inboundLeg = flightLeg; } else { outboundLeg = flightLeg; } } } } break; case "f_company": flightOperator = flightDetailNode.InnerText.Replace("mm. ", string.Empty); break; } } if (outboundLeg != null) { bool shouldAdd; if (shouldAdd = !operatorData.ContainsKey(flightOperator)) { // Flight will always be added if it is the first from this operator if (operatorData.Keys.Count == this.MaxAirlines) { // If we reached the limit for number of flight operators continue; } operatorData.Add(flightOperator, new List<Flight>(this.MaxFlightsPerAirline)); } var opearatorFlights = operatorData[flightOperator]; if (!shouldAdd) { // This is not the first fly from this operator TimeSpan totalDuration = (outboundLeg == null ? TimeSpan.Zero : outboundLeg.Duration) + (inboundLeg == null ? TimeSpan.Zero : inboundLeg.Duration); var lastFlight = opearatorFlights[opearatorFlights.Count - 1]; if ((price - lastFlight.Price) > this.MinPriceMargin) { // If the price differs enough, add new flight if we still have space if (opearatorFlights.Count < this.MaxFlightsPerAirline) { shouldAdd = true; } } else { // The new price does not differ enough from last flight: Add or replace existing flight if the duration is shorter for (int i = opearatorFlights.Count - 1; i >= 0; i--) { var f = opearatorFlights[i]; if ((price - f.Price) <= this.MinPriceMargin && totalDuration < f.Duration) { opearatorFlights.RemoveAt(i); shouldAdd = true; break; } } } } if (shouldAdd && fares.Count > 0) { var newFlight = new Flight(newData, flightOperator, outboundLeg, inboundLeg) { Fares = fares }; newData.AddFlight(newFlight); opearatorFlights.Add(newFlight); } } if (newData.Flights.Count > 0) { Journey existJourney = null; DateTime deptDate = newData.Flights[0].OutboundLeg.Departure.Date; DateTime retDate = DateTime.MinValue; if (newData.Flights[0].InboundLeg != null) { retDate = newData.Flights[0].InboundLeg.Departure.Date; } foreach (var j in route.Journeys) { if (j.DepartureDate == deptDate && j.ReturnDate == retDate) { existJourney = j; break; } } if (existJourney == null) { existJourney = new Journey(); route.AddJourney(existJourney); } existJourney.AddData(newData); existJourney.DepartureDate = deptDate; existJourney.ReturnDate = retDate; } } return new RouteDataResult(DataResult.Ready, route); }
/// <summary> /// The get presentation strings. /// </summary> /// <param name="flight"> /// The flight. /// </param> /// <param name="targetCurrency"> /// The target currency. /// </param> /// <returns> /// The <see cref="List"/>. /// </returns> internal List<string> GetPresentationStrings(Flight flight, string targetCurrency) { string deptTime = flight.OutboundLeg.Departure.ToShortTimeString(), outboundInfo = string.Format("({0}) - {1}", flight.OutboundLeg.Transit, flight.OutboundLeg.Duration.ToHourMinuteString()), returnTime = flight.InboundLeg == null ? null : flight.InboundLeg.Departure.ToShortTimeString(), inboundInfo = flight.InboundLeg == null ? null : string.Format("({0}) - {1}", flight.InboundLeg.Transit, flight.InboundLeg.Duration.ToHourMinuteString()), flightCompany = flight.Operator, price = this.GetFlightPrice(flight, targetCurrency), travelPeriod = flight.OutboundLeg.Departure.ToString("ddd dd/MM/yyyy") + " - " + (flight.InboundLeg == null ? string.Empty : flight.InboundLeg.Departure.ToString("ddd dd/MM/yyyy")), stayDuration = ((int)(flight.InboundLeg == null ? 0 : (flight.InboundLeg.Departure.Date - flight.OutboundLeg.Departure.Date).TotalDays)) .ToString(CultureInfo.InvariantCulture), dataDate = flight.JourneyData.DataDate.ToString("ddd, MMM dd, yyyy h:mm:ss tt"), agency = flight.TravelAgency == null ? null : flight.TravelAgency.Name; var result = new List<string> { deptTime, outboundInfo, returnTime, inboundInfo, flightCompany, price, travelPeriod, stayDuration, dataDate, agency }; return result; }
/// <summary> /// Initializes a new instance of the <see cref="MenuBuilderEventArgs"/> class. /// </summary> /// <param name="selectedFlight"> /// The selected flight. /// </param> public MenuBuilderEventArgs(Flight selectedFlight) { this.SelectedFlight = selectedFlight; }