using System;
using System.ComponentModel;
using System.Drawing;
using System.Reflection;
using System.Runtime.InteropServices;
using Decal.Interop.Core;

namespace Decal.Adapter.Wrappers;

/// <summary>
/// Provides direct access to functions and properties in the AC client.
/// </summary>
[CLSCompliant(true)]
public sealed class HooksWrapper : MarshalByRefObject, IIndexedValueProvider, IDisposable
{
	private IACHooks myHooks;

	private bool isDisposed;

	[CLSCompliant(false)]
	[EditorBrowsable(EditorBrowsableState.Never)]
	public IACHooks Underlying => myHooks;

	/// <summary>
	/// Gets a value indicating how the player is moving an item, or 0 
	/// if the player is not moving an item.  There are different values 
	/// for moving an item, combining/splitting a stack, picking 
	/// up/dropping an item, etc.
	/// </summary>
	/// <remarks>
	/// Here are some known values for <c>BusyState</c>:
	/// <para><c>0</c>: Idle.</para>
	/// <para><c>1</c>: Combining a stack.</para>
	/// <para><c>2</c>: Splitting a stack.</para>
	/// <para><c>3</c>: ???</para>
	/// <para><c>4</c>: Picking up an item from the ground.</para>
	/// <para><c>5</c>: Moving or unequipping an item.</para>
	/// <para><c>6</c>: Dropping an item to the ground.</para>
	/// <para><c>7</c>: Equipping an item.</para>
	/// </remarks>
	public int BusyState => myHooks.BusyState;

	/// <summary>
	/// Gets the GUID of the object that the player is moving, or 0 if the 
	/// player is not currently moving any object.
	/// </summary>
	public int BusyStateId => myHooks.BusyStateID;

	/// <summary>
	/// Returns <c>true</c> if the chat bar at the bottom of the screen 
	/// currently has keyboard focus.  Doesn't apply to floating chat 
	/// windows.
	/// </summary>
	public bool ChatState => myHooks.ChatState;

	/// <summary>
	/// Gets a value indicating the player's combat stance.
	/// <para>1 is out of combat mode;
	/// 2 is melee attack mode;
	/// 4 is missile attack mode;
	/// 8 is magic casting mode.</para>
	/// </summary>
	public CombatState CombatMode => (CombatState)myHooks.CombatMode;

	/// <summary>
	/// Returns a pointer to the CommandInterpreter object
	/// </summary>
	public int CommandInterpreter => myHooks.CommandInterpreter;

	/// <summary>
	/// Gets or sets the GUID of the selected item. A GUID of 0 indicates 
	/// no item selected.
	/// </summary>
	public int CurrentSelection
	{
		get
		{
			return myHooks.CurrentSelection;
		}
		set
		{
			myHooks.CurrentSelection = value;
		}
	}

	/// <summary>
	/// Gets or sets the compass heading of the player (in degrees).  
	/// North is 0, East is 90, etc. Setting the heading will cause the 
	/// player to turn.
	/// </summary>
	public double Heading
	{
		get
		{
			return myHooks.HeadingDegrees;
		}
		set
		{
			FaceHeading(value, bUnknown: true);
		}
	}

	/// <summary>
	/// Gets or sets the compass heading of the player (in radians).  
	/// North is 0, East is pi/2, etc. Setting the heading will cause the 
	/// player to turn.
	/// </summary>
	public double HeadingRadians
	{
		get
		{
			return myHooks.HeadingRadians;
		}
		set
		{
			RadianFaceHeading(value, bUnknown: true);
		}
	}

	/// <summary>
	/// Gets the ID of the player's current landcell (a.k.a. landblock).
	/// </summary>
	/// <remarks>
	/// Here is a description of landblocks from 
	/// <a href="http://www.ugcs.caltech.edu/~dsimpson/">David Simpson's 
	/// Dereth Cartography</a>, from the header comment in his mapac.c
	/// <blockquote>
	/// The map in Asheron's Call is 254 by 254 landblocks.  Each landblock contains
	/// a 9 by 9 grid of data points which makes for an 8 by 8 group of land squares
	/// in game.  Each landblock has a unique id, which is a word in length, and
	/// has the format xxyyFFFF.  In game, xx is the east-west position, and yy is the
	/// north-south position.  Landblock 0000FFFF is located in the southwest corner of
	/// the map.  Use /loc to find out which landblock you are on.  Each square in a
	/// landblock is 0.1 wide and tall, making each landblock 0.8 by 0.8.  Although
	/// each landblock contains 9 by 9 points, the points on the edges are redundant
	/// with adjacent landblocks.  The entire map is 2041 by 2041 data points, making
	/// 2040 by 2040 squares.  Lastly, each square is 24.0 by 24.0 units, whatever
	/// they may be.
	/// </blockquote>
	/// </remarks>
	/// <example>
	/// This example shows how to calculate coordinates from 
	/// <see cref="P:Decal.Adapter.Wrappers.HooksWrapper.Landcell" />, <see cref="P:Decal.Adapter.Wrappers.HooksWrapper.LocationX" />, and
	/// <see cref="P:Decal.Adapter.Wrappers.HooksWrapper.LocationY" />.  North and east are positive, south and 
	/// west are negative.  Round the result to one decimal place to get 
	/// identical coordinates to the ones AC reports.
	/// <code><![CDATA[
	/// double NS = ((uint)((Host.Actions.Landcell & 0x00FF0000) / 0x2000) + Host.Actions.LocationY / 24.0 - 1019.5) / 10.0;
	/// double EW = ((uint)((Host.Actions.Landcell & 0xFF000000) / 0x200000) + Host.Actions.LocationX / 24.0 - 1019.5) / 10.0;
	///
	/// string coords = Math.Abs(NS).ToString("0.0") + (NS >= 0 ? "N" : "S") + ", " + Math.Abs(EW).ToString("0.0") + (EW >= 0 ? "E" : "W");
	/// ]]>
	/// </code>
	/// </example>
	public int Landcell => myHooks.Landcell;

