using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.IO;
using System.Xml;

namespace UtmConvert {
    public class Parser {



        private string _fileName;
        protected string FileName {
            get { return _fileName; }
        }

        protected string _fileString;
        public string FileString {
            get { return _fileString; }
        }
        public Parser() {

        }

        public Parser(string fileName) {
            _fileName = fileName;
        }

        public void readFile(string fileName) {
            _fileName = fileName;
            if (File.Exists(fileName)) {
                StreamReader sRead = new StreamReader(fileName);
                _fileString = sRead.ReadToEnd();
                sRead.Close();
            }
        }

    }

    public class XmlParser : Parser {

		public delegate void updateErrorEventHandler(Exception error);
		public event updateErrorEventHandler updateErrorEvent;

        string _datum = "NAD83/WGS84";

        string _format = "";
        public string Format {
            get { return _format; }
        }

        string _note = "";
        public string Note {
            get { return _note; }
        }

        string _status = "ok";
        public string Status {
            get { return _status; }
        }

        ConvertLatLonUtm con;
        public XmlParser() {
            con = new ConvertLatLonUtm();
        }

        private bool datumMatch(Datum d) {
            return d.Name == _datum;
        }

        List<UtmPointSet> _utmPointSetList;
        public List<UtmPointSet> UtmPointSetList {
            get { return _utmPointSetList; }
        }

        List<LatLonPointSet> _latLonPointSetList;
        public List<LatLonPointSet> LatLonPointSetList {
            get { return _latLonPointSetList; }
        }

        public void Parse(string format) {
			try {
				XmlDocument doc = new XmlDocument();
				doc.LoadXml(_fileString);
				_utmPointSetList = new List<UtmPointSet>();
				_latLonPointSetList = new List<LatLonPointSet>();
				foreach (XmlNode node in doc.ChildNodes) {
					if (node.Name == "lat_lon_point_set") {
						UtmPointSet ps1 = new UtmPointSet();
						LatLonPointSet ps2 = new LatLonPointSet();
						ps1.LocationName = node.Attributes[0].Value;
						ps1.Datum = node.Attributes[1].Value;
						foreach (XmlNode n in node) {
							ps2.Points.Add(new LatLonPoint(double.Parse(
								n.Attributes[0].Value), n.Attributes[1].Value
								, double.Parse(n.Attributes[2].Value)
								, n.Attributes[3].Value, format
								, n.Attributes[4].Value, n.Attributes[5].Value));
							if (_status != "ok") break;
							if (n.Name == "ddd_dd" || n.Name == "ddd_mm_mm"
								|| n.Name == "ddd_mm_ss_ss") {
								ps1.Points.Add(new UtmPoint(convertLatLonToUtm
									(n.Attributes[0].Value, n.Attributes[1].Value[0],
									 n.Attributes[2].Value, n.Attributes[3].Value[0]
									, n.Name, node.Attributes[1].Value), con.Zone
									, n.Attributes[4].Value, n.Attributes[5].Value));
							}
						}
						_utmPointSetList.Add(ps1);
						_latLonPointSetList.Add(ps2);
					} else if (node.Name == "utm_point_set") {
						UtmPointSet ps1 = new UtmPointSet();
						LatLonPointSet ps2 = new LatLonPointSet();
						ps2.LocationName = node.Attributes[0].Value;
						ps2.Datum = node.Attributes[1].Value;
						foreach (XmlNode n in node) {
							if (_status != "ok") break;
							if (n.Name == "dd_dd") {

								ps1.Points.Add(new UtmPoint(new Point(double.Parse(
									n.Attributes[0].Value), double.Parse(
									n.Attributes[1].Value)), n.Attributes[2].Value
									, n.Attributes[3].Value, n.Attributes[4].Value));

								con.convertUtmToLatLon
									(double.Parse(n.Attributes[0].Value)
									, double.Parse(n.Attributes[1].Value)
									, n.Attributes[2].Value);
								string ns = "N", ew = "E";
								if (con.Latitude < 0) ns = "S";
								if (con.Longitude < 0) ew = "W";
								ps2.Points.Add(new LatLonPoint(con.Latitude
									, ns, con.Longitude, ew, format
									, n.Attributes[3].Value
									, n.Attributes[4].Value));
							}
						}
						_utmPointSetList.Add(ps1);
						_latLonPointSetList.Add(ps2);
					}
				}
			} catch (Exception e) {
				if (updateErrorEvent != null)
					updateErrorEvent.Invoke(e);
				_status = "Invalid input, malformed data: " + e.Message
					+ "\r\n" + e.StackTrace;
			}
        }

