class AttachMagazineActionReciveData : ActionReciveData
{
	ref InventoryLocation  m_ilOldMagazine;
}
class AttachMagazineActionData : ActionData
{
	ref InventoryLocation  m_ilOldMagazine;
	Magazine m_oldMagazine;
}

class FirearmActionAttachMagazine : FirearmActionBase
{	
	//-----------------------------------------------------
	// 	Action events and methods
	//-----------------------------------------------------
	void FirearmActionAttachMagazine() 
	{
		m_Text = "#attach";
	}	
	
	override int GetActionCategory()
	{
		return AC_SINGLE_USE;
	}
	
	override bool ActionCondition( PlayerBase player, ActionTarget target, ItemBase item ) //condition for action
	{
		if (!super.ActionCondition( player, target, item ))
			return false;
		
		HumanCommandWeapons hcw = player.GetCommandModifier_Weapons();
		Magazine mag = Magazine.Cast(target.GetObject());	
		Weapon_Base wpn = Weapon_Base.Cast(item);	
		return mag && (player.GetWeaponManager().CanAttachMagazine(wpn,mag) || player.GetWeaponManager().CanSwapMagazine(wpn,mag)) && (!hcw || hcw.GetRunningAction() != WeaponActions.RELOAD);
	}
	
	override bool ActionConditionContinue( ActionData action_data )
	{
		return true;
	}
	
	override ActionData CreateActionData()
	{
		AttachMagazineActionData action_data = new AttachMagazineActionData;
		return action_data;
	}
	
	
	override void WriteToContext(ParamsWriteContext ctx, ActionData action_data)
	{
		super.WriteToContext(ctx, action_data);
		
		AttachMagazineActionData action_data_am = AttachMagazineActionData.Cast(action_data);
		
		action_data_am.m_ilOldMagazine.WriteToContext(ctx);
	}
	
	override bool ReadFromContext(ParamsReadContext ctx, out ActionReciveData action_recive_data )
	{
		if (!action_recive_data)
		{
			action_recive_data = new AttachMagazineActionReciveData;
		}
		
		super.ReadFromContext(ctx, action_recive_data);
		
		InventoryLocation il = new InventoryLocation;		
		if (!il.ReadFromContext(ctx))
			return false;
		
		AttachMagazineActionReciveData recive_data_am = AttachMagazineActionReciveData.Cast(action_recive_data);
		recive_data_am.m_ilOldMagazine = il;
		
		return true;
	}
	
	override void HandleReciveData(ActionReciveData action_recive_data, ActionData action_data)
	{
		AttachMagazineActionReciveData recive_data_am = AttachMagazineActionReciveData.Cast(action_recive_data);
		AttachMagazineActionData action_data_am = AttachMagazineActionData.Cast(action_data);
		
		action_data.m_MainItem = action_recive_data.m_MainItem;
		if (!action_recive_data.m_Target)
		{
			action_data.m_Target = new ActionTarget(NULL, NULL, -1, vector.Zero, 0); 
		}
		else
		{
			action_data.m_Target = action_recive_data.m_Target;
		}
		action_data_am.m_ilOldMagazine = recive_data_am.m_ilOldMagazine;
	}
	
	override bool Post_SetupAction( ActionData action_data )
	{
		if ( !GetGame().IsDedicatedServer() )
		{
			Weapon_Base wpn = Weapon_Base.Cast(action_data.m_MainItem);
			int muzzle_index = wpn.GetCurrentMuzzle();
				
			AttachMagazineActionData am_action_data = AttachMagazineActionData.Cast(action_data);
			am_action_data.m_oldMagazine = wpn.GetMagazine(muzzle_index);
				
			InventoryLocation new_il = new InventoryLocation;

			if (!action_data.m_Player.GetWeaponManager().PrepareInventoryLocationForMagazineSwap(wpn, Magazine.Cast(action_data.m_Target.GetObject()), new_il))
			{
				return false;
			}
			am_action_data.m_ilOldMagazine = new_il;
		}
		return true;
	}
	