	/// <summary>
	/// Gets the player's X-offset within the current landcell, measured in 
	/// meters.  On the landscape, values range from 0 (west side of 
	/// landcell) to 192 (east side).  In dungeons, values are unbounded.
	/// </summary>
	public double LocationX => myHooks.LocationX;

	/// <summary>
	/// Gets the player's Y-offset within the current landcell, measured in 
	/// meters.  On the landscape, values range from 0 (south side of 
	/// landcell) to 192 (north side).  In dungeons, values are unbounded.
	/// </summary>
	public double LocationY => myHooks.LocationY;

	/// <summary>
	/// Gets the player's altitude, measured in meters. 0 is sea-level.
	/// </summary>
	public double LocationZ => myHooks.LocationZ;

	/// <summary>
	/// Gets the total number of items in the currently selected stack.
	/// </summary>
	public int MaxSelectedStackCount => myHooks.MaxSelectedStackCount;

	/// <summary>
	/// Gets the GUID of the currently opened container, such as a chest or 
	/// corpse.  Returns 0 if no container is currently opened.
	/// </summary>
	public int OpenedContainer => myHooks.OpenedContainer;

	/// <summary>
	/// Gets the ID of the current mouse pointer graphics.  This number 
	/// corresponds to an image in client_portal.dat.
	/// </summary>
	/// <remarks>
	/// Here are some known values of <c>PointerState</c>:
	/// <para><c>0x6004D68</c>: Brown idle cursor.</para>
	/// <para><c>0x6004D69</c>: Brown idle cursor with yellow outline.</para>
	/// <para><c>0x6004D6A</c>: Red combat mode cursor.</para>
	/// <para><c>0x6004D6B</c>: Red combat mode cursor with yellow outline.</para>
	/// <para><c>0x6004D6C</c>: Blue magic mode cursor.</para>
	/// <para><c>0x6004D6D</c>: Blue magic mode cursor with yellow outline.</para>
	/// <para><c>0x6004D71</c>: Magnifying glass cursor.</para>
	/// <para><c>0x6004D72</c>: Hand cursor.</para>
	/// <para><c>0x6004D74</c>: Hour glass cursor.</para>
	/// <para><c>0x6004D75</c>: Hour glass cursor with yellow outline.</para>
	/// </remarks>
	public int PointerState => myHooks.PointerState;

	/// <summary>
	/// Gets or sets the GUID of the previously-selected item.  Setting 
	/// this will cause the given GUID to be selected when the user 
	/// presses the "select previous item" key.
	/// </summary>
	public int PreviousSelection
	{
		get
		{
			return myHooks.PreviousSelection;
		}
		set
		{
			myHooks.PreviousSelection = value;
		}
	}

	/// <summary>
	/// Gets the bounding box of the 3D region in the AC window.  The 3D 
	/// region is the area of the window where landscape and characters 
	/// are visible.
	/// </summary>
	public Rectangle Region3D
	{
		get
		{
			tagRECT aC3DRegionRect = myHooks.AC3DRegionRect;
			return new Rectangle(aC3DRegionRect.left, aC3DRegionRect.top, aC3DRegionRect.right, aC3DRegionRect.bottom);
		}
	}

	/// <summary>
	/// Gets the bounding box of the entire AC window, including the 2D 
	/// parts of the GUI.  This is the resolution set on the settings tab 
	/// in AC.
	/// </summary>
	public Rectangle RegionWindow
	{
		get
		{
			tagRECT aCWindowRect = myHooks.ACWindowRect;
			return new Rectangle(aCWindowRect.left, aCWindowRect.top, aCWindowRect.right, aCWindowRect.bottom);
		}
	}

	/// <summary>
	/// Gets or sets the number of items in the currently selected stack.
	/// Must be between 1 and <see cref="P:Decal.Adapter.Wrappers.HooksWrapper.MaxSelectedStackCount" />.  If 
	/// this is less than <see cref="P:Decal.Adapter.Wrappers.HooksWrapper.MaxSelectedStackCount" />, then 
	/// moving the current selection will split the stack.
	/// </summary>
	public int SelectedStackCount
	{
		get
		{
			return myHooks.SelectedStackCount;
		}
		set
		{
			myHooks.SelectedStackCount = value;
		}
	}

	/// <summary>
	/// Gets the GUID of the currently open vendor, or 0 if no vendor is 
	/// open.
	/// </summary>
	public int VendorId => myHooks.VendorID;

	/// <summary>
	/// Gets the level an attribute. "Current" values include buffs, 
	/// vitae, etc.
	/// </summary>
	[CLSCompliant(false)]
	public HookIndexer<AttributeType> Attribute => new HookIndexer<AttributeType>(this, hookIndexType.Attribute);

