class ActionRestrainTargetCB : ActionContinuousBaseCB
{
	const float DEFAULT_RESTRAIN_TIME = 2;
	
	override void CreateActionComponent()
	{
		float time = DEFAULT_RESTRAIN_TIME;
		
		if ( m_ActionData.m_MainItem.ConfigIsExisting("RestrainTime") )
		{
			time = m_ActionData.m_MainItem.ConfigGetFloat("RestrainTime");
		}
		
		if ( m_ActionData.m_Player.IsQuickRestrain() )
		{
			time = DEBUG_QUICK_UNRESTRAIN_TIME;
		}
		
		m_ActionData.m_ActionComponent = new CAContinuousTime(time);
	}
};

class ActionRestrainTarget: ActionContinuousBase
{	
	void ActionRestrainTarget()
	{
		m_CallbackClass = ActionRestrainTargetCB;
		m_CommandUID = DayZPlayerConstants.CMD_ACTIONFB_RESTRAINTARGET;
		m_FullBody = true;
		m_StanceMask = DayZPlayerConstants.STANCEMASK_ERECT | DayZPlayerConstants.STANCEMASK_CROUCH;
		m_SpecialtyWeight = UASoftSkillsWeight.PRECISE_LOW;
		m_Text = "#restrain";
	}
	
	override void CreateConditionComponents()  
	{	
		m_ConditionTarget = new CCTMan(UAMaxDistances.DEFAULT);
		m_ConditionItem = new CCINonRuined;
	}

	override bool ActionCondition( PlayerBase player, ActionTarget target, ItemBase item )
	{
		PlayerBase other_player = PlayerBase.Cast(target.GetObject());
		if (!other_player)
			return false;
		if ( player.GetInstanceType() == DayZPlayerInstanceType.INSTANCETYPE_SERVER )
		{
			return other_player.CanBeRestrained();
		}
		else
		{
			return !other_player.IsRestrained();
		}

	}
	
	override int GetStanceMask(PlayerBase player)
	{
		if ( player.IsPlayerInStance(DayZPlayerConstants.STANCEMASK_CROUCH | DayZPlayerConstants.STANCEMASK_PRONE))
			return DayZPlayerConstants.STANCEMASK_CROUCH;
		else
			return DayZPlayerConstants.STANCEMASK_ERECT;
	}

	override bool ActionConditionContinue(ActionData action_data)
	{
		PlayerBase target_player = PlayerBase.Cast(action_data.m_Target.GetObject());
		
		if ( GetGame().IsServer() && GetGame().IsMultiplayer() )
		{
			if ( target_player.IsSurrendered() || !target_player.CanBeRestrained() )
			{
				return false;
			}
		}
		if ( GetGame().IsServer() )
		{
			ActionRestrainTargetCB callback = ActionRestrainTargetCB.Cast(action_data.m_Callback);
			
			if ( callback.GetActionComponentProgress() > 0.75 && !target_player.IsRestrainPrelocked() )
			{
				target_player.SetRestrainPrelocked(true);
			}
			
			return !GetGame().GetMission().IsPlayerDisconnecting(target_player);
			
		}
		return true;
	}
	
	override void OnStartServer(ActionData action_data)
	{
		super.OnStartServer(action_data);
		
		PlayerBase target_player = PlayerBase.Cast(action_data.m_Target.GetObject());
		if ( target_player.IsSurrendered() )
		{
			SurrenderDataRestrain sdr = new SurrenderDataRestrain;
			target_player.EndSurrenderRequest(sdr);
		}
		else if ( target_player.IsEmotePlaying() )
		{
			target_player.m_EmoteManager.ServerRequestEmoteCancel();
		}
		
		target_player.SetRestrainStarted(true);
	}
	
	override void OnEndServer(ActionData action_data)
	{
		super.OnEndServer(action_data);
		
		PlayerBase target_player = PlayerBase.Cast(action_data.m_Target.GetObject());
		if (target_player)
		{
			target_player.SetRestrainStarted(false);
			target_player.SetRestrainPrelocked(false);
		}
	}