	override bool InventoryReservation( ActionData action_data)
	{
		if( (IsLocal() || !UseAcknowledgment()) && IsInstant() )
			return true;
		
		bool success = true;
		InventoryLocation oldMagTargetInventoryLocation = NULL;
		InventoryLocation targetInventoryLocation = NULL;
		InventoryLocation handInventoryLocation = NULL;
		
		PlayerBase player = action_data.m_Player;
		AttachMagazineActionData am_action_data = AttachMagazineActionData.Cast(action_data);
		
		Weapon_Base wpn = Weapon_Base.Cast(action_data.m_MainItem);
		int muzzle_index = wpn.GetCurrentMuzzle();
		
		Magazine new_mag = Magazine.Cast(action_data.m_Target.GetObject());
		
		if (am_action_data.m_oldMagazine)
		{
			oldMagTargetInventoryLocation = new InventoryLocation;
			if ( action_data.m_Player.GetInventory().HasInventoryReservation( am_action_data.m_oldMagazine, am_action_data.m_ilOldMagazine) )
			{
				success = false;
			}
			else
			{
				player.GetInventory().AddInventoryReservationEx(am_action_data.m_oldMagazine,am_action_data.m_ilOldMagazine,GameInventory.c_InventoryReservationTimeoutMS);
			}
		}
		
		if (success)
		{
			targetInventoryLocation = new InventoryLocation;
			targetInventoryLocation.SetAttachment( wpn, new_mag, InventorySlots.MAGAZINE);
			if ( action_data.m_Player.GetInventory().HasInventoryReservation( new_mag, targetInventoryLocation) )
			{
				success = false;
				if (am_action_data.m_oldMagazine)
				{
					player.GetInventory().ClearInventoryReservation(am_action_data.m_oldMagazine,am_action_data.m_ilOldMagazine);
				}
			}
			else
			{
				action_data.m_Player.GetInventory().AddInventoryReservationEx( new_mag, targetInventoryLocation, GameInventory.c_InventoryReservationTimeoutMS);
			}
		}
	
		if (success)
		{
			handInventoryLocation = new InventoryLocation;
			handInventoryLocation.SetHands(action_data.m_Player, wpn);
		
			if ( action_data.m_Player.GetInventory().HasInventoryReservation( wpn, handInventoryLocation) )
			{
				if (am_action_data.m_oldMagazine)
				{
					player.GetInventory().ClearInventoryReservation(am_action_data.m_oldMagazine,am_action_data.m_ilOldMagazine);
				}
				player.GetInventory().ClearInventoryReservation(new_mag, targetInventoryLocation);
				success = false;
			}
			else
			{
				action_data.m_Player.GetInventory().AddInventoryReservationEx( wpn, handInventoryLocation, GameInventory.c_InventoryReservationTimeoutMS);
			}				
		}
		
		if ( success )
		{
			if (am_action_data.m_ilOldMagazine)
				action_data.m_ReservedInventoryLocations.Insert(am_action_data.m_ilOldMagazine);
			
			if (targetInventoryLocation)
				action_data.m_ReservedInventoryLocations.Insert(targetInventoryLocation);
			
			if (handInventoryLocation)
				action_data.m_ReservedInventoryLocations.Insert(handInventoryLocation);
		}
		
		return success;
	}

	override void Start( ActionData action_data )
	{
		super.Start( action_data );
		AttachMagazineActionData action_data_am = AttachMagazineActionData.Cast(action_data);
		Weapon_Base wpn = Weapon_Base.Cast(action_data.m_MainItem);
		Magazine mag = Magazine.Cast(action_data.m_Target.GetObject());	
		ClearInventoryReservationEx(action_data);
		if ( action_data.m_Player.GetWeaponManager().CanAttachMagazine(wpn,mag,false) )
			action_data.m_Player.GetWeaponManager().AttachMagazine(mag, this);
		else
			action_data.m_Player.GetWeaponManager().SwapMagazineEx(mag, action_data_am.m_ilOldMagazine, this);
		 InventoryReservation(action_data);
	}
	
	override bool CanBePerformedFromInventory()
	{
		return true;
	}
	
	override bool CanBePerformedFromQuickbar()
	{
		return true;
	}
};


class FirearmActionAttachMagazineQuick : FirearmActionBase
{	
	void FirearmActionAttachMagazineQuick() 
	{
	}	
	