	/// <summary>
	/// Gets the number of times a attribute has been raised above its
	/// starting (innate) level.
	/// </summary>
	[CLSCompliant(false)]
	public HookIndexer<AttributeType> AttributeClicks => new HookIndexer<AttributeType>(this, hookIndexType.AttributeClicks);

	/// <summary>
	/// Gets the starting (innate) level of an attribute.
	/// </summary>
	[CLSCompliant(false)]
	public HookIndexer<AttributeType> AttributeStart => new HookIndexer<AttributeType>(this, hookIndexType.AttributeStart);

	/// <summary>
	/// Gets the total amount of XP spent on an attribute.
	/// </summary>
	[CLSCompliant(false)]
	public HookIndexer<AttributeType> AttributeTotalXP => new HookIndexer<AttributeType>(this, hookIndexType.AttributeTotalXP);

	/// <summary>
	/// Gets the value of a hook by its ID.
	/// </summary>
	[CLSCompliant(false)]
	public HookIndexer<int> Misc => new HookIndexer<int>(this, hookIndexType.Misc);

	/// <summary>
	/// Gets the level a skill. "Current" values include buffs, vitae, etc.
	/// </summary>
	[CLSCompliant(false)]
	public HookIndexer<SkillType> Skill => new HookIndexer<SkillType>(this, hookIndexType.Skill);

	/// <summary>
	/// Gets the number of times a skill has been raised above the level 
	/// calculated from the skill's attribute formula plus free points.
	/// </summary>
	[CLSCompliant(false)]
	public HookIndexer<SkillType> SkillClicks => new HookIndexer<SkillType>(this, hookIndexType.SkillClicks);

	/// <summary>
	/// Gets the number of free points for a skill.  Specialized skills 
	/// have 10 free points.
	/// </summary>
	[CLSCompliant(false)]
	public HookIndexer<SkillType> SkillFreePoints => new HookIndexer<SkillType>(this, hookIndexType.SkillFreePoints);

	/// <summary>
	/// Gets the total amount of XP spent on a skill.
	/// </summary>
	[CLSCompliant(false)]
	public HookIndexer<SkillType> SkillTotalXP => new HookIndexer<SkillType>(this, hookIndexType.SkillTotalXP);

	/// <summary>
	/// Gets the level to which a skill is trained.
	/// <para>0 is untrained; 1 is trained; 2 is specialized.</para>
	/// </summary>
	[CLSCompliant(false)]
	public HookIndexer<SkillType> SkillTrainLevel => new HookIndexer<SkillType>(this, hookIndexType.SkillTrainLevel);

	/// <summary>
	/// Gets the level a vital. "Current" values include buffs, vitae, etc.
	/// </summary>
	[CLSCompliant(false)]
	public HookIndexer<VitalType> Vital => new HookIndexer<VitalType>(this, hookIndexType.Vital);

	/// <summary>
	/// Gets the number of times a vital has been raised above the level 
	/// calculated from the vital's attribute formula.
	/// </summary>
	[CLSCompliant(false)]
	public HookIndexer<VitalType> VitalClicks => new HookIndexer<VitalType>(this, hookIndexType.VitalClicks);

	/// <summary>
	/// Gets the total amount of XP spent on a vital.
	/// </summary>
	[CLSCompliant(false)]
	public HookIndexer<VitalType> VitalTotalXP => new HookIndexer<VitalType>(this, hookIndexType.VitalTotalXP);

	internal HooksWrapper(ACHooks hooks)
	{
		myHooks = hooks;
	}

	~HooksWrapper()
	{
		Dispose(disposing: false);
	}

	/// <summary>
	/// Releases the resources used by this HooksWrapper. <b>No plugin or 
	/// filter should use this function!</b>
	/// </summary>
	public void Dispose()
	{
		Dispose(disposing: true);
		GC.SuppressFinalize(this);
	}

	private void Dispose(bool disposing)
	{
		if (!isDisposed)
		{
		}
		if (myHooks != null)
		{
			Marshal.ReleaseComObject(myHooks);
			myHooks = null;
		}
		isDisposed = true;
	}

	/// <summary>
	/// Adds a line of text to the default chat window for the specified 
	/// text color.
	/// </summary>
	/// <param name="text">The text to add to the chat window.</param>
	/// <param name="color">The color ID of the text to add.  This also 
	/// determines in which chat window the text will appear, as per the 
	/// user's chat settings.</param>
	public void AddChatText(string text, int color)
	{
		AddChatText(text, color, 0);
	}

	/// <summary>
	/// Adds a line of text to the specified chat window.
	/// </summary>
	/// <param name="text">The text to add to the chat window.</param>
	/// <param name="color">The color ID of the text to add.</param>
	/// <param name="target">The chat window where the text will appear.
	/// <para>0 is the default chat window for the given color, 1 is main 
	/// chat, and 2-5 are chat tabs #1-4, respectively.</para></param>
	public void AddChatText(string text, int color, int target)
	{
		myHooks.AddChatText(text, color, target);
	}

