// QtSlot.cs - Represents C# slot connections
//
// Copyright (C) 2002  Nick Zigarovich (nick@chemlab.org)
//
// 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.

namespace Qt {
	using System;
	using System.Reflection;
	using System.Text;

	internal class QtSlot {
		protected QObject receiver;
		protected string slot;
		private string name;
		private string args;
		protected MethodInfo slotInfo;
		private IntPtr wrapperPtr;
		private Delegate callback;

		public QObject Receiver {
			get { return receiver; }
		}

		public string Slot {
			get { return slot; }
		}

		public MethodInfo Info {
			get { return slotInfo; }
		}

		public string Identifier {
			get { return receiver.RawObject.ToString()+slot; }
		}

		public string Name {
			get { return name; }
		}

		public string Args {
			get { return args; }
		}

		public string NormalizedArgs {
			get { return NormalizeSlotArgs(args); }
		}

		public IntPtr WrapperPtr {
			get { return wrapperPtr; }
			set { wrapperPtr = value; }
		}

		public Delegate Callback {
			get { return callback; }
			set { callback = value; }
		}

		public bool IsCSharpSlot {
			get { return slotInfo != null; }
		}

		public QtSlot() {}

		public QtSlot(QObject receiver, string slot)
		{
			this.receiver = receiver;
			this.slot = slot;
			string[] slotsplit = slot.Split(new char[] {'('});

			try {
				name = slotsplit[0];
				args = "("+slotsplit[1];
			}
			catch (IndexOutOfRangeException) {
				throw new ArgumentException ("Invalid slot format: " + slot);
			}

			slotInfo = LookupSlot(receiver, name, NormalizedArgs);
			wrapperPtr = IntPtr.Zero;
			callback = null;
		}

		public void SlotBridge_QString (IntPtr value0)
		{
			QString csvalue0 = QtSupport.LookupObject (value0, typeof (QString)) as QString;
		
			Invoke (new object[] {csvalue0});
		}
		
		public void SlotBridge_QDockWindow (IntPtr value0)
		{
			QDockWindow csvalue0 = QtSupport.LookupObject (value0, typeof (QDockWindow)) as QDockWindow;
		
			Invoke (new object[] {csvalue0});
		}
		
		public void SlotBridge_QDropEvent (IntPtr value0)
		{
			QDropEvent csvalue0 = QtSupport.LookupObject (value0, typeof (QDropEvent)) as QDropEvent;
		
			Invoke (new object[] {csvalue0});
		}
		
		public void SlotBridge_QDropEventQListViewItem (IntPtr value0, IntPtr value1)
		{
			QDropEvent csvalue0 = QtSupport.LookupObject (value0, typeof (QDropEvent)) as QDropEvent;
			QListViewItem csvalue1 = QtSupport.LookupObject (value1, typeof (QListViewItem)) as QListViewItem;
		
			Invoke (new object[] {csvalue0, csvalue1});
		}
		
		public void SlotBridge_QIconViewItem (IntPtr value0)
		{
			QIconViewItem csvalue0 = QtSupport.LookupObject (value0, typeof (QIconViewItem)) as QIconViewItem;
		
			Invoke (new object[] {csvalue0});
		}
		
		public void SlotBridge_QListBoxItem (IntPtr value0)
		{
			QListBoxItem csvalue0 = QtSupport.LookupObject (value0, typeof (QListBoxItem)) as QListBoxItem;
		
			Invoke (new object[] {csvalue0});
		}
		
		public void SlotBridge_QListViewItem (IntPtr value0)
		{
			QListViewItem csvalue0 = QtSupport.LookupObject (value0, typeof (QListViewItem)) as QListViewItem;
		
			Invoke (new object[] {csvalue0});
		}
		
		public void SlotBridge_QListViewItemQListViewItem (IntPtr value0, IntPtr value1)
		{
			QListViewItem csvalue0 = QtSupport.LookupObject (value0, typeof (QListViewItem)) as QListViewItem;
			QListViewItem csvalue1 = QtSupport.LookupObject (value1, typeof (QListViewItem)) as QListViewItem;
		
			Invoke (new object[] {csvalue0, csvalue1});
		}
		