	override bool ActionCondition( PlayerBase player, ActionTarget target, ItemBase item ) //condition for action
	{
		if (!super.ActionCondition( player, target, item ))
			return false;
		
		HumanCommandWeapons hcw = player.GetCommandModifier_Weapons();
		if (hcw && hcw.GetRunningAction() == WeaponActions.RELOAD)
			return false;
		
		Magazine magazine;
		#ifdef SERVER
		magazine = Magazine.Cast(target.GetObject());
		#else
		magazine = Magazine.Cast(player.GetWeaponManager().GetPreparedMagazine());
		#endif
		if (!magazine)
			return false;

		MagazineStorage mag = MagazineStorage.Cast(magazine);
		if (!mag)
			return false;
		
		Weapon weapon = Weapon.Cast(item);
		bool isLoadedMag = false;
		
		for (int i = 0, count = weapon.GetMuzzleCount(); i < count; ++i)
			isLoadedMag |= ( mag == weapon.GetMagazine( i ) );
		
		return !isLoadedMag;
	}
	
	override ActionData CreateActionData()
	{
		AttachMagazineActionData action_data = new AttachMagazineActionData;
		return action_data;
	}
	
	
	override void WriteToContext(ParamsWriteContext ctx, ActionData action_data)
	{
		super.WriteToContext(ctx, action_data);
		
		AttachMagazineActionData action_data_am = AttachMagazineActionData.Cast(action_data);
		
		action_data_am.m_ilOldMagazine.WriteToContext(ctx);
	}
	
	override bool ReadFromContext(ParamsReadContext ctx, out ActionReciveData action_recive_data )
	{
		if (!action_recive_data)
		{
			action_recive_data = new AttachMagazineActionReciveData;
		}
		
		super.ReadFromContext(ctx, action_recive_data);
		
		InventoryLocation il = new InventoryLocation;		
		if (!il.ReadFromContext(ctx))
			return false;
		
		AttachMagazineActionReciveData recive_data_am = AttachMagazineActionReciveData.Cast(action_recive_data);
		recive_data_am.m_ilOldMagazine = il;
		
		return true;
	}
	
	override void HandleReciveData(ActionReciveData action_recive_data, ActionData action_data)
	{
		AttachMagazineActionReciveData recive_data_am = AttachMagazineActionReciveData.Cast(action_recive_data);
		AttachMagazineActionData action_data_am = AttachMagazineActionData.Cast(action_data);
		
		action_data.m_MainItem = action_recive_data.m_MainItem;
		if (!action_recive_data.m_Target)
		{
			action_data.m_Target = new ActionTarget(NULL, NULL, -1, vector.Zero, 0); 
		}
		else
		{
			action_data.m_Target = action_recive_data.m_Target;
		}
		action_data_am.m_ilOldMagazine = recive_data_am.m_ilOldMagazine;
	}
	
	override bool Post_SetupAction( ActionData action_data )
	{
		if ( !GetGame().IsDedicatedServer() )
		{
			Weapon_Base wpn = Weapon_Base.Cast(action_data.m_MainItem);
			int muzzle_index = wpn.GetCurrentMuzzle();
				
			AttachMagazineActionData am_action_data = AttachMagazineActionData.Cast(action_data);
			am_action_data.m_oldMagazine = wpn.GetMagazine(muzzle_index);
				
			ActionTarget newTarget = new ActionTarget(action_data.m_Player.GetWeaponManager().GetPreparedMagazine(), null, -1, vector.Zero, -1);
			action_data.m_Target = newTarget;
				
			InventoryLocation new_il = new InventoryLocation;

			if (!action_data.m_Player.GetWeaponManager().PrepareInventoryLocationForMagazineSwap(wpn, Magazine.Cast(action_data.m_Target.GetObject()), new_il))
			{
				return false;
			}
			am_action_data.m_ilOldMagazine = new_il;
		}
		return true;
	}
	
