/// <summary> /// Initializes a new instance of the <see cref="Journey"/> class. /// </summary> /// <param name="id"> /// The id. /// </param> /// <param name="route"> /// The route. /// </param> /// <param name="departureDate"> /// The departure date. /// </param> /// <param name="returnDate"> /// The return date. /// </param> public Journey(long id, TravelRoute route, DateTime departureDate, DateTime returnDate) : this(route) { this.Id = id; this.DepartureDate = departureDate; this.ReturnDate = returnDate; }
/// <summary> /// The export data. /// </summary> /// <param name="targetStream"> /// The target stream. /// </param> /// <param name="route"> /// The route. /// </param> public override void ExportData(Stream targetStream, TravelRoute route) { if (route == null || route.Journeys.Count < 1) { return; } var exporter = new MatrixDataExporter(); exporter.ExportData(targetStream, route); }
/// <summary> /// Initializes a new instance of the <see cref="FlightStatisticForm"/> class. /// </summary> /// <param name="data"> /// The data. /// </param> /// <param name="executionParam"> /// The execution param. /// </param> /// <param name="isMainForm"> /// The is main form. /// </param> public FlightStatisticForm(IList<TravelRoute> data, ExecutionParam executionParam, bool isMainForm) { this.InitializeComponent(); this._isMainForm = isMainForm; this._routeData = data; if (data != null && data.Count > 0) { this._activeRoute = data[0]; this.ReloadRoutes(); } this._executionParam = executionParam; this.InitializeView(); }
/// <summary> /// Bind the list view asynchronously /// </summary> /// <param name="route"> /// The route. /// </param> /// <param name="departureDate"> /// The departure Date. /// </param> /// <param name="returnDate"> /// The return Date. /// </param> /// <param name="priceLimit"> /// The price Limit. /// </param> /// <param name="allHistory"> /// The all History. /// </param> /// <param name="amountOfPrices"> /// The amount Of Prices. /// </param> /// <param name="minDuration"> /// The min Duration. /// </param> /// <param name="maxDuration"> /// The max Duration. /// </param> /// <param name="opearators"> /// The opearators. /// </param> /// <param name="populateData"> /// The populate Data. /// </param> private void BindListViewAsync( TravelRoute route, DateTime departureDate, DateTime returnDate, double priceLimit, bool allHistory, int amountOfPrices, int minDuration, int maxDuration, Dictionary<string, bool> opearators, bool populateData) { if (!this._formLoaded) { return; } ThreadPool.QueueUserWorkItem( o => { AppUtil.NameCurrentThread(this.GetType().Name + "-BindListView"); this.BindListView( route, departureDate, returnDate, priceLimit, allHistory, amountOfPrices, minDuration, maxDuration, opearators, populateData); }); }
/// <summary> /// Initializes a new instance of the <see cref="JourneyEventArgs"/> class. /// </summary> /// <param name="route"> /// The route. /// </param> /// <param name="requestState"> /// The request state. /// </param> /// <param name="initiatedDate"> /// The initiated date. /// </param> public JourneyEventArgs(TravelRoute route, DataRequestState requestState, DateTime initiatedDate) { this.ResultRoute = route; this.RequestState = requestState; this.RequestInitiatedDate = initiatedDate; }
/// <summary> /// The get routes. /// </summary> /// <param name="loadJourneys"> /// The load journeys. /// </param> /// <param name="loadJourneyData"> /// The load journey data. /// </param> /// <param name="loadHistory"> /// The load history. /// </param> /// <param name="loadFlights"> /// The load flights. /// </param> /// <param name="callback"> /// The callback. /// </param> /// <returns> /// The <see cref="IList"/>. /// </returns> public IList<TravelRoute> GetRoutes(bool loadJourneys, bool loadJourneyData, bool loadHistory, bool loadFlights, IProgressCallback callback) { this.Logger.DebugFormat( "Get available routes [{0}{1}{2}{3}]", loadJourneys ? "J" : null, loadJourneyData ? "D" : null, loadHistory ? "H" : null, loadFlights ? "F" : null); var result = new List<TravelRoute>(); using (var connection = new SQLiteConnection(this._connectionString)) { using (var getPlacesCmd = new SQLiteCommand("SELECT LID, SDEPARTURE, SDESTINATION FROM ROUTE", connection)) { connection.Open(); using (var reader = getPlacesCmd.ExecuteReader()) { if (reader.HasRows) { int iLid = reader.GetOrdinal("LID"); int iDeparture = reader.GetOrdinal("SDEPARTURE"); int iDestination = reader.GetOrdinal("SDESTINATION"); while (reader.Read()) { long id = reader.GetInt64(iLid); string origin = reader.GetString(iDeparture); string destination = reader.GetString(iDestination); var newRoute = new TravelRoute(id, AirportDataProvider.FromIATA(origin), AirportDataProvider.FromIATA(destination)); if (loadJourneys) { this.LoadData(newRoute, loadJourneyData, loadHistory, loadFlights, callback); } result.Add(newRoute); } } } } } return result; }
public void FlightDataListViewTest() { // To generate code for this test, select "Generate Code for Coded UI Test" from the shortcut menu and select one of the menu items. // For more information on generated code, see http://go.microsoft.com/fwlink/?LinkId=179463 using (var frm = new Form()) { using (var lv = new FlightDataListView { Dock = DockStyle.Fill }) { var route = new TravelRoute(1, AirportDataProvider.FromIATA("HEL"), AirportDataProvider.FromIATA("SGN")); var j = new Journey(1, route, DateTime.Now, DateTime.Now.AddDays(7)); var d = new JourneyData(1, "EUR", DateTime.Now); var ds = new List<Flight>(100); /* TODO FIX Unit test for (int i = 0; i < 100; i++) { var f = new Flight( d, Guid.NewGuid().ToString(), i + 10, new TravelAgency(Guid.NewGuid().ToString(), "http://google.com"), new FlightLeg(DateTime.Now, DateTime.Now.AddDays(1), TimeSpan.FromHours(i + 12), 2), new FlightLeg(DateTime.Now.AddDays(7), DateTime.Now.AddDays(8), TimeSpan.FromHours(i + 13), 2)); ds.Add(f); } */ j.AddData(d); d.SetFlightLinks(); lv.SetDataSourceAsync(ds, true); frm.Controls.Add(lv); frm.ShowDialog(); } } }
/// <summary> /// The export data. /// </summary> /// <param name="targetStream"> /// The target stream. /// </param> /// <param name="route"> /// The route. /// </param> public abstract void ExportData(Stream targetStream, TravelRoute route);
/// <summary> /// Check if 2 routes have the same departure and destination airport /// </summary> /// <param name="other"> /// The other. /// </param> /// <returns> /// The <see cref="bool"/>. /// </returns> public bool IsSameRoute(TravelRoute other) { if (other == null) { return false; } return string.Equals(this.Departure.IATA, other.Departure.IATA, StringComparison.OrdinalIgnoreCase) && string.Equals(this.Destination.IATA, other.Destination.IATA, StringComparison.OrdinalIgnoreCase); }
/// <summary> /// Initializes a new instance of the <see cref="TravelRoute"/> class. /// </summary> /// <param name="route"> /// The route. /// </param> public TravelRoute(TravelRoute route) : this(route.Id, route.Departure, route.Destination) { }
/// <summary> /// The generate file name. /// </summary> /// <param name="route"> /// The route. /// </param> /// <returns> /// The <see cref="string"/>. /// </returns> private string GenerateFileName(TravelRoute route) { string origin = route.Departure.IATA; string dest = route.Destination.IATA; long minId = int.MaxValue, maxId = 0; foreach (var j in route.Journeys) { var id = j.Id; if (id > maxId) { maxId = id; } if (id < minId) { minId = id; } } var fileName = string.Format( CultureInfo.InvariantCulture, "{0}-{1}.[{2}]-[{3}]-({4}-{5}){6}({7})", this.FareDataProvider.ServiceName, route.Id, origin, dest, minId, maxId, DateTime.Now.ToString(NamingRule.DATE_FORMAT, CultureInfo.InvariantCulture), route.Journeys.Count); var processedName = PathUtil.RemoveInvalidFileNameChars(fileName); return processedName; }
/// <summary> /// The export data. /// </summary> /// <param name="data"> /// The data. /// </param> /// <param name="destinationPath"> /// The destination path. /// </param> /// <param name="format"> /// The format. /// </param> /// <param name="callback"> /// The callback. /// </param> /// <returns> /// The <see cref="string"/>. /// </returns> public string ExportData(TravelRoute data, string destinationPath, DataFormat format, IProgressCallback callback) { return this.ExportData(new List<TravelRoute> { data }, destinationPath, format, callback); }
/// <summary> /// Initializes a new instance of the <see cref="JourneyProgressChangedEventArgs"/> class. /// </summary> /// <param name="percentage"> /// The percentage. /// </param> /// <param name="resultRoute"> /// The result route. /// </param> /// <param name="request"> /// The request. /// </param> /// <param name="stateObj"> /// The state obj. /// </param> public JourneyProgressChangedEventArgs(int percentage, TravelRoute resultRoute, FlightFareRequest request, object stateObj) : base(percentage, stateObj) { this.ResultRoute = resultRoute; this.Request = request; }
/// <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 reset. /// </summary> public void Reset() { this.LastDataDate = this.LastRequestStartedDate = DateTime.MinValue; this._lastRetrievedRoute = null; this.RequestState = DataRequestState.Pending; }
/// <summary> /// Initializes a new instance of the <see cref="DataRequestResult"/> struct. /// </summary> /// <param name="requestState"> /// The request state. /// </param> /// <param name="resultRoute"> /// The result route. /// </param> public DataRequestResult(DataRequestState requestState, TravelRoute resultRoute) { this.RequestState = requestState; this.ResultRoute = resultRoute; }
/// <summary> /// The bind data. /// </summary> /// <param name="route"> /// The route. /// </param> private void BindData(TravelRoute route) { if (route != null && route.Journeys.Count > 0 && route.Journeys[0].Data.Count > 0) { DateTime dataDate = DateTime.Now; var flights = new List<Flight>(); var jData = route.Journeys[0].Data; foreach (var d in jData) { d.DataDate = dataDate; if (d.Flights != null && d.Flights.Count > 0) { flights.AddRange(d.Flights); } } this.lvFlightData.SetDataSourceAsync(flights, true); this.lvFlightData.SetWatermark(null); } else if (this.RequestState == DataRequestState.NoData) { this.lvFlightData.SetWatermark( "There is no data for selected journey. Probably there is no flight on that date or there is no flight between two destinations!"); } else if (this.LastException != null) { this.lvFlightData.SetWatermark("Failed to retrieve data: " + this.LastException.Message); } else { this.lvFlightData.SetWatermark("The request was not properly handled or aborted"); } }
/// <summary> /// Initializes a new instance of the <see cref="Journey"/> class. /// </summary> /// <param name="route"> /// The route. /// </param> public Journey(TravelRoute route) : this() { this.Route = route; }
/// <summary> /// The do request data. /// </summary> /// <param name="request"> /// The request. /// </param> private void DoRequestData(FlightFareRequest request) { if (!Monitor.TryEnter(this._syncObject)) { return; } try { this.IsStopping = false; if (this.IsDestructed() || this.IsStopping) { return; } // First, reset all data this.Reset(); var reqName = StringUtil.GetPeriodString(request.DepartureDate, request.ReturnDate); this.lvFlightData.SafeInvoke( new Action( () => { this.lvFlightData.Name = reqName; this.lvFlightData.SetWatermark("Requesting data... Please wait..."); })); // Create a thread to get the data DataRequestResult dataRequestResult = DataRequestResult.Empty; var workResult = BackgroundThread.DoWork( () => { this.lvFlightData.SetWatermark( "Data request was started on " + DateTime.Now + Environment.NewLine + "Please wait while the application retrieves fare data..."); this.RequestState = DataRequestState.Requested; this.LastRequestStartedDate = DateTime.Now; dataRequestResult = this.DataHandler.QueryData(request, this.OnProgressChanged); }, this.TimeoutInSeconds, reqName, AppContext.Logger); if (workResult.Succeeded) { this.RequestState = dataRequestResult.ResultRoute == null ? DataRequestState.NoData : DataRequestState.Ok; } else { this.RequestState = DataRequestState.Failed; if (workResult.IsTimedout) { string err = "Request timed out after " + this.TimeoutInSeconds + "s"; this.LastException = new TimeoutException(err); this.Logger.ErrorFormat(err); } else if (workResult.Exception != null) { this.LastException = workResult.Exception; this.Logger.Error("Failed to request journey data: " + workResult.Exception.Message); } } this.RequestState = dataRequestResult.RequestState; this._lastRetrievedRoute = dataRequestResult.ResultRoute; if (this.RequestState > DataRequestState.Requested) { this.LastDataDate = DateTime.Now; if (this._lastRetrievedRoute != null && this._lastRetrievedRoute.Journeys.Count > 0) { foreach (var j in this._lastRetrievedRoute.Journeys) { foreach (var d in j.Data) { if (d.DataDate.IsUndefined()) { d.DataDate = this.LastDataDate; } } } } } } catch (Exception ex) { this.LastException = ex; this.RequestState = DataRequestState.Failed; this.Logger.Error("Failed to request data: " + ex); } finally { Monitor.Exit(this._syncObject); // Release the lock at the end this.OnGetJourneyCompleted(new JourneyEventArgs(this.LastRetrievedRoute, this.RequestState, this.LastRequestInitiatedDate)); this.IsStopping = false; } }
/// <summary> /// The do export database. /// </summary> /// <param name="exportPath"> /// The export path. /// </param> /// <param name="format"> /// The format. /// </param> /// <param name="batchSize"> /// The batch size. /// </param> /// <param name="callback"> /// The callback. /// </param> private void DoExportDatabase(string exportPath, DataFormat format, int batchSize, IProgressCallback callback) { var routes = this.ResultEnvironment.FareDatabase.GetRoutes(true, false, false, false, callback); var journeyBatch = new List<Journey>(); var routesBatch = new List<TravelRoute>(); var jCount = routes.Sum(r => r.Journeys.Count); int stackCount = 0; callback.Begin(0, jCount); callback.Title = string.Format("Processing {0} journeys...", jCount); int routesCount = routes.Count; int lastRoutesIdx = routesCount - 1; for (int i = 0; i < routesCount; i++) { if (callback.IsAborting) { return; } TravelRoute route = routes[i]; callback.Text = string.Format("{0} - {1}", route.Departure, route.Destination); var journeys = route.Journeys; int journeysCount = journeys.Count; int lastJourneyIdx = journeysCount - 1; if (journeysCount > 0) { for (int j = 0; j < journeysCount; j++) { var journey = journeys[j]; journeyBatch.Add(journey); if (journeyBatch.Count >= batchSize || j == lastJourneyIdx) { // Batch is full or this is the last item var expRoute = new TravelRoute(route); // Gather journeys into 1 exported route expRoute.AddJourney(journeyBatch, false); this.ResultEnvironment.FareDatabase.LoadData(journeyBatch, true, AppContext.ProgressCallback); routesBatch.Add(expRoute); stackCount += journeyBatch.Count; journeyBatch.Clear(); } if (stackCount >= batchSize || i == lastRoutesIdx) { if (routesBatch.Count > 0) { this.ResultEnvironment.ArchiveManager.ExportData(routesBatch, exportPath, format, AppContext.ProgressCallback); routesBatch.Clear(); } callback.Increment(stackCount); stackCount = 0; } } } callback.Increment(1); } }
/// <summary> /// The selected location changed. /// </summary> /// <param name="sender"> /// The sender. /// </param> /// <param name="e"> /// The e. /// </param> private void SelectedLocationChanged(object sender, EventArgs e) { // If this event was triggered due to changing of another combobox: Return if (this._changingLocation) { return; } this._changingLocation = true; try { if (this._routeData == null) { return; } Airport selDeparture = null; Airport selDestination = null; if (sender == this.cbDeparture) { // If departure location was changed if (this.cbDeparture.Items.Count < 1) { return; } if (this._loadingRoutes) { if (this._executionParam.Departure != null) { this.cbDeparture.SelectedAirportCode = this._executionParam.Departure.IATA; } if (this.cbDeparture.SelectedItem == null && this.cbDeparture.Items.Count > 0) { // If the configured departure does not exist in database this.cbDeparture.SelectedItem = this.cbDeparture.Items[0]; } } selDeparture = this.cbDeparture.SelectedAirport; List<Airport> destList = null; if (this._routeData != null) { destList = new List<Airport>(); foreach (var r in this._routeData) { if (string.Equals(r.Departure.IATA, selDeparture.IATA, StringComparison.OrdinalIgnoreCase) && !destList.Contains(r.Destination)) { destList.Add(r.Destination); } } } this.cbDestination.DataSource = destList; if (this._loadingRoutes) { if (this._executionParam.Destination != null) { this.cbDestination.SelectedAirport = this._executionParam.Destination; } if (this.cbDestination.SelectedItem == null && this.cbDestination.Items.Count > 0) { // If the configured destination does not exist in database this.cbDestination.SelectedItem = this.cbDestination.Items[0]; // Select the first item available } } } else { selDeparture = this.cbDeparture.SelectedAirport; } // If the destination was specified before: Try to match it with the new data selDestination = this.cbDestination.SelectedAirport; if (this._isMainForm) { this._activeRoute = null; // Clear the active route first if (selDeparture != null && selDestination != null) { // Reload data only if we are running on main form foreach (var r in this._routeData) { string deptCode = r.Departure.IATA, destCode = r.Destination.IATA; if (string.Equals(deptCode, selDeparture.IATA, StringComparison.OrdinalIgnoreCase) && string.Equals(destCode, selDestination.IATA, StringComparison.OrdinalIgnoreCase)) { this._activeRoute = r; this.Logger.DebugFormat("Reloading routes [{0}]-[{1}]...", deptCode, destCode); this.FareDatabase.LoadData(this._activeRoute, false, false, false, AppContext.ProgressCallback); break; } } } } this.FlightFilter_Changed(null, e); } finally { this._changingLocation = false; } }
/// <summary> /// The load data. /// </summary> /// <param name="route"> /// The route. /// </param> /// <param name="loadJourneyData"> /// The load journey data. /// </param> /// <param name="loadHistory"> /// The load history. /// </param> /// <param name="loadFlights"> /// The load flights. /// </param> /// <param name="callback"> /// The callback. /// </param> /// <exception cref="ArgumentException"> /// </exception> public void LoadData(TravelRoute route, bool loadJourneyData, bool loadHistory, bool loadFlights, IProgressCallback callback) { this.Logger.DebugFormat( "Load data for route [{0}-{1}] [{2}{3}{4}]", route.Departure.IATA, route.Destination.IATA, loadJourneyData ? "D" : null, loadHistory ? "H" : null, loadFlights ? "F" : null); using (var connection = new SQLiteConnection(this._connectionString)) { if (route.Id < 1) { throw new ArgumentException("Invalid Route Id"); } route.Journeys.Clear(); string selectSql = "SELECT J.LID, J.TDEPARTURE, J.TRETURN" + (loadJourneyData ? (", D.LID DATAID, D.SCURRENCY, " + (loadHistory ? "D.TUPDATE" : "MAX(D.TUPDATE) TUPDATE") + (loadFlights ? ", D.BFLIGHT" : string.Empty)) : string.Empty) + " FROM JOURNEY J" + (loadJourneyData ? ", JOURNEY_DATA D " : string.Empty) + " WHERE J.LROUTEID = @lRouteId " + (loadJourneyData ? " AND D.LJOURNEYID = J.LID " + (loadHistory ? string.Empty : " GROUP BY (D.LJOURNEYID) ") : string.Empty); using (var getJourneyCmd = new SQLiteCommand(selectSql, connection)) { getJourneyCmd.Parameters.AddWithValue("@lRouteId", route.Id); connection.Open(); using (var reader = getJourneyCmd.ExecuteReader()) { if (reader.HasRows) { int iId = reader.GetOrdinal("LID"); int iDeparture = reader.GetOrdinal("TDEPARTURE"); int iReturn = reader.GetOrdinal("TRETURN"); int iUpdate = reader.GetOrdinal("TUPDATE"); int iCurrency = loadJourneyData ? reader.GetOrdinal("SCURRENCY") : -1; int iDataId = loadJourneyData ? reader.GetOrdinal("DATAID") : -1; int iFlight = loadJourneyData ? reader.GetOrdinal("BFLIGHT") : -1; while (reader.Read()) { long journeyId = reader.GetInt64(iId); Journey journey = null; var allJourneys = route.Journeys; foreach (var j in allJourneys) { if (j.Id == journeyId) { journey = j; break; } } if (journey == null) { var deptDate = DateTime.ParseExact(reader.GetString(iDeparture), DATE_FORMAT, CultureInfo.InvariantCulture); var retDate = DateTime.ParseExact(reader.GetString(iReturn), DATE_FORMAT, CultureInfo.InvariantCulture); journey = new Journey(journeyId, route, deptDate, retDate); route.AddJourney(journey); } if (loadJourneyData) { var dataDate = DateTime.ParseExact( reader.GetString(iUpdate), DATETIME_FORMAT, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal); var newData = new JourneyData(reader.GetInt64(iDataId), reader.GetString(iCurrency), dataDate); if (loadFlights) { var dbFlights = this._formatter.FromRaw<List<Flight>>((byte[])reader[iFlight]); if (dbFlights != null && dbFlights.Count > 0) { newData.AddFlights(dbFlights); } } journey.AddData(newData); } } } } } } }
/// <summary> /// The bind list view. /// </summary> /// <param name="route"> /// The route. /// </param> /// <param name="departureDate"> /// The departure date. /// </param> /// <param name="returnDate"> /// The return date. /// </param> /// <param name="priceLimit"> /// The price limit. /// </param> /// <param name="viewAllHistory"> /// The view all history. /// </param> /// <param name="amountFlightsPerData"> /// The amount flights per data. /// </param> /// <param name="minDuration"> /// The min duration. /// </param> /// <param name="maxDuration"> /// The max duration. /// </param> /// <param name="opearators"> /// The opearators. /// </param> /// <param name="populateData"> /// The populate data. /// </param> private void BindListView( TravelRoute route, DateTime departureDate, DateTime returnDate, double priceLimit, bool viewAllHistory, int amountFlightsPerData, int minDuration, int maxDuration, Dictionary<string, bool> opearators, bool populateData) { DateTime requestDate = DateTime.Now; if (!Monitor.TryEnter(this._lockObj)) { // The view is being refreshed: Send a signal this._lvChangeRequested = true; this._lvChangeRequestDate = requestDate; Monitor.Enter(this._lockObj); } this._lvChangeRequested = false; try { if (requestDate < this._lvChangeRequestDate) { // Another request has come in: Let the later one passes through return; } var data = route.Journeys; if (data == null || data.Count < 1) { return; } this.SafeInvoke( (Action)delegate { progressBar.ShowInTaskbar = progressBar.Visible = true; progressBar.Style = ProgressBarStyle.Marquee; }); // Get all the needed data according to the Date filter condition IEnumerable<Journey> journeyCollection = null; if (departureDate.IsDefined()) { // Known departure date if (returnDate == DateTime.MaxValue) { // Unknown return date journeyCollection = data.Where(o => o.DepartureDate.Date == departureDate.Date).OrderByDescending(o => o.ReturnDate); } else { // Known return date or one-way trip for DateTime.MinValue journeyCollection = data.Where(o => o.DepartureDate.Date == departureDate.Date && o.ReturnDate.Date == returnDate.Date); } } else { // Unknown departure date if (returnDate == DateTime.MaxValue) { // Unknown return date journeyCollection = data.OrderBy(o => o.DepartureDate).ThenByDescending(o => o.ReturnDate); } else { // Known return date or one-way trip for DateTime.MinValue journeyCollection = data.Where(o => o.ReturnDate.Date == returnDate.Date).OrderBy(o => o.DepartureDate); } } var newOperators = new List<string>(); var existOperatorSelections = new List<CheckBoxComboBoxItem>(); if (populateData) { this.SetStatus("Loading flight data..."); const int loadSize = 1000; var loadBatch = new List<Journey>(); foreach (var j in journeyCollection) { loadBatch.Add(j); if (loadBatch.Count == loadSize) { this.FareDatabase.LoadData(loadBatch, viewAllHistory, AppContext.ProgressCallback); loadBatch.Clear(); } if (this._lvChangeRequested) { return; } } if (!this._lvChangeRequested && loadBatch.Count > 0) { this.FareDatabase.LoadData(loadBatch, viewAllHistory, AppContext.ProgressCallback); } } this.SetStatus("Processing data..."); int totalJourneysCount = journeyCollection.Count(); int totalFlightsCount = 0; int skippedDuration = 0, skippedPrice = 0, skippedIgnored = 0; var flightsData = new List<Flight>(); this.SafeInvoke( (Action)delegate { progressBar.Style = ProgressBarStyle.Continuous; progressBar.Value = 0; progressBar.Maximum = totalJourneysCount; existOperatorSelections.AddRange(cbAirlines.CheckBoxItems); }); // Only filter based on duration if there is undefined departure or return date, and user did not choose one-way trip bool checkDuration = (departureDate.IsUndefined() || returnDate.IsUndefined()) && returnDate != DateTime.MinValue; foreach (Journey j in journeyCollection) { this.SafeInvoke((Action)delegate { progressBar.Value++; }); if (this._lvChangeRequested) { return; } bool skippedJourney = false; if (checkDuration) { int stayDuration = (int)(j.ReturnDate.Date - j.DepartureDate.Date).TotalDays; if (stayDuration < 0) { // One-way trip stayDuration = 0; } skippedJourney = stayDuration < minDuration || stayDuration > maxDuration; } List<Flight> journeyFlights = skippedJourney ? null : new List<Flight>(); foreach (var d in j.Data) { // Keep counts for statistics totalFlightsCount += d.Flights.Count; if (skippedJourney) { skippedDuration += d.Flights.Count; } else { var flights = d.Flights; flights.Sort(FlightPriceComparer.Instance); int taking = amountFlightsPerData > flights.Count ? flights.Count : amountFlightsPerData; skippedIgnored += flights.Count - taking; for (int i = 0; i < taking; i++) { if (flights[i].Price > priceLimit) { skippedPrice += taking - i; break; } journeyFlights.Add(flights[i]); } } } if (journeyFlights == null) { continue; } // Fill the list of flight operators for filter purpose foreach (Flight flight in journeyFlights) { string flightOperator = flight.Operator; if (opearators != null) { if (opearators.ContainsKey(flightOperator) && !opearators[flightOperator]) { continue; } } flightsData.Add(flight); if (!newOperators.Contains(flightOperator)) { newOperators.Add(flightOperator); } } } this.SetStatus("Rendering view..."); this.SafeInvoke( new Action( () => { this.progressBar.Style = ProgressBarStyle.Marquee; this.lvFlightData.SetDataSourceAsync(flightsData, true); if (opearators == null) { // Reload data - Refill list of operators var newOperatorCheckList = new Dictionary<string, bool>(); if (opearators != null) { foreach (var v in opearators) { newOperatorCheckList.Add(v.Key, v.Value); } } foreach (string s in newOperators) { if (!newOperatorCheckList.ContainsKey(s)) { newOperatorCheckList.Add(s, true); } } List<KeyValuePair<string, bool>> sortedOps = newOperatorCheckList.OrderBy(p => p.Key).ToList(); this.cbAirlines.SelectedValueChanged -= this.FlightFilter_Changed; this.cbAirlines.TextChanged -= this.FlightFilter_Changed; this.cbAirlines.Text = null; this.cbAirlines.Items.Clear(); this.cbAirlines.CheckBoxItems.Clear(); sortedOps.ForEach( p => { int pos = this.cbAirlines.Items.Add(p.Key); this.cbAirlines.CheckBoxItems[pos].Checked = p.Value; }); this.cbAirlines.SelectedValueChanged += this.FlightFilter_Changed; this.cbAirlines.TextChanged += this.FlightFilter_Changed; } this.btnToCsv.Enabled = this.btnGraph.Enabled = flightsData.Count > 0; this.progressBar.Visible = false; string status; if (totalFlightsCount == 0) { status = "There is no flight data for this date"; } else { string journeyStr = totalJourneysCount > 1 ? " (" + totalJourneysCount + " dates)" : null; var parts = new List<string>(); if (skippedDuration > 0) { parts.Add(skippedDuration + " not in duration range"); } if (skippedPrice > 0) { parts.Add(skippedPrice + " too expensive"); } if (skippedIgnored > 0) { parts.Add(skippedIgnored + " ignored"); } if (flightsData.Count > 0) { parts.Add(flightsData.Count + " displayed"); } string skipStr = parts.Count > 0 ? " | " + string.Join(", ", parts.ToArray()) : string.Empty; status = string.Format("Available flights: {0}{1}{2}", totalFlightsCount, journeyStr, skipStr); } this.numMinDuration.Enabled = this.numMaxDuration.Enabled = checkDuration; this.SetStatus(status); })); } catch (Exception ex) { this.Logger.Error(ex); MessageBox.Show(this, ex.ToString(), "Could not display data"); this.SetStatus("An internal error occured"); } finally { this.SafeInvoke( (Action)(() => { this.progressBar.ShowInTaskbar = this.progressBar.Visible = false; this.progressBar.Value = 0; })); Monitor.Exit(this._lockObj); } }
/// <summary> /// The export data. /// </summary> /// <param name="targetStream"> /// The target stream. /// </param> /// <param name="route"> /// The route. /// </param> /// <exception cref="ArgumentException"> /// </exception> public void ExportData(Stream targetStream, TravelRoute route) { if (targetStream == null) { throw new ArgumentException("targetStream cannot be null"); } if (route == null) { throw new ArgumentException("route cannot be null"); } var setting = new XmlWriterSettings(); setting.OmitXmlDeclaration = true; setting.Indent = true; setting.Encoding = Encoding.Default; /* TODO :FIX XML stream writer using (XmlWriter writer = XmlWriter.Create(targetStream, setting)) { writer.WriteStartElement("body"); writer.WriteStartElement("input"); writer.WriteAttributeString("id", "text_fly_from"); writer.WriteAttributeString("value", route.Departure.IATA); writer.WriteEndElement(); writer.WriteStartElement("input"); writer.WriteAttributeString("id", "text_fly_to"); writer.WriteAttributeString("value", route.Destination.IATA); writer.WriteEndElement(); foreach (var journey in route.Journeys) { foreach (var data in journey.Data) { writer.WriteStartElement("div"); writer.WriteAttributeString("id", "results_list"); writer.WriteAttributeString("dataDate", XmlConvert.ToString(data.DataDate, XmlDateTimeSerializationMode.Utc)); foreach (Flight f in data.Flights) { var outboundLeg = f.OutboundLeg; if (outboundLeg == null) { continue; } writer.WriteStartElement("div"); writer.WriteAttributeString("class", "flights_b"); writer.WriteAttributeString("id", "flight_result_0"); if (f.TravelAgency != null && !string.IsNullOrEmpty(f.TravelAgency.Url)) { writer.WriteAttributeString("onclick", "click('" + f.TravelAgency.Url + "')"); } // Outbound writer.WriteStartElement("div"); writer.WriteAttributeString("class", "f_outbound"); writer.WriteStartElement("div"); writer.WriteAttributeString("class", "f_dep_date"); writer.WriteString(outboundLeg.Departure.ToString("dd.MM.yy")); writer.WriteEndElement(); writer.WriteStartElement("div"); writer.WriteAttributeString("class", "f_departure"); writer.WriteString(outboundLeg.Departure.ToString("HH:mm")); writer.WriteEndElement(); writer.WriteStartElement("div"); writer.WriteAttributeString("class", "f_arr_date"); writer.WriteString(outboundLeg.Arrival.ToString("dd.MM.yy")); writer.WriteEndElement(); writer.WriteStartElement("div"); writer.WriteAttributeString("class", "f_arrival"); writer.WriteString(outboundLeg.Arrival.ToString("HH:mm")); writer.WriteEndElement(); writer.WriteStartElement("div"); writer.WriteAttributeString("class", "f_stops"); writer.WriteString(outboundLeg.Transit.ToString(CultureInfo.InvariantCulture)); writer.WriteEndElement(); writer.WriteStartElement("div"); writer.WriteAttributeString("class", "f_duration"); writer.WriteString(outboundLeg.Duration + "h"); writer.WriteEndElement(); writer.WriteEndElement(); // Return trip var inboundLeg = f.InboundLeg; if (inboundLeg != null) { writer.WriteStartElement("div"); writer.WriteAttributeString("class", "f_return"); writer.WriteStartElement("div"); writer.WriteAttributeString("class", "f_dep_date"); writer.WriteString(inboundLeg.Departure.ToString("dd.MM.yy")); writer.WriteEndElement(); writer.WriteStartElement("div"); writer.WriteAttributeString("class", "f_departure"); writer.WriteString(inboundLeg.Departure.ToString("HH:mm")); writer.WriteEndElement(); writer.WriteStartElement("div"); writer.WriteAttributeString("class", "f_arr_date"); writer.WriteString(inboundLeg.Arrival.ToString("dd.MM.yy")); writer.WriteEndElement(); writer.WriteStartElement("div"); writer.WriteAttributeString("class", "f_arrival"); writer.WriteString(inboundLeg.Arrival.ToString("HH:mm")); writer.WriteEndElement(); writer.WriteStartElement("div"); writer.WriteAttributeString("class", "f_stops"); writer.WriteString(inboundLeg.Transit.ToString(CultureInfo.InvariantCulture)); writer.WriteEndElement(); writer.WriteStartElement("div"); writer.WriteAttributeString("class", "f_duration"); writer.WriteString(inboundLeg.Duration + "h"); writer.WriteEndElement(); writer.WriteEndElement(); } writer.WriteStartElement("div"); writer.WriteAttributeString("class", "f_company"); writer.WriteString(f.Operator); writer.WriteEndElement(); writer.WriteStartElement("div"); writer.WriteAttributeString("class", "f_price"); writer.WriteString(f.Price.ToString(CultureInfo.InvariantCulture) + " €"); writer.WriteEndElement(); writer.WriteEndElement(); } writer.WriteEndElement(); } } writer.WriteEndElement(); } */ }
/// <summary>The extract tab data.</summary> /// <returns>The <see cref="IList" />.</returns> private IList<TravelRoute> ExtractTabData() { AppContext.Logger.Debug("Generating journey from all tabs..."); var result = new List<TravelRoute>(); foreach (TabPage tab in this.fareBrowserTabs.TabPages) { try { var request = tab.Tag as FareMonitorRequest; if (request != null && request.BrowserControl != null) { TravelRoute route = request.BrowserControl.LastRetrievedRoute; if (route != null) { TravelRoute existRoute = null; foreach (var r in result) { if (r.IsSameRoute(route)) { existRoute = r; break; } } if (existRoute == null) { existRoute = new TravelRoute(route); result.Add(route); } existRoute.AddJourney(route.Journeys, false); } } } catch (Exception ex) { AppContext.Logger.ErrorFormat("Failed to get data from tab: " + ex); } } return result; }