/**@class		HumanInventory
 * @brief		inventory for plain man/human
 *
 * HumanInventory has simple synchronous operations only, i.e.
 * no animations are involved while adding/removing/swapping to/from hands.
 *
 * Animations are added on higher level of hierarchy (DayZPlayerInventory for example)
 **/
class HumanInventory : GameInventory
{	
	int m_syncClearUserReservationindex = -1;
	//int m_UserReservationToClear = -1;
	/**@fn			GetEntityInHands
	 * @return		entity in hands
	 **/
	proto native EntityAI GetEntityInHands();

	/**@fn			CanAddEntityInHands
	 * @brief		alternative for TestAddEntityInHands(e, true, true, true);
	 **/
	proto native bool CanAddEntityInHands(EntityAI e);

	/**@fn			TestAddEntityInHands
	 * @param[in]	e	entity to test for taking in hands
	 * @param[in]	do_item_check		deny if entity is not InventoryItem
	 * @param[in]	do_occupancy_test		deny if there is item in hands already
	 * @param[in]	do_script_check		deny if script conditions fail
	 * @return		true if item passed all tests
	 **/
	proto native bool TestAddEntityInHands(EntityAI e, bool do_resevation_check, bool do_item_check, bool do_lock_check, bool do_occupancy_test, bool do_script_check);

	/**@fn			CanRemoveEntityInHands
	 * @return		true if entity can be removed from hands
	 **/
	proto native bool CanRemoveEntityInHands();

	proto native bool CanOpenInventory();

	/**@fn			CreateInHands
	 * @brief		creates new entity in hands
	 * @param[in]	typeName type name of the entity to be created
	 * @return		new entity or null otherwise
	 **/
	proto native EntityAI CreateInHands(string typeName);

	proto native int GetUserReservedLocationCount();
	proto native int FindUserReservedLocationIndex(notnull EntityAI e);
	proto native int FindCollidingUserReservedLocationIndex(notnull EntityAI e, notnull InventoryLocation dst);
	proto native void GetUserReservedLocation(int index, out notnull InventoryLocation dst);
	proto native int FindFirstUserReservedLocationIndexForContainer(notnull EntityAI e);
	
	proto native void SetUserReservedLocation(notnull EntityAI eai, notnull InventoryLocation dst);
	proto native void ClearUserReservedLocation(notnull EntityAI eai);
	proto native bool ClearUserReservedLocationAtIndex(int index);
	proto native void ClearUserReservedLocationForContainer(notnull EntityAI eai);
	proto native bool GetDebugFlag();

	/**
	 * @fn		CreateInInventory
	 * @brief	creates entity somewhere in inventory
	 *
	 * @param[in]	type	\p		item type to be placed in inventory
	 * @return	created entity
	 **/
	override EntityAI CreateInInventory(string type)
	{
		EntityAI newEntity = super.CreateInInventory(type);
		if (newEntity == null)
			newEntity = CreateInHands(type);
		return newEntity;
	}
	
	void ClearUserReservedLocationSynced(notnull EntityAI eai)
	{
		if (GetGame().IsClient())
			m_syncClearUserReservationindex = FindUserReservedLocationIndex(eai);
		else if (!GetGame().IsMultiplayer())
		{
			ClearUserReservedLocation(eai);
			eai.GetOnReleaseLock().Invoke(eai);
		}
			
	}
	
	void ClearUserReservedLocationAtIndexSynced(int index)
	{
		if (GetGame().IsClient())
			m_syncClearUserReservationindex = index;
		else if (!GetGame().IsMultiplayer())
		{
			ClearUserReservedLocationAtIndex(index);
			
			InventoryLocation il = new InventoryLocation();
			
			GetUserReservedLocation(index,il);
			EntityAI item = il.GetItem();
			item.GetOnReleaseLock().Invoke(item);
		}
			
	}

	Man GetManOwner()
	{
		return Man.Cast(GetInventoryOwner());
	}

	bool HasEntityInHands(EntityAI e)
	{
		return e == GetEntityInHands();
	}
	
	bool ProcessHandEvent(HandEventBase e);