	/// <summary>
	/// Adds text to the default chat window for the specified text color.
	/// </summary>
	/// <param name="text">The text to add to the chat window.</param>
	/// <param name="color">The color ID of the text to add.  This also 
	/// determines in which chat window the text will appear, as per the 
	/// user's chat settings.</param>
	public void AddChatTextRaw(string text, int color)
	{
		AddChatTextRaw(text, color, 0);
	}

	/// <summary>
	/// Adds text to the specified chat window.
	/// </summary>
	/// <param name="text">The text to add to the chat window.</param>
	/// <param name="color">The color ID of the text to add.</param>
	/// <param name="target">The chat window where the text will appear.
	/// <para>0 is the default chat window for the given color, 1 is main 
	/// chat, and 2-5 are chat tabs #1-4, respectively.</para></param>
	public void AddChatTextRaw(string text, int color, int target)
	{
		myHooks.AddChatTextRaw(text, color, target);
	}

	/// <summary>
	/// Adds a red status message to the status area at the top of the 
	/// screen.
	/// </summary>
	/// <param name="text">The status message.</param>
	public void AddStatusText(string text)
	{
		myHooks.AddStatusText(text);
	}

	/// <summary>
	/// Uses one item on another (for crafting, etc.)
	/// <para>This command will fail if the player is busy using an item, 
	/// casting a spell, etc.  If you are using multiple items, you must 
	/// wait until the previous action is complete before attempting to 
	/// use the next item.</para>
	/// </summary>
	/// <param name="useThis">The GUID of the item to use.</param>
	/// <param name="onThis">The GUID of the target.</param>
	/// <seealso cref="M:Decal.Adapter.Wrappers.HooksWrapper.UseItem(System.Int32,System.Int32,System.Int32)" />
	public void ApplyItem(int useThis, int onThis)
	{
		myHooks.ApplyItem(useThis, onThis);
	}

	/// <summary>
	/// Attempts to wield an item
	/// <para>This command will fail if the player is busy using an item, 
	/// casting a spell, etc.  If you are using multiple items, you must 
	/// wait until the previous action is complete before attempting to 
	/// use the next item.</para>
	/// </summary>
	/// <param name="item">The GUID of the item to use.</param>
	/// <seealso cref="M:Decal.Adapter.Wrappers.HooksWrapper.UseItem(System.Int32,System.Int32,System.Int32)" />
	public void AutoWield(int item)
	{
		myHooks.AutoWield(item);
	}

	/// <summary>
	/// Attempts to wield an item
	/// <para>This command will fail if the player is busy using an item, 
	/// casting a spell, etc.  If you are using multiple items, you must 
	/// wait until the previous action is complete before attempting to 
	/// use the next item.</para>
	/// </summary>
	/// <param name="item">The GUID of the item to use.</param>
	/// <param name="slot">The slot to use</param>
	/// <param name="explic">1 if explicit placement, 0 if automatic placement</param>
	/// <param name="notexplic">0 if explic is 1, 1 if explic is 0</param>
	/// <seealso cref="M:Decal.Adapter.Wrappers.HooksWrapper.UseItem(System.Int32,System.Int32,System.Int32)" />
	public void AutoWield(int item, int slot, int explic, int notexplic)
	{
		myHooks.AutoWieldEx(item, slot, explic, notexplic);
	}

	/// <summary>
	/// Attempts to wield an item
	/// <para>This command will fail if the player is busy using an item, 
	/// casting a spell, etc.  If you are using multiple items, you must 
	/// wait until the previous action is complete before attempting to 
	/// use the next item.</para>
	/// </summary>
	/// <param name="item">The GUID of the item to use.</param>
	/// <param name="slot">The slot to use</param>
	/// <param name="explic">1 if explicit placement, 0 if automatic placement</param>
	/// <param name="notexplic">0 if explic is 1, 1 if explic is 0</param>
	/// <param name="zero1">Zero</param>
	/// <param name="zero2">Zero</param>
	/// <seealso cref="M:Decal.Adapter.Wrappers.HooksWrapper.UseItem(System.Int32,System.Int32,System.Int32)" />
	public void AutoWield(int item, int slot, int explic, int notexplic, int zero1, int zero2)
	{
		myHooks.AutoWieldRaw(item, slot, explic, notexplic, zero1, zero2);
	}

	/// <summary>
	/// Causes the player to attempt to cast a spell.  The player must be 
	/// in spellcasting mode and the spell must be in his spellbook.
	/// </summary>
	/// <param name="spellId">The ID of the spell to cast.</param>
	/// <param name="objectId">The GUID of the target.  This is ignored for 
	/// non-targeted spells, such as self spells and ring spells.</param>
	public void CastSpell(int spellId, int objectId)
	{
		myHooks.CastSpell(spellId, objectId);
	}

	/// <summary>
	/// Drop an item from the player's inventory onto the ground.
	/// </summary>
	/// <param name="objectId">The GUID of the item to drop.</param>
	public void DropItem(int objectId)
	{
		myHooks.DropItem(objectId);
	}

	/// <summary>
	/// Causes the player to turn to the specified heading.
	/// </summary>
	/// <param name="heading">The desired heading (in degrees).</param>
	/// <param name="bUnknown">Unknown.</param>
	/// <returns>Always returns <c>true</c>.</returns>
	public bool FaceHeading(double heading, bool bUnknown)
	{
		return myHooks.FaceHeading((float)heading, bUnknown);
	}

