class ActionPushObjectDataReceiveData : ActionReciveData
{
	Object m_PushTarget;
}

class ActionPushObjectData : ActionData
{
	bool m_NeedUpdate;
	int m_EndType = 0;
	vector m_Origin = "0 0 0";
	
	Object m_Object;
}

class CAContinuousRepeatPushObject : CAContinuousRepeat
{
	void CAContinuousRepeatPushObject(float time_to_complete_action)
	{
		m_DefaultTimeToComplete = time_to_complete_action;
	}
	
	override int Execute(ActionData action_data)
	{
		if (!action_data.m_Player)
			return UA_ERROR;

		if (m_TimeElpased < m_TimeToComplete)
		{
			m_TimeElpased += action_data.m_Player.GetDeltaT();
			m_TotalTimeElpased += action_data.m_Player.GetDeltaT();
			return UA_PROCESSING;
		}
		else
		{
			m_SpentUnits.param1 = m_TimeElpased;
			SetACData(m_SpentUnits);
			m_TimeElpased = m_TimeToComplete - m_TimeElpased;
			OnCompletePogress(action_data);

			return UA_CANCEL;
		}
		
		return UA_FINISHED;
	}
}

class ActionPushObjectCB : ActionContinuousBaseCB
{
	protected float PUSH_FORCE_INCREMENT = 3000.0;
	protected ActionPushObjectData m_ActionDataPushObject;

	override void CreateActionComponent()
	{
		m_ActionData.m_ActionComponent = new CAContinuousRepeatPushObject(10);
	}
	
	override void ProgressActionComponent()
	{
		super.ProgressActionComponent();
		
		ActionPushObjectData data = ActionPushObjectData.Cast(m_ActionData);
		ApplyForce(data);
	}
	
	override void EndActionComponent()
	{
		m_ActionDataPushObject = ActionPushObjectData.Cast(m_ActionData);
		
		if (!m_ActionDataPushObject)
		{
			super.EndActionComponent();
			return;
		}
		
		if (m_ActionDataPushObject.m_State == UA_FINISHED)
		{
			if (m_ActionDataPushObject.m_EndType == 1)
				SetCommand(DayZPlayerConstants.CMD_ACTIONINT_FINISH);
			else if (m_ActionDataPushObject.m_EndType == 0)
				SetCommand(DayZPlayerConstants.CMD_ACTIONINT_END);
		}
		else if (m_ActionDataPushObject.m_State == UA_CANCEL)
		{
			ActionContinuousBase action = ActionContinuousBase.Cast(m_ActionDataPushObject.m_Action);
			if (action.HasAlternativeInterrupt())
				SetCommand(DayZPlayerConstants.CMD_ACTIONINT_FINISH);
			else
				SetCommand(DayZPlayerConstants.CMD_ACTIONINT_END);

			return;
		}

		m_ActionDataPushObject.m_State = UA_FINISHED;
	}
	
	protected void ApplyForce(ActionPushObjectData actionData)
	{	
		Object entity = actionData.m_Object;
				
		float bodyMass = dBodyGetMass(entity);
		float invBodyMass = 1.0 / bodyMass;
		float force = bodyMass * PUSH_FORCE_INCREMENT;
		float easedProgress = Easing.EaseInOutSine(actionData.m_ActionComponent.GetProgress());
		
		vector impulse 	= force * actionData.m_Player.GetDirection() * invBodyMass * easedProgress;
		
		actionData.m_Player.DepleteStamina(EStaminaModifiers.PUSH_CAR);

		dBodyApplyImpulseAt(entity, impulse, entity.ModelToWorld(vector.Zero));	
	}
}

class ActionPushObject : ActionContinuousBase
{

	override typename GetInputType()
	{
		return ContinuousInteractActionInput;
	}
	
		override void CreateConditionComponents()
	{
		m_ConditionItem		= new CCINotPresent();
		m_ConditionTarget	= new CCTCursorNoRuinCheck(UAMaxDistances.DEFAULT);
	}
	
	override bool HasAlternativeInterrupt()
	{
		return true;
	}
	
	override ActionData CreateActionData()
	{
		ActionPushObjectData data = new ActionPushObjectData();
		return data;
	}
	
	override bool ActionCondition(PlayerBase player, ActionTarget target, ItemBase item)
	{
		if (!player.IsPlayerInStance(DayZPlayerConstants.STANCEMASK_ERECT|DayZPlayerConstants.STANCEMASK_CROUCH))
			return false;
		
		if (player.PhysicsGetLinkedEntity() == target.GetObject())
			return false;
		
		if (!player.GetSurfaceType())
			return false;

		if (!player.CanConsumeStamina(EStaminaConsumers.PUSH))
			return false;
		
		return true;
	}
	
	override void OnUpdate(ActionData action_data)
	{
		super.OnUpdate(action_data);

		ActionPushObjectData data = ActionPushObjectData.Cast(action_data);		
		if (data.m_NeedUpdate)
		{
			if (!data.m_Player.CanConsumeStamina(EStaminaConsumers.PUSH))
			{
				data.m_State 		= UA_CANCEL;
				data.m_NeedUpdate 	= false;

				return;
			}
	
			if (vector.Distance(data.m_Object.GetPosition(), data.m_Origin) > 0.5)
			{
				data.m_State 		= UA_FINISHED;
				data.m_EndType 		= 0;
				data.m_NeedUpdate 	= false;
			}
		}
	}
	
	override void OnStart(ActionData action_data)
	{
		super.OnStart(action_data);
		
		ActionPushObjectData data 	= ActionPushObjectData.Cast(action_data);
		data.m_Object 			= GetPushObject(action_data.m_Target);
		data.m_Origin 			= data.m_Object.GetPosition();
		data.m_NeedUpdate 		= true;
	}
			
	override void OnEndInput(ActionData action_data)
	{
		super.OnEndInput(action_data);
		
		ActionPushObjectData data 	= ActionPushObjectData.Cast(action_data);
		data.m_State 			= UA_CANCEL;
		data.m_EndType 			= 1;
		data.m_NeedUpdate 		= false;
	}
	
	protected Object GetPushObject(ActionTarget target)
	{
		if (target.IsProxy())
			return target.GetParent();
		
		return target.GetObject();
	}
}