// A Qt to C# binding generator.
//
// Copyright (C) 2002  Adam Treat (manyoso@yahoo.com)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

using System;
using System.Collections;
using System.IO;
using System.Xml;

namespace QtCSharp {

	public class Parser {

		XmlTextReader xtr;
		QType qtype;

		public Parser (string xmlFragment)
		{
			qtype = new QType ();
			XmlNameTable nt = new NameTable ();
			XmlNamespaceManager nsMgr = new XmlNamespaceManager (nt);
			XmlParserContext parserContext = new XmlParserContext (null, nsMgr, null, XmlSpace.None);
			xtr = new XmlTextReader (xmlFragment, XmlNodeType.Document, parserContext);
			Parse ();
			OverLoad ();
			NewQCtors ();
		}

		public QType GetQType ()
		{
			return qtype;
		}

		public void Parse ()
		{
			while(xtr.Read ()) {
				if (xtr.NodeType != XmlNodeType.EndElement) {
					switch (xtr.Name) {
						case "qtype":
							ParseQType ();
							continue;
						case "qancestor":
							ParseQAncestor ();
							continue;
						case "qenum":
							ParseQEnum ();
							continue;
						case "qctor":
							ParseQCtor ();
							continue;
						case "qdctor":
							ParseQDCtor ();
							continue;
						case "qmethod":
							ParseQMethod ();
							continue;
						default:
							continue;
					}
				}
			}
		}

		public void NewQCtors ()
		{
			// A ctor for inherited classes
			QCtor _qctor = new QCtor();
			_qctor.Name = qtype.Name;
			_qctor.Access = "internal";
			_qctor.Inherited = true;
			qtype.AddQCtor(_qctor);

			// A ctor for type boxing
			QCtor __qctor = new QCtor();
			__qctor.Name = qtype.Name;
			__qctor.Access = "internal";
			__qctor.Boxer = true;
			QParam qparam = new QParam();
			qparam.Type = "IntPtr";
			qparam.Name = "_ptr";
			__qctor.AddCSharpParam(qparam);
			qtype.AddQCtor(__qctor);

			// A dummy ctor
			QCtor ___qctor = new QCtor();
			___qctor.Name = qtype.Name;
			___qctor.Access = "internal";
			___qctor.Dummy = true;
			QParam ___qparam = new QParam();
			___qparam.Type = "QNull";
			___qparam.Name = "dummy";
			___qctor.AddCSharpParam(___qparam);
			qtype.AddQCtor(___qctor);
		}

		public void OverLoad ()
		{
			ArrayList additions = new ArrayList ();

			foreach (QCtor qctor in qtype.QCtors){
				foreach (QParam pinvokeparam in qctor.PinvokeParams) {
					if (pinvokeparam.Default != null) {
						QCtor _qctor = new QCtor();
						_qctor.Name = qctor.Name;
						_qctor.Access = qctor.Access;
						_qctor.Overload = true;
						for (int j = 0; j < qctor.PinvokeParams.IndexOf(pinvokeparam)+1; j++) {
							_qctor.AddPinvokeParam((QParam)qctor.PinvokeParams[j]);
							_qctor.AddPinvokeCallParam((QParam)qctor.PinvokeCallParams[j]);
							_qctor.AddCSharpParam((QParam)qctor.CSharpParams[j]);
							_qctor.AddOverloadParam((QParam) (( QParam) qctor.CSharpParams[j]).Clone());
						}
						_qctor.CSharpParams.RemoveAt(_qctor.CSharpParams.Count-1);
						//qtype.AddQCtor(_qctor);
						additions.Add (_qctor);
					}
				}
			}

			foreach (QCtor ctor in additions) qtype.AddQCtor (ctor);
			additions = new ArrayList ();

			foreach (QMethod qmethod in qtype.QMethods){
				foreach (QParam pinvokeparam in qmethod.PinvokeParams) {
					if (pinvokeparam.Default != null) {
						QMethod _qmethod = new QMethod();
						_qmethod.Name = qmethod.Name;
						_qmethod.Access = qmethod.Access;
						_qmethod.Return = qmethod.Return;
						_qmethod.Overload = true;
						for (int j = 0; j < qmethod.PinvokeParams.IndexOf(pinvokeparam)+1; j++) {
							_qmethod.AddPinvokeParam((QParam)qmethod.PinvokeParams[j]);
							_qmethod.AddPinvokeCallParam((QParam)qmethod.PinvokeCallParams[j]);
							_qmethod.AddCSharpParam((QParam)qmethod.CSharpParams[j]);
							_qmethod.AddOverloadParam((QParam) ((QParam) qmethod.CSharpParams[j]).Clone());

						}
						_qmethod.CSharpParams.RemoveAt(_qmethod.CSharpParams.Count-1);
						//qtype.AddQMethod(_qmethod);
						additions.Add (_qmethod);
					}
				}
			}

			foreach (QMethod method in additions) qtype.AddQMethod (method);
		}