        public Point convertLatLonToUtm(string lat, char ns, string lon
            , char ew, string format, string datum) {
            _datum = datum;
            _status = "ok";
            _format = format;
            Point pt = new Point(-1, -1);
            double radLat = 0, radLon = 0;
            try {
                con.Datum = Datums.datumList.Find(datumMatch);
                if((ns != 'N' && ns != 'S') || (ew != 'E' && ew != 'W'))
                    throw new Exception("Direction string wrong format");
                if (format == "ddd_dd") { //degrees decimal degrees
                    radLat = ConvertDegRad.getRadians(lat, ns);
                    if (ConvertDegRad.Status != "ok")
                        throw new Exception(ConvertDegRad.Status);
                    radLon = ConvertDegRad.getRadians(lon, ew);
                } else if (format == "ddd_mm_mm") {
                    string s = lat;
                    string f1 = s.Substring(0, s.IndexOf(" "));
                    string f2 = s.Substring(s.IndexOf(" ") + 1,
                        (s.Length - s.IndexOf(" ")) - 1);
                    s = lon;
                    string f3 = s.Substring(0, s.IndexOf(" "));
                    string f4 = s.Substring(s.IndexOf(" ") + 1,
                        (s.Length - s.IndexOf(" ") - 1));
                    radLat = ConvertDegRad.getRadians(f1, f2, ns);
                    if (ConvertDegRad.Status != "ok")
                        throw new Exception(ConvertDegRad.Status);
                    radLon = ConvertDegRad.getRadians(f3, f4, ew);
                } else if (format == "ddd_mm_ss_ss") {
                    string s = lat;
                    string f1 = s.Substring(0, s.IndexOf(" "));
                    string f2 = s.Substring(s.IndexOf(" ") + 1, (s.IndexOf(" "
                        , s.IndexOf(" ")) - s.IndexOf(" ") + 1));
                    string f3 = s.Substring(s.IndexOf(" ", s.IndexOf(" ") + 1) + 1
                        , s.Length - s.IndexOf(" ", s.IndexOf(" ") + 1) - 1);
                    s = lon;
                    string f4 = s.Substring(0, s.IndexOf(" "));
                    string f5 = s.Substring(s.IndexOf(" ") + 1, (s.IndexOf(" "
                        , s.IndexOf(" ")) - s.IndexOf(" ") + 1));
                    string f6 = s.Substring(s.IndexOf(" ", s.IndexOf(" ") + 1) + 1
                        , s.Length - s.IndexOf(" ", s.IndexOf(" ") + 1) - 1);
                    radLat = ConvertDegRad.getRadians(f1, f2, f3, ns);
                    if (ConvertDegRad.Status != "ok")
                        throw new Exception(ConvertDegRad.Status);
                    radLon = ConvertDegRad.getRadians(f4, f5, f6, ew);
                }
                if ((format == "ddd_dd" || format == "ddd_mm_mm"
                    || format == "ddd_mm_ss_ss") && ConvertDegRad.Status == "ok") {
                    con.convertLatLonToUtm(radLat, radLon);
                    pt = new Point(con.x, con.y);
                    return pt;
                }
                _status = "Invalid input, malformed data";
                return pt;
            } catch (Exception e) {
				if (updateErrorEvent != null)
					updateErrorEvent.Invoke(e);
                _status = "Invalid input, malformed data: " + e.Message
					+ "\r\n" + e.StackTrace;
                return pt;
            }
        }
    }
}