	override void OnFinishProgressServer( ActionData action_data )
	{
		PlayerBase target_player = PlayerBase.Cast(action_data.m_Target.GetObject());
		PlayerBase source_player = PlayerBase.Cast(action_data.m_Player);
		
		if (CanReceiveAction(action_data.m_Target) && !target_player.IsRestrained())
		{
			EntityAI item_in_hands_target = target_player.GetHumanInventory().GetEntityInHands();
			EntityAI item_in_hands_source = source_player.GetHumanInventory().GetEntityInHands();
			
			if ( !item_in_hands_source )
			{
				Error("Restraining target failed, nothing in hands");
				return;
			}
	
			string new_item_name = MiscGameplayFunctions.ObtainRestrainItemTargetClassname(item_in_hands_source);
			if (item_in_hands_target)
			{
				ChainedDropAndRestrainLambda lambda2 = new ChainedDropAndRestrainLambda(item_in_hands_target, item_in_hands_target.GetType(), target_player, false, source_player);
				MiscGameplayFunctions.TurnItemInHandsIntoItemEx(target_player, lambda2);
			}
			else
			{
				RestrainTargetPlayerLambda lambda = new RestrainTargetPlayerLambda(item_in_hands_source, new_item_name, target_player);
				source_player.LocalReplaceItemInHandsWithNewElsewhere(lambda);
			}
		}
	}
	
	override void OnFinishProgressClient( ActionData action_data )
	{
		super.OnFinishProgressClient( action_data );
		
		GetGame().GetAnalyticsClient().OnActionRestrain();
	}
};

class ChainedDropAndRestrainLambda : DestroyItemInCorpsesHandsAndCreateNewOnGndLambda
{
	PlayerBase m_SourcePlayer;
	ExplosivesBase m_PairedExplosive;

	void ChainedDropAndRestrainLambda (EntityAI old_item, string new_item_type, PlayerBase player, bool destroy = false, PlayerBase src_player = null)
	{
		m_SourcePlayer = src_player;
	}
	
	override void OnSuccess(EntityAI new_item)
	{
		super.OnSuccess(new_item);
		
		if (m_PairedExplosive)
		{
			m_PairedExplosive.UnpairRemote();
			ItemBase ib = ItemBase.Cast(new_item);
			ib.PairWithDevice(m_PairedExplosive);
			m_PairedExplosive.Arm();
		}
		
		// as soon as previous op is finish, start another one
		EntityAI item_in_hands_source = m_SourcePlayer.GetHumanInventory().GetEntityInHands();
		if (item_in_hands_source)
		{
			string new_item_name = MiscGameplayFunctions.ObtainRestrainItemTargetClassname(item_in_hands_source);
			RestrainTargetPlayerLambda lambda = new RestrainTargetPlayerLambda(item_in_hands_source, new_item_name, m_Player);
			if (m_SourcePlayer)
				m_SourcePlayer.LocalReplaceItemInHandsWithNewElsewhere(lambda);
			else
				Error("ChainedDropAndRestrainLambda: missing source player!");
		}
		else
		{
			Error("ChainedDropAndRestrainLambda: missing source item in hands!");
		}
	}
	
	override void CopyOldPropertiesToNew (notnull EntityAI old_item, EntityAI new_item)
	{
		super.CopyOldPropertiesToNew(old_item, new_item);
		RemoteDetonatorTrigger trigger = RemoteDetonatorTrigger.Cast(old_item);
		if (trigger)
			m_PairedExplosive = ExplosivesBase.Cast(trigger.GetControlledDevice());
	}
}


class RestrainTargetPlayerLambda : TurnItemIntoItemLambda
{
	PlayerBase m_TargetPlayer;

	void RestrainTargetPlayerLambda (EntityAI old_item, string new_item_type, PlayerBase player)
	{
		m_TargetPlayer = player;
		
		InventoryLocation targetHnd = new InventoryLocation;
		targetHnd.SetHands(m_TargetPlayer, null);
		OverrideNewLocation(targetHnd);
	}
	
	override void OnSuccess(EntityAI new_item)
	{
		super.OnSuccess(new_item);

		m_TargetPlayer.SetRestrained(true);
		m_TargetPlayer.OnItemInHandsChanged();
	}
};

class SurrenderDataRestrain extends SurrenderData
{
	override void End()
	{
		
	}
}