Beispiel #1
0
        /// <summary>
        /// Called when either a new set of journeys or an extended set of journeys have been retrieved
        /// </summary>
        /// <param name="journeys"></param>
        public void JourneysAvailable(TrainJourneys journeys)
        {
            // Display them
            journeyAdapter.Items = journeys.Journeys.ToArray();
            journeyAdapter.NotifyDataSetChanged();

            // Update the manual update text
            updateTimer.JustUpdated();
        }
        /// <summary>
        /// Retrieve a set of journeys for the specified from and to stations.
        /// </summary>
        /// <param name="from"></param>
        /// <param name="to"></param>
        public async void GetJourneys(string from, string to, DateTime requestTime, CancellationToken cancelToken)
        {
            try
            {
                // Check if a previously obtained session id cookie is still valid
                if ((DateTime.Now - sessionCookieTime).TotalMinutes > SeesionCookieValidTimeInMinutes)
                {
                    // Must load the search page in order to set the session id cookie
                    await client.GetAsync("http://ojp.nationalrail.co.uk/service/planjourney/search", cancelToken);

                    // Save the time that this session id was obtained
                    sessionCookieTime = DateTime.Now;
                }

                // Set up the variable parameters
                requestParameters["from.searchTerm"]               = TrainTrip.ToWebFormat(from);
                requestParameters["to.searchTerm"]                 = TrainTrip.ToWebFormat(to);
                requestParameters["timeOfOutwardJourney.hour"]     = requestTime.Hour.ToString();
                requestParameters["timeOfOutwardJourney.minute"]   = requestTime.Minute.ToString();
                requestParameters["timeOfOutwardJourney.monthDay"] = requestTime.ToString("dd/MM/yy");

                // Make the request
                HttpResponseMessage response = await client.PostAsync("http://ojp.nationalrail.co.uk/service/planjourney/plan",
                                                                      new FormUrlEncodedContent( requestParameters ), cancelToken);

                // Load the result of the request into an HtmlDocument
                HtmlDocument doc = new HtmlDocument();
                doc.LoadHtml(await response.Content.ReadAsStringAsync());

                // Extract the journey, changes and date change nodes
                // The journeys are in table rows that contain cells of class 'dep'. Grab the containing row.
                // The changes associated with a journey are not in the same row as the journey so look for a cell with class 'origin'.
                // Changes are stored in the containing table. The extracted changes are stored with the last journey.
                // Date changes between journeys are contained in table rows with class 'day-heading'.
                // If date of the first journey are in an H3 element with class 'outward top ctf-h3'.
                HtmlNodeCollection dormNodes = doc.DocumentNode.SelectNodes(
                    "//td[@class='dep']/..|//td[@class='origin']/..|//h3[@class='outward top ctf-h3']/.|//tr[@class='day-heading']/.");
                if (dormNodes != null)
                {
                    // Assume that the journeys found are initially for the same day as the request
                    DateTime responseDate = requestTime.Date;

                    TrainJourneys journeys = new TrainJourneys();

                    // Fill the journeys list with the results
                    foreach (HtmlNode journeyNode in dormNodes)
                    {
                        // Check if this is a train node
                        if (journeyNode.SelectSingleNode("./td[@class='dep']") != null)
                        {
                            TrainJourney newJourney = new TrainJourney {
                                ArrivalTime   = journeyNode.SelectSingleNode("./td[@class='arr']").InnerText.Substring(0, 5),
                                DepartureTime = journeyNode.SelectSingleNode("./td[@class='dep']").InnerText.Substring(0, 5),
                                Duration      = ReplaceWhitespace(journeyNode.SelectSingleNode("./td[@class='dur']").InnerText),
                                Status        = ReplaceWhitespace(journeyNode.SelectSingleNode("./td[@class='status']").InnerText)
                            };

                            // Set the full departure timestamp from the responseDate and the departure time
                            newJourney.DepartureDateTime = responseDate + TimeSpan.ParseExact(newJourney.DepartureTime, "h\\:mm", CultureInfo.InvariantCulture);

                            journeys.Journeys.Add(newJourney);
                        }
                        else if (journeyNode.SelectSingleNode("./td[@class='origin']") != null)
                        {
                            // Only proceed with processing changes if a journey has been found
                            if (journeys.Journeys.Count > 0)
                            {
                                // Get the change data ignoring any empty cells and whitespace
                                HtmlNodeCollection cells = journeyNode.SelectNodes("./td");

                                if (cells != null)
                                {
                                    // Somewhere to save the cell data
                                    List <string> cellContents = new List <string>();

                                    foreach (HtmlNode cell in cells)
                                    {
                                        string innerText = ReplaceWhitespace(cell.InnerText);
                                        if (innerText.Length > 0)
                                        {
                                            cellContents.Add(innerText);
                                        }
                                    }

                                    // There should be 4 entries for a journey leg
                                    if (cellContents.Count == 4)
                                    {
                                        JourneyLeg leg = new JourneyLeg {
                                            DepartureTime = cellContents[0], From = cellContents[1],
                                            ArrivalTime   = cellContents[2], To = cellContents[3]
                                        };

                                        journeys.Journeys[journeys.Journeys.Count - 1].Legs.Add(leg);
                                    }
                                }
                            }
                        }
                        else
                        {
                            // If this is either the report header or a date change within the report.
                            // Extraxct the date
                            string headerDate = (journeyNode.Name == "h3") ?
                                                ReplaceWhitespace(journeyNode.InnerText).Replace("+", " ").Substring(17, 10) :
                                                ReplaceWhitespace(journeyNode.InnerText);

                            // Date is now of the format DDD nn MMM where nn could be one or two numeric digits
                            try
                            {
                                responseDate = DateTime.ParseExact(headerDate, new[] { "ddd dd MMM", "ddd d MMM" }, CultureInfo.InvariantCulture, DateTimeStyles.None);
                            }
                            catch (FormatException)
                            {
                            }
                        }
                    }

                    // Save the journeys so they can be accessed from outside the class
                    Journeys = journeys.Journeys;

                    JourneysAvailableEvent?.Invoke(this, new JourneysAvailableArgs {
                        JourneysAvailable = true
                    });
                }
                else
                {
                    JourneysAvailableEvent?.Invoke(this, new JourneysAvailableArgs {
                        JourneysAvailable = false
                    });
                }
            }
            catch (HttpRequestException)
            {
                JourneysAvailableEvent?.Invoke(this, new JourneysAvailableArgs {
                    JourneysAvailable = false, NetworkProblem = true
                });
            }
            catch (TaskCanceledException)
            {
                // This can be caused either from a user request or a network problem
                if (cancelToken.IsCancellationRequested == true)
                {
                    JourneysAvailableEvent?.Invoke(this, new JourneysAvailableArgs {
                        JourneysAvailable = false, RequestCancelled = true
                    });
                }
                else
                {
                    JourneysAvailableEvent?.Invoke(this, new JourneysAvailableArgs {
                        JourneysAvailable = false, NetworkProblem = true
                    });
                }
            }
            catch (OperationCanceledException)
            {
                JourneysAvailableEvent?.Invoke(this, new JourneysAvailableArgs {
                    JourneysAvailable = false, NetworkProblem = true
                });
            }
        }