namespace Binge.Parsers
{
	using System;
	using System.Collections;
	using System.Xml;

	public abstract class Parser: Binge.Bits.Object
	{
		private XmlTextReader reader;
		private string filename;
		private bool parseThrottled;
		private bool parsePrivate;
		private bool parseProtected;
		private bool showWarnings;
		private Hashtable namespaces;

		public bool ParseThrottled
		{
			get { return parseThrottled; }
			set { parseThrottled = value; }
		}

		public bool ParsePrivate
		{
			get { return parsePrivate; }
			set { parsePrivate = value; }
		}

		public bool ParseProtected
		{
			get { return parseProtected; }
			set { parseProtected = value; }
		}

		public bool ShowWarnings
		{
			get { return showWarnings; }
			set { showWarnings = value; }
		}

		public Hashtable Namespaces
		{
			get { return namespaces; }
			set { namespaces = value; }
		}

		public string Filename
		{
			get { return filename; }
			set { filename = value; }
		}

		protected XmlNodeType NodeType
		{
			get { return reader.NodeType; }
		}

		protected string Name
		{
			get { return reader.Name; }
		}

		protected bool IsEmptyAttribute
		{
			get { return reader.IsEmptyElement; }
		}

		protected Parser ()
		{
			filename = String.Empty;
			parseThrottled = false;
			parsePrivate = false;
			showWarnings = false;
			namespaces = new Hashtable ();
		}

		protected Parser (string file): this ()
		{
			filename = file;
		}

		protected Parser (string file, Hashtable ns)
		{
			filename = file;
			namespaces = ns;
		}

		public abstract void Parse ();

		// Wrapped XmlTextReader methods

		protected void Open (string file)
		{
			reader = new XmlTextReader (file);
			reader.WhitespaceHandling = WhitespaceHandling.None;
			// reader.Normalization = true; // FIXME Not implemented in Mono
			filename = file;
		}

		protected void Close ()
		{
			reader.Close ();
			filename = String.Empty;
		}

		protected bool Read ()
		{
			return reader.Read ();
		}

		protected string GetAttribute (string attr)
		{
			string r = reader[attr];
			return r != null ? r : String.Empty;
		}

		protected string this [string a]
		{
			get { return GetAttribute (a); }
		}

		protected void Skip ()
		{
			reader.Skip ();
		}

		// Debugging helper methods

		protected void XmlDbg (string format, params object[] arg)
		{
			if (showWarnings)
			{
				format = "Warning: " + filename + ": " + reader.LineNumber  + ": " + format;
				Outl (format, arg);
			}
		}

		protected void XmlDbg (string format)
		{
			XmlDbg ("{0}", format);
		}

		protected void RequiredTagMissing (string tag, bool thr)
		{
			if (thr)
				throw new ApplicationException
					(filename + ":" + reader.LineNumber + ": Required element missing: " + tag);
			else
				XmlDbg ("Required element missing: <{0}>", tag);
		}

		protected void RequiredAttrMissing (string attr, bool thr)
		{
			if (thr)
				throw new ApplicationException
					(filename + ":" + reader.LineNumber + ": Required attribute missing: " + attr);
			else
				XmlDbg (filename, reader.LineNumber, "Required attribute missing: {0}", attr);
		}

		protected void UnexpectedTag (string tag)
		{
			XmlDbg ("Unexpected or unknown element: {0}", tag);
		}

		protected void ExpectedTag (string expected, string found)
		{
			XmlDbg ("Expected element '{0}' but found '{1}'", expected, found);
		}

		protected void UnexpectedAttr (string attr, string value)
		{
			XmlDbg ("Unexpected value for attribute {0}: {1}", attr, value);
		}

		protected void UnexpectedNesting (string name)
		{
			XmlDbg ("Unsupported nesting of {0} element", name);
		}
	}
}
