OpenTemp.ParseGHCNv2()

        /// <summary>
        /// Read the data file and parse into the list of samples.
        /// </summary>
        /// <returns>Number of samples parsed if successful; -ve for error code</returns>
        protected int ParseGHCNv2()
        {
            OpenTemp.WriteLine(string.Format("Reading the data file '{0}'...", _dataFile));
            // Open the file
            StreamReader sr;
            try
            {
                sr = new StreamReader(_dataFile, true);
                OpenTemp.WriteLine("  File opened for reading");
            }
            catch (Exception ex)
            {
                OpenTemp.WriteLine(string.Format("  Exception thrown when opening file:  {0}", ex.ToString()));
                return -1;
            }
            if (sr == null)
            {
                OpenTemp.WriteLine("  Failed to open file (check that it exists and the path is correct)");
                return -2;
            }
           

            // Parse one line at a time
            int nLinesTotal = 0;
            int nLinesParsed = 0;
            int expectedLength = 76;
            while (!sr.EndOfStream)
            {
                nLinesTotal++;

                string line = sr.ReadLine();
                if (line.Length != expectedLength)
                {
                    OpenTemp.WriteLine(string.Format("  Line {0}: Wrong number of characters ({1}, expected {2})", nLinesTotal + 1, line.Length, expectedLength));
                    sr.Dispose();
                    return -4;
                }

                string countryStation = line.Substring(0, 11);
                if (!_stations.ContainsKey(countryStation)) continue;
                Station station = _stations[countryStation];

                string seriesText = line.Substring(11, 1);
                byte series;
                bool seriesOk = byte.TryParse(seriesText, out series);
                if (!seriesOk)
                {
                    OpenTemp.WriteLine(string.Format("  Line {0}: Failed to parse series # {1}", nLinesTotal + 1, seriesText));
                    sr.Dispose();
                    return -5;
                }
                if (!station.ContainsSeries(series))
                {
                    station.AddSeries(series);
                }
                SortedList<DateTime, float?> values = station.GetReadings(series);

                int year = 0;
                string yearString = line.Substring(12, 4);
                bool yearOk = int.TryParse(yearString, out year);
                if (!yearOk)
                {
                    OpenTemp.WriteLine(string.Format("  Line {0}: Error parsing year '{1}'", nLinesTotal + 1, yearString));
                    sr.Dispose();
                    return -6;
                }
                // Loop over all months
                for (int iMonth = 1; iMonth <= 12; iMonth++)
                {
                    DateTime date = new DateTime(year, iMonth, 1);

                    // Parse value
                    short value = -9999;
                    string valueString = line.Substring(16 + (iMonth - 1) * 5, 5);
                    bool valueOk = short.TryParse(valueString, out value);
                    if (!valueOk)
                    {
                        OpenTemp.WriteLine(string.Format("  Line {0}: Failed to parse value '{1}'", nLinesTotal + 1, valueString));
                        sr.Dispose();
                        return -7;
                    }

                    // Store sample
                    try
                    {
                        if ((value > -1000) && (value < +1000))
                        {
                            values.Add(new DateTime(year, iMonth, 1), 0.1f * (float)value);     // Convert from tenths to real degrees
                        }
                        else
                        {
                            values.Add(new DateTime(year, iMonth, 1), null);                    // No reading
                        }
                    }
                    catch
                    {
                        OpenTemp.WriteLine(string.Format("  DUPLICATE station year: Station {0}, Series {1}, Year {2}", countryStation, series, year));
                        break;
                    }
                }

                // Increment and continue
                nLinesParsed++;
                if ((nLinesTotal % 100000) == 0)
                {
                    OpenTemp.WriteLine(string.Format("  Parsing progress: {0} of {1} lines parsed", nLinesParsed, nLinesTotal));
                }
            }

            // Cleanup
            sr.Dispose();

            // Done
            OpenTemp.WriteLine(string.Format("  Parsing finished: {0} of {1} lines parsed", nLinesParsed, nLinesTotal));
            return 12*nLinesParsed;
        }