		public void SlotBridge_QListViewItemQListViewItemQListViewItem (IntPtr value0, IntPtr value1, IntPtr value2)
		{
			QListViewItem csvalue0 = QtSupport.LookupObject (value0, typeof (QListViewItem)) as QListViewItem;
			QListViewItem csvalue1 = QtSupport.LookupObject (value1, typeof (QListViewItem)) as QListViewItem;
			QListViewItem csvalue2 = QtSupport.LookupObject (value2, typeof (QListViewItem)) as QListViewItem;

			Invoke (new object[] {csvalue0, csvalue1, csvalue2});
		}
		
		public void SlotBridge_QNetworkOperation (IntPtr value0)
		{
			QNetworkOperation csvalue0 = QtSupport.LookupObject (value0, typeof (QNetworkOperation)) as QNetworkOperation;
		
			Invoke (new object[] {csvalue0});
		}
		
		public void SlotBridge_QObject (IntPtr value0)
		{
			QObject csvalue0 = QtSupport.LookupObject (value0, typeof (QObject)) as QObject;
		
			Invoke (new object[] {csvalue0});
		}
		
		public void SlotBridge_QToolBar (IntPtr value0)
		{
			QToolBar csvalue0 = QtSupport.LookupObject (value0, typeof (QToolBar)) as QToolBar;
		
			Invoke (new object[] {csvalue0});
		}
		
		public void SlotBridge_QWidget (IntPtr value0)
		{
			QWidget csvalue0 = QtSupport.LookupObject (value0, typeof (QWidget)) as QWidget;
		
			Invoke (new object[] {csvalue0});
		}
		
		public void SlotBridge_intQIconViewItem (int value0, IntPtr value1)
		{
			QIconViewItem csvalue1 = QtSupport.LookupObject (value1, typeof (QIconViewItem)) as QIconViewItem;

			Invoke (new object[] {value0, csvalue1});
		}

		public void SlotBridge_intQListBoxItem (int value0, IntPtr value1)
		{
			QListBoxItem csvalue1 = QtSupport.LookupObject (value1, typeof (QListBoxItem)) as QListBoxItem;

			Invoke (new object[] {value0, csvalue1});
		}

		public void Invoke(object[] args)
		{
			if (slotInfo != null) {
				slotInfo.Invoke(receiver, args);
			}
		}

		private static MethodInfo LookupSlot(QObject receiver, string name, string args)
		{
			MethodInfo ret = null;

			foreach (MethodInfo info in receiver.GetType().GetMethods(
				BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance ))
			{
				string infoargs = "(" + ShortArgs (info.ToString().Split(new char[] {'('})[1].Replace(" ", "")) + ")";
				string nargs = args.Replace ("string", "String"); // FIXME

				if (nargs.CompareTo(infoargs) == 0 &&
					name.CompareTo(info.Name) == 0)
				{
					ret = info;
					break;
				}
			}

			return ret;
		}

		private static string ShortArgs (string args)
		{
			StringBuilder builder = new StringBuilder ();
			string [] s = args.TrimEnd (')').Split (',');
			foreach (string st in s) {
				string [] str = st.Trim (' ').Split ('.');
				string stri = str [str.Length -1];
				builder.Append (stri+", ");
			}
			return builder.ToString ().TrimEnd (',', ' ');
		}

		private static string NormalizeSlotArgs(string methodargs)
		{
			string[] args = methodargs.Replace("(", "").Replace(")", "").Split(new char[] {','});
			StringBuilder sb = new StringBuilder();
			sb.Append("(");
			int count = 0;

			// FIXME Handle unsigned, bool, and byte cases. Would lookups in a hashtable be faster?
			foreach (string arg in args) {
				if (count > 0) sb.Append(",");

				if (arg == "short")
					sb.Append("Int16");
				else if (arg == "int")
					sb.Append("Int32");
				else if (arg == "long")
					sb.Append("Int64");
				else if (arg == "float")
					sb.Append("Single");
				else if (arg == "double")
					sb.Append("Double");
				else if (arg == "char")
					sb.Append("Char");
				else
					sb.Append(arg);

				count++;
			}

			sb.Append(")");
			return sb.ToString();
		}

		// For ArrayList storage.
		public override bool Equals(object obj)
		{
			return ((QtSlot)obj).Identifier == Identifier;
		}
	}
}