	/// <summary>
	/// Causes the player to turn to the specified heading.
	/// </summary>
	/// <param name="heading">The desired heading (in radians).</param>
	/// <param name="bUnknown">Unknown</param>
	/// <returns></returns>
	public bool RadianFaceHeading(double heading, bool bUnknown)
	{
		if (heading < 0.0)
		{
			throw new ArgumentOutOfRangeException("heading");
		}
		if (heading > Math.PI * 10.0)
		{
			throw new ArgumentOutOfRangeException("heading");
		}
		double num = heading * 180.0 / Math.PI;
		return myHooks.FaceHeading((float)num, bUnknown);
	}

	/// <summary>
	/// Recruit someone to your fellowship.
	/// </summary>
	/// <param name="lObjectID">The GUID of the character to recruit.</param>
	public void FellowshipRecruit(int lObjectID)
	{
		myHooks.FellowshipRecruit(lObjectID);
	}

	/// <summary>
	/// Give fellowship leadership to a player.
	/// </summary>
	/// <param name="lObjectID">The GUID of the character to become the leader.</param>
	public void FellowshipGrantLeader(int lObjectID)
	{
		myHooks.FellowshipGrantLeader(lObjectID);
	}

	/// <summary>
	/// Opens or closes the fellowship.
	/// </summary>
	/// <param name="IsOpen">True if the fellowship should be made open, false if it should be made closed.</param>
	public void FellowshipSetOpen(bool IsOpen)
	{
		myHooks.FellowshipSetOpen(IsOpen);
	}

	/// <summary>
	/// Quits the current fellowship.
	/// </summary>
	public void FellowshipQuit()
	{
		myHooks.FellowshipQuit();
	}

	/// <summary>
	/// Disbands the current fellowship.
	/// </summary>
	public void FellowshipDisband()
	{
		myHooks.FellowshipDisband();
	}

	/// <summary>
	/// Dismisses another player from the fellowship.
	/// </summary>
	/// <param name="lObjectID">The GUID of the character to remove from the fellowship.</param>
	public void FellowshipDismiss(int lObjectID)
	{
		myHooks.FellowshipDismiss(lObjectID);
	}

	/// <summary>
	/// Gives an object from the player's inventory to another player or 
	/// NPC.
	/// </summary>
	/// <param name="lObject">The GUID of the object to give.</param>
	/// <param name="lDestination">The GUID of the player or NPC to receive 
	/// the object.</param>
	public void GiveItem(int lObject, int lDestination)
	{
		myHooks.GiveItem(lObject, lDestination);
	}

	/// <summary>
	/// Adds an identify-request to the end of the request queue.
	/// </summary>
	/// <param name="objectId">The GUID of the object to request an ID for.</param>
	public void RequestId(int objectId)
	{
		CoreManager.Current.IDQueue.AddToQueueForCaller(objectId, Assembly.GetCallingAssembly(), DateTime.MaxValue);
	}

	/// <summary>
	/// Sends text to AC's chat parser as if the user had typed the text 
	/// into the chat bar.  This text will <i>not</i> be sent to other 
	/// plugins via the 
	/// <see cref="E:Decal.Adapter.Extension.CommandLineText" /> event, so
	/// this function cannot be used to send chat commands to other plugins.
	/// </summary>
	/// <param name="text">The text to send.</param>
	public void InvokeChatParser(string text)
	{
		myHooks.InvokeChatParser(text);
	}

	/// <summary>
	/// Checks if the AC client knows about an object GUID.  The client 
	/// must know about an object for it to be used in other HooksWrapper 
	/// functions.
	/// </summary>
	/// <param name="objectId">The GUID of the object to check.</param>
	/// <returns><c>true</c> if the client knows about an object, or 
	/// <c>false</c> if not.</returns>
	public bool IsValidObject(int objectId)
	{
		return myHooks.IsValidObject(objectId);
	}

	/// <summary>
	/// Logs out the current character and returns to the character 
	/// selection screen.
	/// </summary>
	public void Logout()
	{
		myHooks.Logout();
	}

	/// <summary>
	/// Moves an item to the specified pack in the player's inventory.
	/// <para>This command will fail if the player is busy moving an item, 
	/// casting a spell, etc.  If you are moving multiple items, you must 
	/// wait until the previous action is complete before attempting to 
	/// move the next item.</para>
	/// </summary>
	/// <param name="objectId">The GUID of the object to move.</param>
	/// <param name="packId">The GUID of the destination container.</param>
	/// <param name="slot">The slot within the pack, where 0 is the first 
	/// slot.  If this number is greater than the number of items in the 
	/// pack, the object will be placed in the first unused slot in the 
	/// pack.</param>
	/// <param name="stack">A flag indicating whether to add the object to 
	/// a stack in the pack, if one exists.</param>
	public void MoveItem(int objectId, int packId, int slot, bool stack)
	{
		myHooks.MoveItem(objectId, packId, slot, stack);
	}

	/// <summary>
	/// Moves an item to the front of the specified container.  If the item 
	/// is not in the player's inventory, the destination must be the 
	/// player's main pack (the GUID of the player), or one of his side 
	/// packs.
	/// <para>This command will fail if the player is busy moving an item, 
	/// casting a spell, etc.  If you are moving multiple items, you must 
	/// wait until the previous action is complete before attempting to 
	/// move the next item.</para>
	/// </summary>
	/// <param name="objectId">The GUID of the item to move.</param>
	/// <param name="destinationId">The GUID of the destination container.</param>
	public void MoveItem(int objectId, int destinationId)
	{
		myHooks.MoveItemEx(objectId, destinationId);
	}

