// 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;
		TQType qtype;

		public Parser (string xmlFragment)
		{
			qtype = new TQType ();
			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 ();
			NewTQCtors ();
		}

		public TQType GetTQType ()
		{
			return qtype;
		}

		public void Parse ()
		{
			while(xtr.Read ()) {
				if (xtr.NodeType != XmlNodeType.EndElement) {
					switch (xtr.Name) {
						case "qtype":
							ParseTQType ();
							continue;
						case "qancestor":
							ParseTQAncestor ();
							continue;
						case "qenum":
							ParseTQEnum ();
							continue;
						case "qctor":
							ParseTQCtor ();
							continue;
						case "qdctor":
							ParseTQDCtor ();
							continue;
						case "qmethod":
							ParseTQMethod ();
							continue;
						default:
							continue;
					}
				}
			}
		}

		public void NewTQCtors ()
		{
			// A ctor for inherited classes
			TQCtor _qctor = new TQCtor();
			_qctor.Name = qtype.Name;
			_qctor.Access = "internal";
			_qctor.Inherited = true;
			qtype.AddTQCtor(_qctor);

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

			// A dummy ctor
			TQCtor ___qctor = new TQCtor();
			___qctor.Name = qtype.Name;
			___qctor.Access = "internal";
			___qctor.Dummy = true;
			TQParam ___qparam = new TQParam();
			___qparam.Type = "TQNull";
			___qparam.Name = "dummy";
			___qctor.AddCSharpParam(___qparam);
			qtype.AddTQCtor(___qctor);
		}

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

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

			foreach (TQCtor ctor in additions) qtype.AddTQCtor (ctor);
			additions = new ArrayList ();

			foreach (TQMethod qmethod in qtype.TQMethods){
				foreach (TQParam pinvokeparam in qmethod.PinvokeParams) {
					if (pinvokeparam.Default != null) {
						TQMethod _qmethod = new TQMethod();
						_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((TQParam)qmethod.PinvokeParams[j]);
							_qmethod.AddPinvokeCallParam((TQParam)qmethod.PinvokeCallParams[j]);
							_qmethod.AddCSharpParam((TQParam)qmethod.CSharpParams[j]);
							_qmethod.AddOverloadParam((TQParam) ((TQParam) qmethod.CSharpParams[j]).Clone());

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

			foreach (TQMethod method in additions) qtype.AddTQMethod (method);
		}

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

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

		public void ParseTQAncestor ()
		{
			TQAncestor qancestor = new TQAncestor();
			if (xtr.MoveToAttribute("name")) {
				qancestor.Name = xtr.Value;
			}
			qtype.AddTQAncestor(qancestor);
		}

		public void ParseTQEnum ()
		{
			bool match = false;
			TQEnum qenum = new TQEnum();
			if (xtr.MoveToAttribute("name"))
				qenum.Name = xtr.Value;
			if (xtr.MoveToAttribute("access"))
				qenum.Access = xtr.Value;
			while (xtr.Read()) {
				if (xtr.Name == "qitem") {
					TQItem qitem = ParseTQItem();
					qenum.AddTQItem(qitem);
					long parse = 0;
					try {
						parse = Int64.Parse(qitem.Value);
					} catch {
					}
					if (parse >= 2147483647)
						qenum.Type = "uint";
				} else if (xtr.Name == "") {
				} else {
					break;
				}
			}
			qtype.AddTQEnum(qenum);
		}

		public void ParseTQCtor ()
		{
			bool IsEmpty = xtr.IsEmptyElement;
			TQCtor qctor = new TQCtor();
			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(ParseTQParam());
						qctor.AddPinvokeCallParam(ParseTQParam());
						qctor.AddCSharpParam(ParseTQParam());
					} else if (xtr.Name == ""){
					} else {
						break;
					}
				}
			}
			qtype.AddTQCtor(qctor);
		}

		public void ParseTQDCtor ()
		{
			bool IsEmpty = xtr.IsEmptyElement;
			TQDCtor qdctor = new TQDCtor();
			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.AddTQParam(ParseTQParam());
					} else if (xtr.Name == "") {
					} else {
						break;
					}
				}
			}
			qtype.AddTQDCtor(qdctor);
		}

		public void ParseTQMethod ()
		{
			bool IsEmpty = xtr.IsEmptyElement;
			TQMethod qmethod = new TQMethod();
			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(ParseTQParam());
						qmethod.AddPinvokeCallParam(ParseTQParam());
						qmethod.AddCSharpParam(ParseTQParam());
					} else if (xtr.Name == ""){
					} else {
						break;
					}
				}
			}
			qtype.AddTQMethod(qmethod);
		}

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

		public TQParam ParseTQParam ()
		{
			TQParam qparam = new TQParam();
			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;
		}
	}
}