	void OnHandsStateChanged(HandStateBase src, HandStateBase dst);
	void OnHandsExitedStableState(HandStateBase src, HandStateBase dst);
	void OnHandsEnteredStableState(HandStateBase src, HandStateBase dst);
	
	void OnEntityInHandsCreated(InventoryLocation src)
	{
		InventoryLocation cpy = new InventoryLocation();
		cpy.Copy(src);
		if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] OnEntityInHandsCreated src=" + InventoryLocation.DumpToStringNullSafe(cpy));
		ProcessHandEvent(new HandEventCreated(GetManOwner(), src));
	}

	void OnEntityInHandsDestroyed(InventoryLocation src)
	{
		InventoryLocation cpy = new InventoryLocation();
		cpy.Copy(src);
		if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] OnEntityInHandsDestroyed src=" + InventoryLocation.DumpToStringNullSafe(cpy));
		ProcessHandEvent(new HandEventDestroyed(GetManOwner(), cpy));
	}

	bool HandEvent(InventoryMode mode, HandEventBase e)
	{
		return true;
	}
	
	override bool DropEntity(InventoryMode mode, EntityAI owner, notnull EntityAI item)
	{
		InventoryLocation src = new InventoryLocation();
		if (item && item.GetInventory() && item.GetInventory().GetCurrentInventoryLocation(src))
		{
			switch (src.GetType())
			{
				case InventoryLocationType.HANDS:
					if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] HumanInventory::DropEntity(" + typename.EnumToString(InventoryMode, mode) + ") item=" + item);
					HandEvent(mode, new HandEventDrop(GetManOwner(), src));
					return true;

				default:
					return super.DropEntity(mode, owner, item);
			}
		}

		Error("No inventory location");
		return false;
	}
	
	bool ThrowEntity(EntityAI item, vector dir, float force)
	{
		if (GetGame().IsServer() && GetGame().IsMultiplayer())
			return false;
		
		DayZPlayer player = DayZPlayer.Cast(item.GetHierarchyRootPlayer());
		InventoryMode invMode = InventoryMode.PREDICTIVE;
				
		if (player.NeedInventoryJunctureFromServer(item, item.GetHierarchyParent(), null))
			invMode = InventoryMode.JUNCTURE;
		
		InventoryLocation src = new InventoryLocation();
		if (item && item.GetInventory() && item.GetInventory().GetCurrentInventoryLocation(src))
		{
			switch (src.GetType())
			{
				case InventoryLocationType.HANDS:
					if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] HumanInventory::ThrowEntity item=" + item);
					HandEventThrow throwEvent = new HandEventThrow(GetManOwner(), src);
					throwEvent.SetForce(dir * force);
					HandEvent(invMode, throwEvent);
					return true;

				default:
					DropEntity(invMode, player, item);
					return true;
			}
		}
		Error("No inventory location");
		return false;
	}
		
	bool RedirectToHandEvent(InventoryMode mode, notnull InventoryLocation src, notnull InventoryLocation dst)
	{
		if (src.GetType() == InventoryLocationType.HANDS)
		{
			Man man_src = Man.Cast(src.GetParent());
			if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] HI::RedirectToHandEvent - source location == HANDS, player has to handle this");
			
			EntityAI item = src.GetItem();
			
			int r_index = FindUserReservedLocationIndex(item);

			if (r_index >= 0)
			{
				InventoryLocation r_il = new InventoryLocation();
				GetUserReservedLocation(r_index,r_il);

				ClearUserReservedLocationAtIndex(r_index);
				int r_type = r_il.GetType();
				if (r_type == InventoryLocationType.CARGO || r_type == InventoryLocationType.PROXYCARGO)
				{
					r_il.GetParent().GetOnReleaseLock().Invoke(item);
				}
				else if (r_type == InventoryLocationType.ATTACHMENT)
				{
					r_il.GetParent().GetOnAttachmentReleaseLock().Invoke(item, r_il.GetSlot());
				}
			}
	
			man_src.GetHumanInventory().HandEvent(mode, new HandEventMoveTo(man_src, src, dst));
			return true;
		}
		
		if (dst.GetType() == InventoryLocationType.HANDS)
		{
			if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] HI::RedirectToHandEvent - dst location == HANDS, player has to handle this");
						
			Man man_dst = Man.Cast(dst.GetParent());
			man_dst.GetHumanInventory().HandEvent(mode, new HandEventTake(man_dst, src));
			return true;
		}
		return false;
	}

	override bool TakeToDst(InventoryMode mode, notnull InventoryLocation src, notnull InventoryLocation dst)
	{
		if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] Take2Dst(" + typename.EnumToString(InventoryMode, mode) + ") src=" + InventoryLocation.DumpToStringNullSafe(src) + " dst=" + InventoryLocation.DumpToStringNullSafe(dst));

		if (GetManOwner().IsAlive() && RedirectToHandEvent(mode, src, dst))
			return true;

		return super.TakeToDst(mode, src, dst);
	}

	override bool TakeEntityToInventory(InventoryMode mode, FindInventoryLocationType flags, notnull EntityAI item)
	{
		InventoryLocation src = new InventoryLocation();
		if (item.GetInventory().GetCurrentInventoryLocation(src))
		{
			InventoryLocation dst = new InventoryLocation();
			if (FindFreeLocationFor(item, flags, dst))
			{
				if (RedirectToHandEvent(mode, src, dst))
					return true;

				if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] HumanInventory::Take2Inv(" + typename.EnumToString(InventoryMode, mode) + ") item=" + item);
				return super.TakeEntityToInventory(mode, flags, item);
			}
			else
				return false; // no room
		}
		Error("HumanInventory::TakeEntityToInventory: No inventory location");
		return false;
	}

	/**
	\brief Put item into into cargo on specific cargo location
	*/
	override bool TakeEntityToCargoEx(InventoryMode mode, notnull EntityAI item, int idx, int row, int col)
	{
		InventoryLocation src = new InventoryLocation();
		if (item.GetInventory().GetCurrentInventoryLocation(src))
		{
			switch (src.GetType())
			{
				case InventoryLocationType.HANDS:
					if (GetInventoryOwner().IsAlive())
					{
						if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] HumanInventory::Take2Cgo(" + typename.EnumToString(InventoryMode, mode) + ") item=" + item + " row=" + row + " col=" + col);
						InventoryLocation dst = new InventoryLocation();
						dst.SetCargo(GetInventoryOwner(), item, idx, row, col, item.GetInventory().GetFlipCargo());

						HandEvent(mode, new HandEventMoveTo(GetManOwner(), src, dst));
						return true;
					}

					return super.TakeEntityToCargoEx(mode, item, idx, row, col);

				default:
					return super.TakeEntityToCargoEx(mode, item, idx, row, col);
			}
		}

		Error("HumanInventory::TakeEntityToCargoEx: No inventory location");
		return false;
	}

	override bool TakeEntityAsAttachmentEx(InventoryMode mode, notnull EntityAI item, int slot)
	{
		InventoryLocation src = new InventoryLocation();
		if (item.GetInventory().GetCurrentInventoryLocation(src))
		{
			switch (src.GetType())
			{
				case InventoryLocationType.HANDS:
					if (GetInventoryOwner().IsAlive())
					{
						if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] HumanInventory::Take2Att(" + typename.EnumToString(InventoryMode, mode) + ") item=" + item + " slot=" + slot);
						InventoryLocation dst = new InventoryLocation();
						EntityAI src_entity = GetInventoryOwner();
						dst.SetAttachment(src_entity, item, slot);

						HandEvent(mode, new HandEventMoveTo(GetManOwner(), src, dst));
						return true;
					}

					return super.TakeEntityAsAttachmentEx(mode, item, slot);

				default:
					return super.TakeEntityAsAttachmentEx(mode, item, slot);
			}
		}

		Error("HumanInventory::TakeEntityAsAttachmentEx: No inventory location");
		return false;
	}

	override bool SwapEntities(InventoryMode mode, notnull EntityAI item1, notnull EntityAI item2)
	{
		InventoryLocation src1, src2, dst1, dst2;
		if (GameInventory.MakeSrcAndDstForSwap(item1, item2, src1, src2, dst1, dst2))
		{
			bool handled = false;
			switch (src1.GetType())
			{
				case InventoryLocationType.HANDS:
					//! returns item to previous location, if available
					InventoryLocation fswap_dst2 = new InventoryLocation;
					if ( SwappingToPreviousLocation(item1, item2, fswap_dst2) )
					{
						if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] HumanInventory::Swap HandEventForceSwap(" + typename.EnumToString(InventoryMode, mode) + ") IH=src1=" + InventoryLocation.DumpToStringNullSafe(src1) + " src2=" + InventoryLocation.DumpToStringNullSafe(src2));
						HandEvent(mode, new HandEventForceSwap(GetManOwner(), src1, src2, dst1, fswap_dst2));
					}
					else
					{
						if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] HumanInventory::Swap HandEventSwap(" + typename.EnumToString(InventoryMode, mode) + ") src1=" + InventoryLocation.DumpToStringNullSafe(src1) + "src2=" + InventoryLocation.DumpToStringNullSafe(src2));
						HandEvent(mode, new HandEventSwap(GetManOwner(), src1, src2, dst1, dst2));
					}
					handled = true;
					break;
			}

			switch (src2.GetType())
			{
				case InventoryLocationType.HANDS:
					if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] HumanInventory::Swap HandEventSwap2(" + typename.EnumToString(InventoryMode, mode) + ") src1=" + InventoryLocation.DumpToStringNullSafe(src1) + " IH=src2=" + InventoryLocation.DumpToStringNullSafe(src2));
					HandEvent(mode, new HandEventSwap(GetManOwner(), src2, src1, dst2, dst1));
					handled = true;
					break;
			}

			if (!handled)
				return super.SwapEntities(mode, item1, item2);

			return true;
		}

		Error("HumanInventory::SwapEntities: cannot create src1, src2, dst1, dst2");
		return false;
	}

	override bool ForceSwapEntities(InventoryMode mode, notnull EntityAI item1, notnull EntityAI item2, notnull InventoryLocation item2_dst)
	{
		InventoryLocation src1, src2, dst1;
		if (GameInventory.MakeSrcAndDstForForceSwap(item1, item2, src1, src2, dst1, item2_dst))
		{
			GameInventory manOwnerInventory = GetManOwner().GetInventory();
			
			if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] HumanInventory::FSwap(" + typename.EnumToString(InventoryMode, mode) + ") dst1=" + InventoryLocation.DumpToStringNullSafe(dst1)+ " dst2=" + InventoryLocation.DumpToStringNullSafe(item2_dst));
			bool handled = false;
			switch (src1.GetType())
			{
				case InventoryLocationType.HANDS:
					if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] HumanInventory::FSwap-HND@1(" + typename.EnumToString(InventoryMode, mode) + ") src1=" + InventoryLocation.DumpToStringNullSafe(src1) + " src2=" + InventoryLocation.DumpToStringNullSafe(src2) +  " dst1=" + InventoryLocation.DumpToStringNullSafe(dst1) + " item2_dst=" + InventoryLocation.DumpToStringNullSafe(item2_dst));
					HandEventBase e = new HandEventForceSwap(GetManOwner(), src1, src2, dst1, item2_dst);
					e.ReserveInventory();
					HandEvent(mode, e);
					handled = true;
					break;

			}

			switch (src2.GetType())
			{
				case InventoryLocationType.HANDS:
					//! returns item to previous location, if available
					InventoryLocation fswap_dst2 = new InventoryLocation;
					if ( SwappingToPreviousLocation(item2, item1, fswap_dst2))
					{
						if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] HumanInventory::FSwap-PREV(" + typename.EnumToString(InventoryMode, mode) + ") src1=" + InventoryLocation.DumpToStringNullSafe(src1) + " src2=" + InventoryLocation.DumpToStringNullSafe(src2) +  " dst1=" + InventoryLocation.DumpToStringNullSafe(dst1) + " fswap_dst2=" + InventoryLocation.DumpToStringNullSafe(fswap_dst2));
						HandEvent(mode, new HandEventForceSwap(GetManOwner(), src1, src2, dst1, fswap_dst2));
					}
					else
					{
						if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] HumanInventory::FSwap-HND@2(" + typename.EnumToString(InventoryMode, mode) + ") src1=" + InventoryLocation.DumpToStringNullSafe(src1) + " src2=" + InventoryLocation.DumpToStringNullSafe(src2) +  " dst1=" + InventoryLocation.DumpToStringNullSafe(dst1) + " item2_dst=" + InventoryLocation.DumpToStringNullSafe(item2_dst));
						HandEvent(mode, new HandEventForceSwap(GetManOwner(), src1, src2, dst1, item2_dst));
					}
				
					handled = true;	
					break;
			}
			
			bool returnValue = true;

			if (!handled)
				returnValue = super.ForceSwapEntities(mode, item1, item2, item2_dst);
			
			return returnValue;
		}

		Error("HumanInventory::ForceSwapEntities: No inventory location");
		return false;
	}

	override bool LocalDestroyEntity(notnull EntityAI item)
	{
		InventoryLocation src = new InventoryLocation();
		if (item.GetInventory().GetCurrentInventoryLocation(src))
		{
			switch (src.GetType())
			{
				case InventoryLocationType.HANDS:
					if (GetInventoryOwner().IsAlive())
					{
						if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] HumanInventory::LocalDestroy inv item=" + item);
						HandEvent(InventoryMode.LOCAL, new HandEventDestroy(GetManOwner(), src));
						return true;
					}

					return super.LocalDestroyEntity(item);

				default:
					return super.LocalDestroyEntity(item);
			}
		}

		Error("LocalDestroyEntity: No inventory location");
		return false;
	}

	override bool ReplaceItemWithNew(InventoryMode mode, ReplaceItemWithNewLambdaBase lambda)
	{
		EntityAI itemInHands = GetEntityInHands();
		if (itemInHands == lambda.m_OldItem)
			return ReplaceItemInHandsWithNew(mode, lambda);

		return super.ReplaceItemWithNew(mode, lambda);
	}
	
	bool ReplaceItemElsewhereWithNewInHands(InventoryMode mode, ReplaceItemWithNewLambdaBase lambda)
	{
		return ReplaceItemInElsewhereWithNewinHandsImpl(mode, new HandEventDestroyElsewhereAndReplaceWithNewInHands(GetManOwner(), null, lambda));
	}
	
	protected bool ReplaceItemInElsewhereWithNewinHandsImpl(InventoryMode mode, HandEventBase e)
	{
		if (GetEntityInHands())
		{
			Error("[inv] HumanInventory::ReplaceItemInElsewhereWithNewinHandsImpl Item in hands, event=" + e.DumpToString());
			return false;
		}

		InventoryLocation dst = e.GetDst();
		if (dst)
		{
			switch (dst.GetType())
			{
				case InventoryLocationType.HANDS:
					if (GetInventoryOwner().IsAlive())
					{
						if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] HumanInventory::ReplaceItemInElsewhereWithNewinHandsImpl event=" + e);
						HandEvent(mode, e);
						return true;
					}

					if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] HumanInventory::ReplaceItemInElsewhereWithNewinHandsImpl DEAD_owner=" + GetInventoryOwner().GetName() +"="+ GetInventoryOwner());
					Error("HumanInventory::ReplaceItemInElsewhereWithNewinHandsImpl TODO"); // replace-with-new in corpse's hands, not implemented
					return false;

				default:
					Error("[inv] HumanInventory::ReplaceItemInElsewhereWithNewinHandsImpl src has to be hands");
					return false;
			}
		}

		Error("[inv] HumanInventory::ReplaceItemInElsewhereWithNewinHandsImpl no dst in event, event=" + e.DumpToString());
		return false;
	}

	protected bool ReplaceItemInHandsWithNewImpl(InventoryMode mode, HandEventBase e)
	{
		EntityAI itemInHands = GetEntityInHands();
		InventoryLocation src = new InventoryLocation();
		if (itemInHands && itemInHands.GetInventory().GetCurrentInventoryLocation(src))
		{
			switch (src.GetType())
			{
				case InventoryLocationType.HANDS:
					if ((mode != InventoryMode.SERVER) && GetInventoryOwner().IsAlive())
					{
						if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] HumanInventory::ReplaceItemInHandsWithNewImpl event=" + e);
						HandEvent(mode, e);
						return true;
					}

					if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] HumanInventory::ReplaceItemInHandsWithNewImpl DEAD_owner=" + GetInventoryOwner().GetName() +"="+ GetInventoryOwner());
					HandEvent(mode, e);
					return true;

				default:
					Error("[inv] HumanInventory::ReplaceItemInHandsWithNewImpl src has to be hands");
					return false;
			}
		}

		Error("[inv] HumanInventory::ReplaceItemInHandsWithNewImpl No item in hands, event=" + e.DumpToString());
		return false;
	}

	bool ReplaceItemInHandsWithNew(InventoryMode mode, ReplaceItemWithNewLambdaBase lambda)
	{
		return ReplaceItemInHandsWithNewImpl(mode, new HandEventDestroyAndReplaceWithNew(GetManOwner(), null, lambda));
	}

	bool ReplaceItemInHandsWithNewElsewhere(InventoryMode mode, ReplaceItemWithNewLambdaBase lambda)
	{
		return ReplaceItemInHandsWithNewImpl(mode, new HandEventDestroyAndReplaceWithNewElsewhere(GetManOwner(), null, lambda));
	}
	
	bool SwappingToPreviousLocation(EntityAI item1, EntityAI item2, out InventoryLocation dst)
	{
		bool SwapToPrevious = true;
		InventoryLocation src1 = new InventoryLocation();
		InventoryLocation src2 = new InventoryLocation();
		dst = new InventoryLocation();
		if (item1.GetInventory().GetCurrentInventoryLocation(src1) && item2.GetInventory().GetCurrentInventoryLocation(src2))
		{
			if (item1.m_OldLocation && item1.m_OldLocation.IsValid() && !item1.m_OldLocation.CollidesWith(src2) && item1.m_OldLocation.GetParent() && item1.m_OldLocation.GetParent().GetHierarchyRootPlayer())	
			{
				dst.Copy(item1.m_OldLocation);
				
				int count = item1.GetInventory().GetSlotIdCount();
				if (count > 0 && src2.GetType() == InventoryLocationType.ATTACHMENT) //item2 is currently attached somewhere
				{
					for (int i = 0; i < count; i++)
					{
						int slotID = item1.GetInventory().GetSlotId(i);
						if (src2.GetSlot() == slotID) //can be attached into the same slot. And will be.
							return false;
					}
				}
				
				if (!item1.m_OldLocation.GetParent().GetInventory().LocationCanAddEntity(item1.m_OldLocation))
					SwapToPrevious = false;

				if (CanSwapEntitiesEx(item1,item2))
					SwapToPrevious = false;
				
				if (SwapToPrevious)
					return true;
			}
		}
		
		return false;
	}
	
	void HandleInventoryManipulation();
	
	void Update(float delta_time)
	{
		HandleInventoryManipulation();
		if ( m_syncClearUserReservationindex != -1 && ScriptInputUserData.CanStoreInputUserData())
		{
			ScriptInputUserData ctx = new ScriptInputUserData();
			ctx.Write(INPUT_UDT_INVENTORY);
			ctx.Write(InventoryCommandType.USER_RESERVATION_CANCEL);
			ctx.Write(m_syncClearUserReservationindex);
			ctx.Send();
			
			InventoryLocation il = new InventoryLocation();
			
			GetUserReservedLocation(m_syncClearUserReservationindex,il);
			ClearUserReservedLocationAtIndex(m_syncClearUserReservationindex);
			EntityAI item = il.GetItem();
			item.GetOnReleaseLock().Invoke(item);
			m_syncClearUserReservationindex = -1;
		}
	}

	bool ValidateUserReservationCancel(inout Serializer ctx, InventoryValidation validation)
	{
		validation.m_Result = InventoryValidationResult.SUCCESS;

		int index = -1;
		if (!ctx.Read(index))
		{
			//! TODO(kumarjac): It returned true and claimed success before, is this correct?
			return true; 
		}
		
		ClearUserReservedLocationAtIndex(index);
		//m_UserReservationToClear = index;
		
		return true; 
	}
	
	bool PostDeferredEventTakeToDst(InventoryMode mode, notnull InventoryLocation src, notnull InventoryLocation dst)
	{
		return true;
	}

	
	bool PostDeferredForceSwapEntities(InventoryMode mode, notnull EntityAI item1, notnull EntityAI item2, notnull InventoryLocation dst1, notnull InventoryLocation dst2)
	{
		return true;
	}
}