	/// <summary>
	/// Moves an item to the specified container, with flags indicating 
	/// how the move should be performed.
	/// <para>This command will fail if the player is busy moving an item, 
	/// casting a spell, etc.  If you are moving multiple items, you must 
	/// wait until the previous action is complete before attempting to 
	/// move the next item.</para>
	/// </summary>
	/// <param name="objectId">The GUID of the object to move.</param>
	/// <param name="destinationId">The GUID of the destination container.</param>
	/// <param name="moveFlags">Flags indicating how the move should be 
	/// performed.</param>
	public void MoveItem(int objectId, int destinationId, int moveFlags)
	{
		myHooks.MoveItemExRaw(objectId, destinationId, moveFlags);
	}

	/// <summary>
	/// Adds a salvagable item to the salvage panel.
	/// <para>The salvage panel does not need to be open for this command, 
	/// but it <i>does</i> need to be open for 
	/// <see cref="M:Decal.Adapter.Wrappers.HooksWrapper.SalvagePanelSalvage" />, and opening the salvage panel 
	/// after adding items to it will clear the panel.</para>
	/// </summary>
	/// <param name="objectId">The GUID of the object to add.</param>
	public void SalvagePanelAdd(int objectId)
	{
		myHooks.SalvagePanelAdd(objectId);
	}

	/// <summary>
	/// Salvages the items in the salvage panel.  The salvage panel must 
	/// be open.
	/// </summary>
	public void SalvagePanelSalvage()
	{
		myHooks.SalvagePanelSalvage();
	}

	/// <summary>
	/// Selects an item.
	/// </summary>
	/// <param name="objectId">The GUID of the object to select, or 0 to 
	/// clear the current selection.</param>
	public void SelectItem(int objectId)
	{
		myHooks.SelectItem(objectId);
	}

	/// <summary>
	/// Turns player's autorun on or off.
	/// </summary>
	/// <param name="on"><c>true</c> to turn on autorun; 
	/// <c>false</c> to turn it off.</param>
	public void SetAutorun(bool on)
	{
		myHooks.SetAutorun(on);
	}

	/// <summary>
	/// Attempts to put the player in the specified combat stance. The 
	/// player must be wielding the proper weapon type (melee, bow, 
	/// magic caster) for the given combat stance.
	/// </summary>
	/// <param name="newMode">The desired combat stance.
	/// <para>1 is out of combat mode;
	/// 2 is melee attack mode;
	/// 4 is missile attack mode;
	/// 8 is magic casting mode.</para></param>
	public void SetCombatMode(CombatState newMode)
	{
		myHooks.SetCombatMode((int)newMode);
	}

	/// <summary>
	/// Moves the mouse cursor to the given coordinates, relative to the 
	/// AC window.
	/// </summary>
	/// <param name="x">The X-coordinate.</param>
	/// <param name="y">The Y-coordinate.</param>
	public void SetCursorPosition(int x, int y)
	{
		myHooks.SetCursorPosition(x, y);
	}

	/// <summary>
	/// Sets the amount of time that the player can be idle (no mouse or 
	/// keyboard input) before AC automatically logs out.  The default 
	/// value is 1200 seconds (20 minutes).
	/// </summary>
	/// <param name="timeout">The idle timeout (in seconds).</param>
	public void SetIdleTime(double timeout)
	{
		myHooks.SetIdleTime(timeout);
	}

	/// <summary>
	/// Adds a spell to the specified tab on the player's spell bar.  The 
	/// spell must be in the player's spell book.  Each spell tab can 
	/// contain only one copy of each spell.  Putting a spell onto a tab 
	/// that already contains that spell will just move the spell to the 
	/// new index.
	/// </summary>
	/// <remarks>
	/// This function does not always work if you call it multiple times 
	/// in a loop.  Consider putting the loop in the 
	/// <see cref="E:System.Windows.Forms.Timer.Tick" /> event of a 
	/// <see cref="T:System.Windows.Forms.Timer" />, and then running the 
	/// timer for one tick.
	/// </remarks>
	/// <param name="tab">The zero-based tab index to add the spell.</param>
	/// <param name="index">The zero-based slot on the tab to add the spell.
	/// If this index is greater than the number of spells on the tab, the 
	/// spell will be added to the first unused slot.</param>
	/// <param name="spellId">The ID of the spell to be added.</param>
	public void SpellTabAdd(int tab, int index, int spellId)
	{
		myHooks.SpellTabAdd(tab, index, spellId);
	}

	/// <summary>
	/// Removes a spell from the specified tab on the player's spell bar. 
	/// This function can safely be called multiple times in a row with no 
	/// time delay between calls.
	/// </summary>
	/// <param name="tab">The tab from which to remove the spell.</param>
	/// <param name="spellId">The ID of the spell to be removed.</param>
	public void SpellTabDelete(int tab, int spellId)
	{
		myHooks.SpellTabDelete(tab, spellId);
	}

	/// <summary>
	/// Accepts a trade with another player.
	/// </summary>
	public void TradeAccept()
	{
		myHooks.TradeAccept();
	}

