/// <summary>
        /// This function doesn't technically use wunderground's api. Instead it uses a normal web request to a csv file.
        /// A limitation of this approach is that we would have to read through each day and decide if a significant event happened
        /// on that day from the data given.
        /// Right now this function just returns all data for a given day.
        /// </summary>
        /// <returns>Weather Incidents for the location</returns>
        public IEnumerable<WeatherIncident> GetEvents(string airportCode, DateTime date, WeatherIncidentType? typeToFilter)
        {
            string requestUrl = string.Format(WeatherHistoryCsvUrl, airportCode, date.Year, date.Month,
                                              date.Day);
            string response = WebClient.DownloadString(requestUrl);

            return ParseWundergroundResponse(airportCode, response, date, typeToFilter);
        }
 public WeatherIncident(IEnumerable <Address> locations, WeatherIncidentType eventType
                        , DateTime date, Uri moreInformationUrl)
 {
     Locations          = locations;
     EventType          = eventType;
     Date               = date;
     MoreInformationUrl = moreInformationUrl;
 }
 public WeatherIncident(IEnumerable<Address> locations, WeatherIncidentType eventType
                         , DateTime date, Uri moreInformationUrl)
 {
     Locations = locations;
     EventType = eventType;
     Date = date;
     MoreInformationUrl = moreInformationUrl;
 }
        private static IEnumerable <WeatherIncident> ParseWundergroundResponse(string airportCode, string responseString, DateTime date, WeatherIncidentType?typeToFilter)
        {
            var     moreInfoUrl       = new Uri(string.Format(WeatherHistoryUrl, airportCode, date.Year, date.Month, date.Day));
            Airport currentAirpot     = AirportList.GetAirport(airportCode);
            var     locationOfAirport = Address.Search(string.Empty, currentAirpot.City, currentAirpot.State.Abbreviation, string.Empty, false);

            // Remove HTML comments and line breaks
            responseString =
                Regex.Replace(responseString, "<!--.*?-->", string.Empty, RegexOptions.Singleline).Replace("<br />", "");

            IEnumerable <string> rows = responseString.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);

            rows = rows.Skip(1); // Skip header row


            var incidents = new List <WeatherIncident>();

            foreach (string row in rows)
            {
                var entry = new WeatherUndergroundEntry(date, row);
                WeatherIncidentType incidentType = WeatherIncidentClassifier.Classify(entry);
                if (typeToFilter != null)
                {
                    if (incidentType == typeToFilter)
                    {
                        incidents.Add(new WeatherIncident(locationOfAirport, incidentType,
                                                          date, moreInfoUrl));
                    }
                }
                else
                {
                    if (incidentType != WeatherIncidentType.Unclassified)
                    {
                        incidents.Add(new WeatherIncident(locationOfAirport, incidentType,
                                                          date, moreInfoUrl));
                    }
                }
            }
            return(incidents);
        }
        private static IEnumerable<WeatherIncident> ParseWundergroundResponse(string airportCode, string responseString, DateTime date, WeatherIncidentType? typeToFilter)
        {
            var moreInfoUrl = new Uri(string.Format(WeatherHistoryUrl, airportCode, date.Year, date.Month, date.Day));
            Airport currentAirpot = AirportList.GetAirport(airportCode);
            var locationOfAirport = Address.Search(string.Empty, currentAirpot.City, currentAirpot.State.Abbreviation, string.Empty, false);

            // Remove HTML comments and line breaks
            responseString =
                Regex.Replace(responseString, "<!--.*?-->", string.Empty, RegexOptions.Singleline).Replace("<br />", "");

            IEnumerable<string> rows = responseString.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
            rows = rows.Skip(1); // Skip header row

            var incidents = new List<WeatherIncident>();
            foreach (string row in rows)
            {
                var entry = new WeatherUndergroundEntry(date, row);
                WeatherIncidentType incidentType = WeatherIncidentClassifier.Classify(entry);
                if (typeToFilter != null)
                {
                    if (incidentType == typeToFilter)
                    {
                        incidents.Add(new WeatherIncident(locationOfAirport, incidentType,
                                                          date, moreInfoUrl));
                    }
                }
                else
                {
                    if (incidentType != WeatherIncidentType.Unclassified)
                    {
                        incidents.Add(new WeatherIncident(locationOfAirport, incidentType,
                                                          date, moreInfoUrl));
                    }
                }

            }
            return incidents;
        }
        public IEnumerable<WeatherIncident> GetEvents(State state, string county, DateTime startDate, DateTime endDate, WeatherIncidentType? filter)
        {
            // hardcoded url that we scrape the data from
            const string baseNcdcUrl = "http://www4.ncdc.noaa.gov/cgi-win/wwcgi.dll?wwevent~storms";

            // the post parameters for making the call
            string parameters =
                string.Format("bdate={0}%2F{1}%2F{2}&edate={3}%2F{4}%2F{5}&STATE={6}&County={7}&ETYPE=*All&fscale=*All&hamt=&wspd=&injuries=&deaths=&pdamage=&cdamage=&Send=List+Storms"
                              , startDate.Month, startDate.Day, startDate.Year, endDate.Month, endDate.Day, endDate.Year, state.Abbreviation, county);
            byte[] postData = Encoding.ASCII.GetBytes(parameters);

            // make a POST request to the url with the parameters given
            var request = WebRequest.Create(baseNcdcUrl) as HttpWebRequest;
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = postData.Length;

            // write the post data
            Stream requestStream = request.GetRequestStream();
            requestStream.Write(postData, 0, postData.Length);
            requestStream.Close();

            // load the html response
            HtmlNode node;
            using (var response = request.GetResponse() as HttpWebResponse)
            {
                var reader = new StreamReader(response.GetResponseStream());

                var doc = new HtmlDocument();
                doc.LoadHtml(reader.ReadToEnd());

                // the description below is the best I could find in xpath that would describe the table of weather events
                // we may want to pull the string out into a config file
                node =
                    doc.DocumentNode.SelectSingleNode(
                        "//table[@summary='This Table displays the Events Query output by state and date.']");
            }

            if (node != null)
            {
                // This goes through each row and pulls out the location and event type
                // This is fragile because we are depending on the html of the response

                var returnValues =
                    (from weatherEvent in node.SelectNodes("tr")
                     where weatherEvent.SelectSingleNode("td[@headers]") != null
                     let location = weatherEvent.SelectSingleNode("td[@headers='h1']/a").InnerText.Trim()
                     select
                         new WeatherIncident(
                         Address.Search(_zoneLookup.IsZone(location) ? location : location + ", " + state.Abbreviation),
                         WeatherIncidentClassifier.Classify(
                             weatherEvent.SelectSingleNode("td[@headers='h4']").InnerText.Trim()),
                         DateTime.Parse(
                             weatherEvent.SelectSingleNode("td[@headers='h2']").InnerText.Trim()),
                         new Uri(
                             weatherEvent.SelectSingleNode("td[@headers='h1']/a").Attributes["href"].Value.Trim()))
                    );

                if(filter != null)
                {
                    returnValues =
                        (from weatherEvent in returnValues
                         where weatherEvent.EventType == filter
                         select weatherEvent);
                }
                return returnValues;
            }
            return new WeatherIncident[0];
        }