} // Plot

        public int CompareTo(object obj)
        {
            Quake other = obj as Quake;

            return(-this.age.CompareTo(other.age));
        }
        static public void Main(string[] args)
        {
            Console.WriteLine("quakemap running in " + Environment.CurrentDirectory);

            options = new Options(args);

            Console.WriteLine("Options:");
            Console.WriteLine("    width:    " + options.width);
            Console.WriteLine("    height:   " + options.height);
            Console.WriteLine("    mercator: " + options.mercator);
            Console.WriteLine("    quakeData:");
            foreach (string s in options.quakeData)
            {
                Console.WriteLine("        \"" + s + "\"");
            }
            Console.WriteLine("    shoreData:");
            foreach (string s in options.shoreData)
            {
                Console.WriteLine("        \"" + s + "\"");
            }
            Console.WriteLine("    imageFile:");
            foreach (string s in options.imageFile)
            {
                Console.WriteLine("        \"" + s + "\"");
            }

            using (StreamReader reader = OpenStream(options.quakeData))
            {
                string line1 = reader.ReadLine();
                if (line1 == null)
                {
                    Console.WriteLine("No line 1");
                }
                else
                {
                    string[] headers = line1.Split(new char[] { ',' }, StringSplitOptions.None);
                    for (int i = 0; i < headers.Length; i++)
                    {
                        Console.Write(headers[i]);
                        if (i < headers.Length - 1)
                        {
                            Console.Write('|');
                        }
                    }
                    Console.WriteLine();
                }

                string pattern = "^";
                for (int i = 0; i <= 9; i++)
                {
                    if (i == 3 || i == 9)
                    {
                        pattern += "\"([^\"]*)\"";
                    }
                    else
                    {
                        pattern += "([^,]*)";
                    }
                    if (i < 9)
                    {
                        pattern += ",";
                    }
                }
                pattern += "$";
                Console.WriteLine("pattern = \"" + pattern + "\"");
                Regex line_re = new Regex(pattern);

                string    line;
                int       lineCount = 0;
                ArrayList quakes    = new ArrayList();
                while ((line = reader.ReadLine()) != null)
                {
                    lineCount++;
                    Match m = line_re.Match(line);
                    if (m.Success)
                    {
                        Quake q = new Quake();
                        q.src      = m.Groups[1].Value;
                        q.eqid     = m.Groups[2].Value;
                        q.version  = m.Groups[3].Value;
                        q.datetime = m.Groups[4].Value;
                        double lat = Convert.ToDouble(m.Groups[5].Value);
                        double lon = Convert.ToDouble(m.Groups[6].Value);
                        q.position  = new Position(lon, lat);
                        q.magnitude = Convert.ToDouble(m.Groups[7].Value);
                        q.depth     = Convert.ToDouble(m.Groups[8].Value);
                        // q.nst       = Convert.ToInt32(m.Groups[9].Value);
                        q.region = m.Groups[10].Value;
                        bool ok = DateTime.TryParseExact
                                      (q.datetime,
                                      Constants.dateFormat,
                                      Constants.enUS,
                                      Constants.dateStyle,
                                      out q.dt);
                        if (ok)
                        {
                            q.age = Constants.now.Subtract(q.dt);
                            if (q.dt < Quake.oldest)
                            {
                                Quake.oldest = q.dt;
                            }
                        }
                        else
                        {
                            q.dt = DateTime.MinValue;
                        }
                        quakes.Add(q);
                    }
                    else
                    {
                        Console.WriteLine("Line \"" + line + "\" does not match Regex " + line_re);
                        Environment.Exit(1);
                    }
                }
                Quake.oldestInDays = Constants.now.Subtract(Quake.oldest).TotalDays;

                Console.WriteLine("Got " + lineCount + " lines, " + quakes.Count + " earthquakes");
                Console.WriteLine("Oldest: " + Quake.oldest.ToString() + ", " + Quake.oldestInDays + " days ago");

                double   minLat       = Double.MaxValue;
                double   maxLat       = Double.MinValue;
                double   minLon       = Double.MaxValue;
                double   maxLon       = Double.MinValue;
                double   minMagnitude = Double.MaxValue;
                double   maxMagnitude = Double.MinValue;
                TimeSpan minAge       = TimeSpan.MaxValue;
                TimeSpan maxAge       = TimeSpan.MinValue;
                quakes.Sort(); // plot older quakes first
                foreach (Quake q in quakes)
                {
                    if (q.position.lat < minLat)
                    {
                        minLat = q.position.lat;
                    }
                    if (q.position.lat > maxLat)
                    {
                        maxLat = q.position.lat;
                    }
                    if (q.position.lon < minLon)
                    {
                        minLon = q.position.lon;
                    }
                    if (q.position.lon > maxLon)
                    {
                        maxLon = q.position.lon;
                    }
                    if (q.magnitude < minMagnitude)
                    {
                        minMagnitude = q.magnitude;
                    }
                    if (q.magnitude > maxMagnitude)
                    {
                        maxMagnitude = q.magnitude;
                    }
                    if (q.age < minAge)
                    {
                        minAge = q.age;
                    }
                    if (q.age > maxAge)
                    {
                        maxAge = q.age;
                    }
                }
                if (quakes.Count > 0)
                {
                    Console.WriteLine("Lat: " + minLat + " .. " + maxLat);
                    Console.WriteLine("Lon: " + minLon + " .. " + maxLon);
                    Console.WriteLine("Magnitude: " + minMagnitude + " .. " + maxMagnitude);
                    Console.WriteLine("Age: " + minAge + " .. " + maxAge);
                }

                Bitmap bitmap;
                try
                {
                    bitmap = new Bitmap(options.width, options.height);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Exception creating bitmap: " + e);
                    bitmap = null;
                    Environment.Exit(1);
                }

                Console.WriteLine("Initializing blank screen");
                for (int y = 0; y < options.height; y++)
                {
                    for (int x = 0; x < options.width; x++)
                    {
                        bitmap.SetPixel(x, y, Constants.bgColor);
                    }
                }

                Console.WriteLine("Setting shores");
                StreamReader shores = OpenStream(options.shoreData);
                string       shore;
                int          shorePoints = 0;
                int          shorePixels = 0;
                while ((shore = shores.ReadLine()) != null)
                {
                    try
                    {
                        string[] words = shore.Split(new Char[] { ' ' });
                        double   lat   = Convert.ToDouble(words[0]);
                        double   lon   = Convert.ToDouble(words[1]);
                        if (lon < -180)
                        {
                            lon += 360;
                        }
                        if (lon > +180)
                        {
                            lon -= 360;
                        }
                        Point p = new Point(new Position(lon, lat));
                        shorePoints++;
                        if (bitmap.GetPixel(p.x, p.y).ToArgb() != Constants.shoreARGB)
                        {
                            bitmap.SetPixel(p.x, p.y, Constants.shoreColor);
                            shorePixels++;
                        }
                    }
                    catch
                    {
                        // Ignore input errors
                    }
                }
                double percentage = (double)shorePixels / (double)shorePoints * 100.0;
                Console.WriteLine("Plotted " + shorePixels + " pixels for " + shorePoints + " points" +
                                  " (" + percentage.ToString("0.##") + "%)");

                Console.WriteLine("Drawing meridians of longitude");
                for (int ilon = -180; ilon <= 180; ilon += 15)
                {
                    for (Position pos = new Position((double)ilon, 90.0);
                         !pos.isNull;
                         pos = pos.NextPixelSouth())
                    {
                        Point p = new Point(pos);
                        if (p.x < options.width && p.y < options.height)
                        {
                            // Console.WriteLine("Plot " + p);
                            bitmap.SetPixel(p.x, p.y, Constants.axisColor);
                        }
                    }
                }

                Console.WriteLine("Drawing parallels of latitude");
                for (int ilat = -90; ilat <= 90; ilat += 15)
                {
                    for (Position pos = new Position(-180.0, (double)ilat);
                         !pos.isNull;
                         pos = pos.NextPixelEast())
                    {
                        Point p = new Point(pos);
                        if (p.x < options.width && p.y < options.height)
                        {
                            bitmap.SetPixel(p.x, p.y, Constants.axisColor);
                        }
                    }
                }

                Console.WriteLine("Iterating over quakes");
                foreach (Quake q in quakes)
                {
                    q.Plot(bitmap);
                }

                SaveBitmapToPng(bitmap, options.imageFile);
            }
        } // Main
 public Point(Quake q)
 {
     this = new Point(q.position);
 }