	/// <summary>
	/// Adds an object to the trade window with another player.  The object 
	/// must be in the player's inventory.
	/// </summary>
	/// <param name="objectId">The GUID of the object to add.</param>
	public void TradeAdd(int objectId)
	{
		myHooks.TradeAdd(objectId);
	}

	/// <summary>
	/// Gets a physics object.
	/// </summary>
	/// <param name="objectId">The ID of the physics object.</param>
	/// <returns>A pointer to a physics object.</returns>
	public IntPtr PhysicsObject(int objectId)
	{
		return new IntPtr(myHooks.GetPhysicsObjectPtr(objectId));
	}

	/// <summary>
	/// Gets a weenie object.
	/// </summary>
	/// <param name="objectId">The ID of the weenie object.</param>
	/// <returns>A pointer to the weenie object.</returns>
	public IntPtr WeenieObject(int objectId)
	{
		return new IntPtr(myHooks.GetWeenieObjectPtr(objectId));
	}

	/// <summary>
	/// Declines (un-accepts) a trade with another player.
	/// </summary>
	public void TradeDecline()
	{
		myHooks.TradeDecline();
	}

	/// <summary>
	/// Clears the contents of the trade window.
	/// </summary>
	public void TradeReset()
	{
		myHooks.TradeReset();
	}

	/// <summary>
	/// Ends the current trade, leaving the trade window open.
	/// </summary>
	public void TradeEnd()
	{
		myHooks.TradeEnd();
	}

	/// <summary>
	/// Gets a UIElement instance.
	/// </summary>
	/// <param name="TypeID">The TypeID of the UIElement instance.</param>
	/// <returns>A pointer to the UIElement instance.</returns>
	public IntPtr UIElementLookup(UIElementType pUIElementType)
	{
		return new IntPtr(myHooks.UIElementLookup((int)pUIElementType));
	}

	/// <summary>
	/// Sets the position of a UIElement region in the AC window.  
	/// </summary>
	/// <param name="TypeID">The TypeID of the UIElement instance.</param>
	/// <param name="x">The x-axis position the UIElement instance.</param>
	/// <param name="y">The y-axis position of the UIElement instance.</param>
	public void UIElementMove(UIElementType pUIElementType, int x, int y)
	{
		myHooks.UIElementMove((int)pUIElementType, x, y);
	}

	/// <summary>
	/// Sets the position of a UIElement region in the AC window.  
	/// </summary>
	/// <param name="TypeID">The TypeID of the UIElement instance.</param>
	/// <param name="width">The width of the UIElement instance.</param>
	/// <param name="height">The height of the UIElement instance.</param>
	public void UIElementResize(UIElementType pUIElementType, int width, int height)
	{
		myHooks.UIElementResize((int)pUIElementType, width, height);
	}

	/// <summary>
	/// Gets the bounding box of a UIElement region in the AC window.  
	/// </summary>
	public Rectangle UIElementRegion(UIElementType pUIElementType)
	{
		tagRECT tagRECT = myHooks.UIElementRegionRect((int)pUIElementType);
		return new Rectangle(tagRECT.left, tagRECT.top, 1 + tagRECT.right - tagRECT.left, 1 + tagRECT.bottom - tagRECT.top);
	}

	/// <summary>
	/// Uses an item, such as a potion, healing kit, etc.
	/// </summary>
	/// <remarks>
	/// This command will fail if the player is busy using an item, 
	/// casting a spell, etc.  If you are using multiple items, you must 
	/// wait until the previous action is complete before attempting to 
	/// use the next item.
	/// </remarks>
	/// <param name="objectId">The GUID of the item to use.</param>
	/// <param name="useState">The purpose of this argument is not 
	/// entirely known.  Valid values appear to be 0 and 1: 0 uses
	/// an item by itself (like a potion); 1 uses an item on the current
	/// selection.</param>
	public void UseItem(int objectId, int useState)
	{
		myHooks.UseItem(objectId, useState);
	}

	/// <summary>
	/// Uses an item, such as a potion, healing kit, casts the spell on a
	/// wand/orb, etc.
	/// </summary>
	/// <remarks>
	/// This command will fail if the player is busy using an item, 
	/// casting a spell, etc.  If you are using multiple items, you must 
	/// wait until the previous action is complete before attempting to 
	/// use the next item.
	/// </remarks>
	/// <param name="objectId">The GUID of the item to use.</param>
	/// <param name="useState">The purpose of this argument is not 
	/// entirely known.  Valid values appear to be 0 and 1: 0 uses
	/// an item by itself (like a potion); 1 uses an item on the current
	/// selection.</param>
	/// <param name="useMethod">The purpose of this argument is not 
	/// entirely known.  It may be a target GUID for wand/orb spells, or 
	/// some other flag</param>
	public void UseItem(int objectId, int useState, int useMethod)
	{
		myHooks.UseItemRaw(objectId, useState, useMethod);
	}

	/// <summary>
	/// Buys all of the items in the buy-list. The player must have 
	/// enough pyreals and slots in the main pack to hold all of the items
	/// being bought.
	/// </summary>
	public void VendorBuyAll()
	{
		myHooks.VendorBuyAll();
	}