	override bool InventoryReservation( ActionData action_data)
	{
		if( (IsLocal() || !UseAcknowledgment()) && IsInstant() )
			return true;
		
		bool success = true;
		InventoryLocation oldMagTargetInventoryLocation = NULL;
		InventoryLocation targetInventoryLocation = NULL;
		InventoryLocation handInventoryLocation = NULL;
		
		PlayerBase player = action_data.m_Player;
		AttachMagazineActionData am_action_data = AttachMagazineActionData.Cast(action_data);
		
		Weapon_Base wpn = Weapon_Base.Cast(action_data.m_MainItem);
		int muzzle_index = wpn.GetCurrentMuzzle();
		
		Magazine new_mag = Magazine.Cast(action_data.m_Target.GetObject());
		
		if (am_action_data.m_oldMagazine)
		{
			oldMagTargetInventoryLocation = new InventoryLocation;
			if ( action_data.m_Player.GetInventory().HasInventoryReservation( am_action_data.m_oldMagazine, am_action_data.m_ilOldMagazine) )
			{
				success = false;
			}
			else
			{
				player.GetInventory().AddInventoryReservationEx(am_action_data.m_oldMagazine,am_action_data.m_ilOldMagazine,GameInventory.c_InventoryReservationTimeoutMS);
			}
		}
		
		if (success)
		{
			targetInventoryLocation = new InventoryLocation;
			targetInventoryLocation.SetAttachment( wpn, new_mag, InventorySlots.MAGAZINE);
			if ( action_data.m_Player.GetInventory().HasInventoryReservation( new_mag, targetInventoryLocation) )
			{
				success = false;
				if (am_action_data.m_oldMagazine)
				{
					player.GetInventory().ClearInventoryReservation(am_action_data.m_oldMagazine,am_action_data.m_ilOldMagazine);
				}
			}
			else
			{
				action_data.m_Player.GetInventory().AddInventoryReservationEx( new_mag, targetInventoryLocation, GameInventory.c_InventoryReservationTimeoutMS);
			}
		}
	
		if (success)
		{
			handInventoryLocation = new InventoryLocation;
			handInventoryLocation.SetHands(action_data.m_Player, wpn);
		
			if ( action_data.m_Player.GetInventory().HasInventoryReservation( wpn, handInventoryLocation) )
			{
				if (am_action_data.m_oldMagazine)
				{
					player.GetInventory().ClearInventoryReservation(am_action_data.m_oldMagazine,am_action_data.m_ilOldMagazine);
				}
				player.GetInventory().ClearInventoryReservation(new_mag, targetInventoryLocation);
				success = false;
			}
			else
			{
				action_data.m_Player.GetInventory().AddInventoryReservationEx( wpn, handInventoryLocation, GameInventory.c_InventoryReservationTimeoutMS);
			}				
		}
		
		if ( success )
		{
			if (am_action_data.m_ilOldMagazine)
				action_data.m_ReservedInventoryLocations.Insert(am_action_data.m_ilOldMagazine);
			
			if (targetInventoryLocation)
				action_data.m_ReservedInventoryLocations.Insert(targetInventoryLocation);
			
			if (handInventoryLocation)
				action_data.m_ReservedInventoryLocations.Insert(handInventoryLocation);
		}
		
		return success;
	}

	override void Start( ActionData action_data )
	{
		super.Start( action_data );
		AttachMagazineActionData action_data_am = AttachMagazineActionData.Cast(action_data);
		Weapon_Base wpn = Weapon_Base.Cast(action_data.m_MainItem);
		Magazine mag = Magazine.Cast(action_data.m_Target.GetObject());	
		ClearInventoryReservationEx(action_data);
		if ( action_data.m_Player.GetWeaponManager().CanAttachMagazine(wpn,mag,false) )
			action_data.m_Player.GetWeaponManager().AttachMagazine(mag, this);
		else
			action_data.m_Player.GetWeaponManager().SwapMagazineEx(mag, action_data_am.m_ilOldMagazine, this);
		 InventoryReservation(action_data);
	}
	
	override bool HasTarget()
	{
		return true;
	}
	
	override bool HasProgress()
	{
		return false;
	}
	
	override typename GetInputType()
	{
		return ContinuousWeaponManipulationActionInput;
	} 
	
	override void CreateConditionComponents()  
	{
		m_ConditionItem = new CCINonRuined();
		m_ConditionTarget = new CCTSelf;
	}
};