// 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 TQObject receiver;
		protected string slot;
		private string name;
		private string args;
		protected MethodInfo slotInfo;
		private IntPtr wrapperPtr;
		private Delegate callback;

		public TQObject 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(TQObject 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)
		{
			TQString csvalue0 = QtSupport.LookupObject (value0, typeof (TQString)) as TQString;
		
			Invoke (new object[] {csvalue0});
		}
		
		public void SlotBridge_QDockWindow (IntPtr value0)
		{
			TQDockWindow csvalue0 = QtSupport.LookupObject (value0, typeof (TQDockWindow)) as TQDockWindow;
		
			Invoke (new object[] {csvalue0});
		}
		
		public void SlotBridge_QDropEvent (IntPtr value0)
		{
			TQDropEvent csvalue0 = QtSupport.LookupObject (value0, typeof (TQDropEvent)) as TQDropEvent;
		
			Invoke (new object[] {csvalue0});
		}
		
		public void SlotBridge_QDropEventTQListViewItem (IntPtr value0, IntPtr value1)
		{
			TQDropEvent csvalue0 = QtSupport.LookupObject (value0, typeof (TQDropEvent)) as TQDropEvent;
			TQListViewItem csvalue1 = QtSupport.LookupObject (value1, typeof (TQListViewItem)) as TQListViewItem;
		
			Invoke (new object[] {csvalue0, csvalue1});
		}
		
		public void SlotBridge_QIconViewItem (IntPtr value0)
		{
			TQIconViewItem csvalue0 = QtSupport.LookupObject (value0, typeof (TQIconViewItem)) as TQIconViewItem;
		
			Invoke (new object[] {csvalue0});
		}
		
		public void SlotBridge_QListBoxItem (IntPtr value0)
		{
			TQListBoxItem csvalue0 = QtSupport.LookupObject (value0, typeof (TQListBoxItem)) as TQListBoxItem;
		
			Invoke (new object[] {csvalue0});
		}
		
		public void SlotBridge_QListViewItem (IntPtr value0)
		{
			TQListViewItem csvalue0 = QtSupport.LookupObject (value0, typeof (TQListViewItem)) as TQListViewItem;
		
			Invoke (new object[] {csvalue0});
		}
		
		public void SlotBridge_QListViewItemTQListViewItem (IntPtr value0, IntPtr value1)
		{
			TQListViewItem csvalue0 = QtSupport.LookupObject (value0, typeof (TQListViewItem)) as TQListViewItem;
			TQListViewItem csvalue1 = QtSupport.LookupObject (value1, typeof (TQListViewItem)) as TQListViewItem;
		
			Invoke (new object[] {csvalue0, csvalue1});
		}
		
		public void SlotBridge_QListViewItemTQListViewItemTQListViewItem (IntPtr value0, IntPtr value1, IntPtr value2)
		{
			TQListViewItem csvalue0 = QtSupport.LookupObject (value0, typeof (TQListViewItem)) as TQListViewItem;
			TQListViewItem csvalue1 = QtSupport.LookupObject (value1, typeof (TQListViewItem)) as TQListViewItem;
			TQListViewItem csvalue2 = QtSupport.LookupObject (value2, typeof (TQListViewItem)) as TQListViewItem;

			Invoke (new object[] {csvalue0, csvalue1, csvalue2});
		}
		
		public void SlotBridge_QNetworkOperation (IntPtr value0)
		{
			TQNetworkOperation csvalue0 = QtSupport.LookupObject (value0, typeof (TQNetworkOperation)) as TQNetworkOperation;
		
			Invoke (new object[] {csvalue0});
		}
		
		public void SlotBridge_QObject (IntPtr value0)
		{
			TQObject csvalue0 = QtSupport.LookupObject (value0, typeof (TQObject)) as TQObject;
		
			Invoke (new object[] {csvalue0});
		}
		
		public void SlotBridge_QToolBar (IntPtr value0)
		{
			TQToolBar csvalue0 = QtSupport.LookupObject (value0, typeof (TQToolBar)) as TQToolBar;
		
			Invoke (new object[] {csvalue0});
		}
		
		public void SlotBridge_QWidget (IntPtr value0)
		{
			TQWidget csvalue0 = QtSupport.LookupObject (value0, typeof (TQWidget)) as TQWidget;
		
			Invoke (new object[] {csvalue0});
		}
		
		public void SlotBridge_intTQIconViewItem (int value0, IntPtr value1)
		{
			TQIconViewItem csvalue1 = QtSupport.LookupObject (value1, typeof (TQIconViewItem)) as TQIconViewItem;

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

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

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

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

		private static MethodInfo LookupSlot(TQObject 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;
		}
	}
}