	/// <summary>
	/// Adds an item to the list of things to buy from a vendor.  A vendor
	/// window must be open to use this command.
	/// </summary>
	/// <param name="templateId">The GUID of the item template or item in 
	/// the vendor's inventory.  Templates are the generic items sold by 
	/// vendors, such as spell components or trade notes.</param>
	/// <param name="count">The number of the specified item to add to the 
	/// buy-list.</param>
	public void VendorAddBuyList(int templateId, int count)
	{
		myHooks.VendorBuyListAdd(templateId, count);
	}

	/// <summary>
	/// Clears the buy-list.
	/// </summary>
	public void VendorClearBuyList()
	{
		myHooks.VendorBuyListClear();
	}

	/// <summary>
	/// Sells all of the items in the sell-list.  The player must have 
	/// enough slots in the main pack to hold all of the stacks of pyreals
	/// obtained from the sale.
	/// </summary>
	public void VendorSellAll()
	{
		myHooks.VendorSellAll();
	}

	/// <summary>
	/// Adds an item to the list of things to sell to a vendor.  A vendor
	/// window must be open, and the item must be in the player's inventory.
	/// </summary>
	/// <param name="itemId">The GUID of the item to add to the sell-list.</param>
	public void VendorAddSellList(int itemId)
	{
		myHooks.VendorSellListAdd(itemId);
	}

	/// <summary>
	/// Clears the sell-list.
	/// </summary>
	public void VendorClearSellList()
	{
		myHooks.VendorSellListClear();
	}

	/// <summary>
	/// Spends experience points on a skill.
	/// </summary>
	/// <param name="skill">The skill to raise.</param>
	/// <param name="experience">The number of experience points to spend. 
	/// Cannot be more than the player's unspent experience.</param>
	/// <seealso cref="M:Decal.Adapter.Wrappers.HooksWrapper.AddAttributeExperience(Decal.Adapter.Wrappers.AttributeType,System.Int32)" />
	/// <seealso cref="M:Decal.Adapter.Wrappers.HooksWrapper.AddVitalExperience(Decal.Adapter.Wrappers.VitalType,System.Int32)" />
	public void AddSkillExperience(SkillType skill, int experience)
	{
		myHooks.AddSkillExp((eSkill)skill, experience);
	}

	/// <summary>
	/// Spends experience points on an attribute.
	/// </summary>
	/// <param name="attrib">The attribute to raise.</param>
	/// <param name="experience">The number of experience points to spend. 
	/// Cannot be more than the player's unspent experience.</param>
	/// <seealso cref="M:Decal.Adapter.Wrappers.HooksWrapper.AddSkillExperience(Decal.Adapter.Wrappers.SkillType,System.Int32)" />
	/// <seealso cref="M:Decal.Adapter.Wrappers.HooksWrapper.AddVitalExperience(Decal.Adapter.Wrappers.VitalType,System.Int32)" />
	public void AddAttributeExperience(AttributeType attrib, int experience)
	{
		myHooks.AddAttributeExp((eAttribute)attrib, experience);
	}

	/// <summary>
	/// Spends experience points on a vital.
	/// </summary>
	/// <param name="vital">The vital to raise.</param>
	/// <param name="experience">The number of experience points to spend. 
	/// Cannot be more than the player's unspent experience.</param>
	/// <seealso cref="M:Decal.Adapter.Wrappers.HooksWrapper.AddAttributeExperience(Decal.Adapter.Wrappers.AttributeType,System.Int32)" />
	/// <seealso cref="M:Decal.Adapter.Wrappers.HooksWrapper.AddSkillExperience(Decal.Adapter.Wrappers.SkillType,System.Int32)" />
	public void AddVitalExperience(VitalType vital, int experience)
	{
		myHooks.AddVitalExp((eVital)vital, experience);
	}

	int IIndexedValueProvider.GetIndexedObject(hookIndexType index, int item)
	{
		int result = 0;
		switch (index)
		{
		case hookIndexType.Attribute:
			result = myHooks.get_Attribute(item);
			break;
		case hookIndexType.AttributeClicks:
			result = myHooks.get_AttributeClicks((eAttribute)item);
			break;
		case hookIndexType.AttributeStart:
			result = myHooks.get_AttributeStart((eAttribute)item);
			break;
		case hookIndexType.AttributeTotalXP:
			result = myHooks.get_AttributeTotalXP((eAttribute)item);
			break;
		case hookIndexType.Skill:
			result = myHooks.get_Skill(item);
			break;
		case hookIndexType.SkillClicks:
			result = myHooks.get_SkillClicks((eSkill)item);
			break;
		case hookIndexType.SkillFreePoints:
			result = myHooks.get_SkillFreePoints((eSkill)item);
			break;
		case hookIndexType.SkillTotalXP:
			result = myHooks.get_SkillTotalXP((eSkill)item);
			break;
		case hookIndexType.SkillTrainLevel:
			result = (int)myHooks.get_SkillTrainLevel((eSkill)item);
			break;
		case hookIndexType.Vital:
			result = myHooks.get_Vital(item);
			break;
		case hookIndexType.VitalClicks:
			result = myHooks.get_VitalClicks((eVital)item);
			break;
		case hookIndexType.VitalTotalXP:
			result = myHooks.get_VitalTotalXP((eVital)item);
			break;
		case hookIndexType.Misc:
			result = myHooks.get_Misc(item);
			break;
		}
		return result;
	}
}
