/// <summary>
        /// Gets the cameras.
        /// </summary>
        /// <param name="cameraType">Type of the camera.</param>
        /// <param name="name">The name.</param>
        /// <returns></returns>
        public IObservable<Camera> GetCameras(CameraType cameraType, string name)
        {
            var cachedCameras = new CachedEntity<List<Camera>>(string.Format("Services.Camera.{0}.{1}", cameraType, name));

            return new AnonymousObservable<Camera>(observer =>
            {
                if (!cachedCameras.Value.Any() || !cachedCameras.CachedDateTime.HasValue || cachedCameras.CachedDateTime.Value <= DateTime.Now.AddDays(-1))
                {
                    Uri cameraListUri = null;

                    if (cameraType == CameraType.Regional)
                    {
                        cameraListUri = new Uri(string.Format("{0}?roadway={1}", DfwTranstarUri.CamerasRegionalUri, name.Replace(' ', '_')));
                    }
                    else
                    {
                        cameraListUri = new Uri(string.Format("{0}?list={1}&roadway={2}", DfwTranstarUri.CamerasUri, cameraType.ToString().ToLower(), name.Replace(' ', '_')));
                    }

                    IObservable<string> observable = ObservableHelper.TextFromUri(cameraListUri);

                    var svc = observable.Subscribe(result =>
                    {
                        int tableStart = result.IndexOf("<table id=\"ListTable\"");
                        int tableEnd = result.IndexOf("</table>", tableStart);

                        XElement xmlDoc = XElement.Parse(result.Substring(tableStart, (tableEnd + 8) - tableStart));

                        var cameras = from item in xmlDoc.Element("tr").Element("td").Element("ul").Elements("li")
                                      select new Camera
                                      {
                                          ID = this.GetCameraID(cameraType, item.Element("a").Attribute("href").Value),
                                          Name = item.Value,
                                          EnableThumbnails = ProfileCommon.UserSettings.ShowCameraThumbnails,
                                          ImageUri = cameraType == CameraType.Regional ?
                                              string.Format(DfwTranstarUri.CameraDetailRegionalUri, name.ToLower()
                                              .Replace(" north", "")
                                              .Replace(" south", "")
                                              .Replace(" east", "")
                                              .Replace(" west", ""),
                                              this.GetCameraID(cameraType, item.Element("a").Attribute("href").Value)) :
                                              string.Format(DfwTranstarUri.CameraDetailUri, this.GetCameraID(cameraType, item.Element("a").Attribute("href").Value))
                                      };

                        cachedCameras.Value = cameras.ToList();
                        cachedCameras.Cache();

                        cachedCameras.Value.ToList().ForEach(c => observer.OnNext(c));
                        observer.OnCompleted();
                    },
                    ex =>
                    {
                        observer.OnError(new Exception("Unable to retrieve traffic data.", ex));
                    });
                }
                else
                {
                    cachedCameras.Value.ToList().ForEach(c => observer.OnNext(c));
                    observer.OnCompleted();
                }

                return Disposable.Empty;
            });
        }
        /// <summary>
        /// Gets the roadway cameras.
        /// </summary>
        /// <param name="cameraType">Type of the camera.</param>
        /// <returns></returns>
        public IObservable<Roadway> GetRoadwayCameras(CameraType cameraType)
        {
            var cachedRoadways = new CachedEntity<List<Roadway>>("Services.RoadwayCameras." + cameraType.ToString());

            return new AnonymousObservable<Roadway>(observer =>
            {
                if (!cachedRoadways.Value.Any() || cachedRoadways.CachedDateTime <= DateTime.Now.AddDays(-1))
                {
                    Uri uri = null;

                    switch (cameraType)
                    {
                        case CameraType.Freeway:
                            uri = new Uri(DfwTranstarUri.CamerasUri);
                            break;

                        case CameraType.Street:
                            uri = new Uri(DfwTranstarUri.CamerasUri + "?list=street");
                            break;

                        case CameraType.Regional:
                            uri = new Uri(DfwTranstarUri.CamerasRegionalUri);
                            break;
                    }

                    IObservable<string> observable = ObservableHelper.TextFromUri(uri);

                    var svc = observable.Subscribe(result =>
                    {
                        int tableStart = result.IndexOf("<table id=\"ListTable\"");
                        int tableEnd = result.IndexOf("</table>", tableStart);

                        XElement xmlDoc = XElement.Parse(result.Substring(tableStart, (tableEnd + 8) - tableStart));

                        var roadways = from item in xmlDoc.Element("tr").Element("td").Element("ul").Elements("li")
                                       select new Roadway
                                       {
                                           Name = item.Value,
                                           IconUri = cameraType == CameraType.Freeway ?
                                                this.GetRoadwayIconUri(item.Value) : "/Resources/Images/empty_svg_small.png"
                                       };

                        cachedRoadways.Value = roadways.ToList();
                        cachedRoadways.Cache();

                        cachedRoadways.Value.ToList().ForEach(r => observer.OnNext(r));
                        observer.OnCompleted();
                    }, ex =>
                    {
                        observer.OnError(new Exception("Unable to retrieve traffic data.", ex));
                    });
                }
                else
                {
                    cachedRoadways.Value.ToList().ForEach(r => observer.OnNext(r));
                    observer.OnCompleted();
                }

                return Disposable.Empty;
            });
        }
        /// <summary>
        /// Gets the road closures.
        /// </summary>
        /// <param name="refreshData">if set to <c>true</c> [refresh data].</param>
        /// <returns></returns>
        public IObservable<RoadClosure> GetRoadClosures(bool refreshData)
        {
            var cachedRoadClosures = new CachedEntity<RoadClosure>("Services.RoadClosures");

            return new AnonymousObservable<RoadClosure>(observer =>
            {
                if (refreshData || !cachedRoadClosures.CachedDateTime.HasValue || cachedRoadClosures.CachedDateTime.Value <= DateTime.Now.AddMinutes(-15))
                {
                    IObservable<string> observable = ObservableHelper.TextFromUri(new Uri(DfwTranstarUri.BaseUri + "/mobile/roadclosures.aspx"));

                    observable.Subscribe(result =>
                    {
                        RoadClosure roadClosure = new RoadClosure();

                        if (result != null)
                        {
                            int spanStart = result.IndexOf("<span id=\"RCMessage\"");
                            int spanEnd = result.IndexOf("</span>", spanStart);
                            string message = string.Empty;

                            if (spanStart > 0)
                            {
                                message = result.Substring(spanStart + 21, spanEnd - spanStart - 21).Trim()
                                    .Replace("<br/>", "\n")
                                    .Replace("<br />", "\n")
                                    .Replace("</br>", "")
                                    .Replace("<b>", "")
                                    .Replace("</b>", "");
                            }

                            roadClosure.Closure = message;
                        }

                        cachedRoadClosures.Value = roadClosure;
                        cachedRoadClosures.Cache();

                        observer.OnNext(roadClosure);
                        observer.OnCompleted();
                    }, ex =>
                    {
                        observer.OnError(new Exception("Unable to retrieve traffic data.", ex));
                    },
                    () => { });
                }
                else
                {
                    observer.OnNext(cachedRoadClosures.Value);
                    observer.OnCompleted();
                }

                return Disposable.Empty;
            });
        }
        /// <summary>
        /// Gets the incidents.
        /// </summary>
        /// <param name="refreshData">if set to <c>true</c> [refresh data].</param>
        /// <returns></returns>
        public IObservable<Incident> GetIncidents(bool refreshData)
        {
            var cachedIncidents = new CachedEntity<List<Incident>>("Services.Incidents");

            return new AnonymousObservable<Incident>(observer =>
            {
                if (refreshData || !cachedIncidents.Value.Any() || cachedIncidents.CachedDateTime <= DateTime.Now.AddMinutes(-10))
                {
                    IObservable<string> observable = ObservableHelper.TextFromUri(new Uri(string.Format("{0}?CenterId={1}", DfwTranstarUri.IncidentsUri, TrafficCenter.DalTrans)));

                    var svc = observable.Subscribe(result =>
                    {
                        List<Incident> incidents;
                        int indexStart = result.IndexOf("<span id=\"LabelTime\"");
                        int indexEnd = result.IndexOf("</span>", indexStart);
                        var incidentTime = result.Substring(indexStart + 21, indexEnd - indexStart - 21);

                        indexStart = result.IndexOf("<ul id=\"IncidentList\"");

                        if (indexStart > 0)
                        {
                            indexEnd = result.IndexOf("</ul>", indexStart);

                            XElement xmlDoc = XElement.Parse(result.Substring(indexStart, (indexEnd + 5) - indexStart));

                            incidents = (from item in xmlDoc.Elements("li")
                                        select new Incident
                                        {
                                            Title = item.Value,
                                            PublishedDate = DateTime.Parse(string.Format("{0:d} {1}", DateTime.Today, incidentTime))
                                        }).ToList();
                        }
                        else
                        {
                            incidents = new List<Incident>();
                            incidents.Add(new Incident() { Title = "No incidents found",
                                PublishedDate = DateTime.Parse(string.Format("{0:d} {1}", DateTime.Today, incidentTime)) });
                        }

                        cachedIncidents.Value = incidents.ToList();
                        cachedIncidents.Cache();

                        incidents.ToList().ForEach(i => observer.OnNext(i));
                        observer.OnCompleted();
                    }, ex =>
                    {
                        observer.OnError(new Exception("Unable to retrieve traffic data.", ex));
                    });
                }
                else
                {
                    cachedIncidents.Value.ToList().ForEach(i => observer.OnNext(i));
                    observer.OnCompleted();
                }

                return Disposable.Empty;
            });
        }
        /// <summary>
        /// Gets the construction closures.
        /// </summary>
        /// <param name="roadway">The roadway.</param>
        /// <returns></returns>
        public IObservable<ConstructionClosure> GetConstructionClosures(string roadway)
        {
            var cachedConstructionClosures = new CachedEntity<ConstructionClosure>("Services.ConstructionClosures." + roadway.Replace(" ", "."));

            return new AnonymousObservable<ConstructionClosure>(observer =>
            {
                if (!cachedConstructionClosures.CachedDateTime.HasValue || cachedConstructionClosures.CachedDateTime.Value <= DateTime.Now.AddDays(-1))
                {
                    IObservable<string> observable = ObservableHelper.TextFromUri(new Uri(string.Format("{0}?roadway={1}",
                        DfwTranstarUri.ConstructionClosure, roadway.Replace(" ", "_"))));

                    observable.Subscribe(result =>
                    {
                        ConstructionClosure constructionClosure = new ConstructionClosure() { Roadway = roadway };

                        if (result != null)
                        {
                            int spanStart = result.IndexOf("<span id=\"CurrentConstruction\"");
                            int spanEnd = result.IndexOf("</span>", spanStart);
                            string message = string.Empty;

                            if (spanStart > 0)
                            {
                                message = result.Substring(spanStart + 31, spanEnd - spanStart - 31).Trim()
                                    .Replace("<br/>", "\n")
                                    .Replace("<br />", "\n")
                                    .Replace("</br>", ""); ;
                            }

                            constructionClosure.Message = message;
                        }

                        cachedConstructionClosures.Value = constructionClosure;
                        cachedConstructionClosures.Cache();

                        observer.OnNext(constructionClosure);
                        observer.OnCompleted();
                    }, ex =>
                    {
                        observer.OnError(new Exception("Unable to retrieve traffic data.", ex));
                    },
                    () => { });
                }
                else
                {
                    observer.OnNext(cachedConstructionClosures.Value);
                    observer.OnCompleted();
                }

                return Disposable.Empty;
            });
        }
        /// <summary>
        /// Gets the incidents.
        /// </summary>
        /// <param name="refreshData">if set to <c>true</c> [refresh data].</param>
        /// <returns></returns>
        public IObservable<Incident> GetIncidents(bool refreshData)
        {
            var cachedIncidents = new CachedEntity<List<Incident>>("Services.Incidents");

            return new AnonymousObservable<Incident>(observer =>
            {
                if (refreshData || !cachedIncidents.Value.Any() || cachedIncidents.CachedDateTime <= DateTime.Now.AddMinutes(-10))
                {
                    IObservable<string> observable = ObservableHelper.TextFromUri(new Uri(HoustonTranstarUri.IncidentsUri));

                    var svc = observable.Subscribe(result =>
                    {
                        XElement xmlDoc = XElement.Parse(result);

                        string title = (string)xmlDoc.Element("channel").Element("title");

                        var incidents = from item in xmlDoc.Element("channel").Elements("item")
                                        select new Incident
                                        {
                                            Title = (string)item.Element("title"),
                                            PublishedDate = item.Element("pubDate") != null ? ((DateTime)item.Element("pubDate")).ToLocalTime() : DateTime.MinValue
                                        };

                        cachedIncidents.Value = incidents.ToList();
                        cachedIncidents.Cache();

                        incidents.ToList().ForEach(i => observer.OnNext(i));
                        observer.OnCompleted();
                    }, ex =>
                    {
                        observer.OnError(new Exception("Unable to retrieve traffic data.", ex));
                    });
                }
                else
                {
                    cachedIncidents.Value.ToList().ForEach(i => observer.OnNext(i));
                    observer.OnCompleted();
                }

                return Disposable.Empty;
            });
        }