		public void ParseQType ()
		{
			if (xtr.MoveToAttribute("name")) {
				qtype.Name = xtr.Value;
			}

			if (xtr.MoveToAttribute("access")) {
				qtype.Access = xtr.Value;
			}
		}

		public void ParseQAncestor ()
		{
			QAncestor qancestor = new QAncestor();
			if (xtr.MoveToAttribute("name")) {
				qancestor.Name = xtr.Value;
			}
			qtype.AddQAncestor(qancestor);
		}

		public void ParseQEnum ()
		{
			bool match = false;
			QEnum qenum = new QEnum();
			if (xtr.MoveToAttribute("name"))
				qenum.Name = xtr.Value;
			if (xtr.MoveToAttribute("access"))
				qenum.Access = xtr.Value;
			while (xtr.Read()) {
				if (xtr.Name == "qitem") {
					QItem qitem = ParseQItem();
					qenum.AddQItem(qitem);
					long parse = 0;
					try {
						parse = Int64.Parse(qitem.Value);
					} catch {
					}
					if (parse >= 2147483647)
						qenum.Type = "uint";
				} else if (xtr.Name == "") {
				} else {
					break;
				}
			}
			qtype.AddQEnum(qenum);
		}

		public void ParseQCtor ()
		{
			bool IsEmpty = xtr.IsEmptyElement;
			QCtor qctor = new QCtor();
			if (xtr.MoveToAttribute("name")) {
				qctor.Name = xtr.Value;
			}
			if (xtr.MoveToAttribute("access")) {
				qctor.Access = xtr.Value;
			}
			if (xtr.MoveToAttribute("id")) {
				qctor.Id = xtr.Value;
			}
			if (!IsEmpty) {
				while (xtr.Read()) {
					if (xtr.Name == "qparam") {
						qctor.AddPinvokeParam(ParseQParam());
						qctor.AddPinvokeCallParam(ParseQParam());
						qctor.AddCSharpParam(ParseQParam());
					} else if (xtr.Name == ""){
					} else {
						break;
					}
				}
			}
			qtype.AddQCtor(qctor);
		}

		public void ParseQDCtor ()
		{
			bool IsEmpty = xtr.IsEmptyElement;
			QDCtor qdctor = new QDCtor();
			if (xtr.MoveToAttribute("name")) {
				qdctor.Name = xtr.Value;
			}
			if (xtr.MoveToAttribute("access")) {
				qdctor.Access = xtr.Value;
			}
			if (!IsEmpty) {
				while (xtr.Read()) {
					if (xtr.Name == "qparam") {
						qdctor.AddQParam(ParseQParam());
					} else if (xtr.Name == "") {
					} else {
						break;
					}
				}
			}
			qtype.AddQDCtor(qdctor);
		}

		public void ParseQMethod ()
		{
			bool IsEmpty = xtr.IsEmptyElement;
			QMethod qmethod = new QMethod();
			if (xtr.MoveToAttribute("name")) {
				qmethod.Name = xtr.Value;
			}
			if (xtr.MoveToAttribute("access")) {
				qmethod.Access = xtr.Value;
			}
			if (xtr.MoveToAttribute("return")) {
				qmethod.Return = xtr.Value;
			}
			if (xtr.MoveToAttribute("id")) {
				qmethod.Id = xtr.Value;
			}
			if (xtr.MoveToAttribute("throttle")) {
				if (String.Compare(xtr.Value, "true", true) == 0) {
					qmethod.Throttle = true;
				}
			}
			if (!IsEmpty) {
				while (xtr.Read()) {
					if (xtr.Name == "qparam") {
						qmethod.AddPinvokeParam(ParseQParam());
						qmethod.AddPinvokeCallParam(ParseQParam());
						qmethod.AddCSharpParam(ParseQParam());
					} else if (xtr.Name == ""){
					} else {
						break;
					}
				}
			}
			qtype.AddQMethod(qmethod);
		}

		public QItem ParseQItem ()
		{
			QItem qitem = new QItem();
			if (xtr.MoveToAttribute("name")) {
				qitem.Name = xtr.Value;
			}
			if (xtr.MoveToAttribute("value")) {
				qitem.Value = xtr.Value;
			}
			return qitem;
		}

		public QParam ParseQParam ()
		{
			QParam qparam = new QParam();
			if (xtr.MoveToAttribute("type")) {
				qparam.Type = xtr.Value;
			}
			if (xtr.MoveToAttribute("name")) {
				qparam.Name = xtr.Value;
			}
			if (xtr.MoveToAttribute("default")) {
				qparam.Default = xtr.Value;
			}
			return qparam;
		}
	}
}
