class MoveToCoverCommandTask extends AIbehaviortaskScript
{
	protected editable inlined var m_inCommand : AIArgumentMapping;
	protected var m_currentCommand : weak< AIMoveToCoverCommand >;
	private var m_coverID : Uint64;

	protected export override function Activate( context : ScriptExecutionContext )
	{
		SetUpdateInterval( context, RandomizeOffsetForUpdateInterval( 0.2 ) );
	}

	protected export override function Update( context : ScriptExecutionContext ) : AIbehaviorUpdateOutcome
	{
		var rawCommand : IScriptable;
		var typedCommand : AIMoveToCoverCommand;
		var coverID : Uint64;
		var cm : CoverManager;
		var tmpID : Uint64;
		var coverDemandHolder : CoverDemandHolder;
		rawCommand = ScriptExecutionContext.GetScriptableMappingValue( context, m_inCommand );
		typedCommand = ( ( AIMoveToCoverCommand )( rawCommand ) );
		if( !( typedCommand ) )
		{
			m_currentCommand = NULL;
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		if( typedCommand == m_currentCommand )
		{
			if( ScriptExecutionContext.GetArgumentUint64( context, 'CoverID' ) != m_coverID )
			{
				ScriptExecutionContext.DebugLog( context, 'AIMoveToCoverCommand', "Something changed current coverID, repeting command" );
				return AIbehaviorUpdateOutcome.FAILURE;
			}
			if( ShouldInterrupt( context ) )
			{
				return AIbehaviorUpdateOutcome.SUCCESS;
			}
			return AIbehaviorUpdateOutcome.IN_PROGRESS;
		}
		else if( m_currentCommand )
		{
			MoveToCoverCommandDelegate.SendGracefulInterruptionSignal( context );
			return AIbehaviorUpdateOutcome.IN_PROGRESS;
		}
		cm = GameInstance.GetCoverManager( GetGame( context ) );
		if( !( cm ) )
		{
		}
		else
		{
			coverDemandHolder = cm.GetDemandCoverHolder( typedCommand.coverNodeRef );
			coverID = coverDemandHolder.GetCoverID();
		}
		if( ( coverID == ( ( Uint64 )( 0 ) ) ) || !( cm.IsCoverValid( coverID ) ) )
		{
			ScriptExecutionContext.DebugLog( context, 'AIMoveToCoverCommand', "Trying to select invalid cover or cover with ID == 0!" );
			m_currentCommand = NULL;
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		if( typedCommand.alwaysUseStealth )
		{
			NPCPuppet.ChangeHighLevelState( ScriptExecutionContext.GetOwner( context ), gamedataNPCHighLevelState.Stealth );
		}
		m_coverID = coverID;
		tmpID = ScriptExecutionContext.GetArgumentUint64( context, 'CoverID' );
		if( tmpID != m_coverID )
		{
			ScriptExecutionContext.SetArgumentUint64( context, 'CoverID', m_coverID );
		}
		tmpID = ScriptExecutionContext.GetArgumentUint64( context, 'DesiredCoverID' );
		if( tmpID != m_coverID )
		{
			ScriptExecutionContext.SetArgumentUint64( context, 'DesiredCoverID', m_coverID );
		}
		m_currentCommand = typedCommand;
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	private export override final function Deactivate( context : ScriptExecutionContext )
	{
		var aiComponent : AIHumanComponent;
		aiComponent = GetPuppet( context ).GetAIControllerComponent();
		if( ( m_currentCommand && aiComponent ) && ShouldInterrupt( context ) )
		{
			if( m_currentCommand.state == AICommandState.Executing )
			{
				aiComponent.StopExecutingCommand( m_currentCommand, true );
			}
		}
		m_currentCommand = NULL;
	}

	public function ShouldInterrupt( context : ScriptExecutionContext ) : Bool
	{
		var rawCommand : IScriptable;
		var takedownCommand : AIFollowerTakedownCommand;
		var stopCover : Bool;
		rawCommand = ScriptExecutionContext.GetArgumentScriptable( context, 'FollowerTakedownCommand' );
		takedownCommand = ( ( AIFollowerTakedownCommand )( rawCommand ) );
		if( takedownCommand && !( takedownCommand.approachBeforeTakedown ) )
		{
			return true;
		}
		stopCover = ScriptExecutionContext.GetArgumentBool( context, 'StopCover' );
		if( stopCover )
		{
			return true;
		}
		return false;
	}

}

enum ECoverSpecialAction
{
	None = 0,
	Left = 1,
	Right = 2,
}

class MoveToCoverCommandDelegate extends ScriptBehaviorDelegate
{
	editable inlined var m_inCommand : AIArgumentMapping;
	var releaseSignalOnCoverEnter : Bool;
	var useSpecialAction : Bool;
	var useHigh : Bool;
	var useLeft : Bool;
	var useRight : Bool;

	public function ResetVariables( context : ScriptExecutionContext ) : Bool
	{
		releaseSignalOnCoverEnter = false;
		useSpecialAction = false;
		useLeft = false;
		useRight = false;
		useHigh = false;
		return true;
	}

	public export function OnActivate( context : ScriptExecutionContext ) : Bool
	{
		var rawCommand : IScriptable;
		var typedCommand : AIMoveToCoverCommand;
		ResetVariables( context );
		if( m_inCommand )
		{
			rawCommand = ScriptExecutionContext.GetScriptableMappingValue( context, m_inCommand );
			typedCommand = ( ( AIMoveToCoverCommand )( rawCommand ) );
		}
		if( !( typedCommand ) )
		{
			return false;
		}
		releaseSignalOnCoverEnter = false;
		if( typedCommand.specialAction != ECoverSpecialAction.None && ScriptedPuppet.IsPlayerCompanion( ScriptExecutionContext.GetOwner( context ) ) )
		{
			useSpecialAction = true;
			if( GetCoverHeight( context ) == gameCoverHeight.High )
			{
				useHigh = true;
			}
			switch( typedCommand.specialAction )
			{
				case ECoverSpecialAction.Left:
					useLeft = true;
				break;
				case ECoverSpecialAction.Right:
					useRight = true;
				break;
				default:
					useSpecialAction = false;
				break;
			}
		}
		return true;
	}

	private function GetCoverHeight( context : ScriptExecutionContext ) : gameCoverHeight
	{
		var coverID : Uint64;
		coverID = ScriptExecutionContext.GetArgumentUint64( context, 'CoverID' );
		return GameInstance.GetCoverManager( ScriptExecutionContext.GetOwner( context ).GetGame() ).GetCoverHeight( coverID );
	}

	public export function GracefulInterruption( context : ScriptExecutionContext ) : Bool
	{
		SendGracefulInterruptionSignal( context );
		return true;
	}

	public export function ResetGracefulInterruption( context : ScriptExecutionContext ) : Bool
	{
		ResetGracefulInterruptionSignal( context );
		return true;
	}

	public export function StopExecutingCommand( context : ScriptExecutionContext ) : Bool
	{
		var rawCommand : IScriptable;
		var typedCommand : AIMoveToCoverCommand;
		var aiComponent : AIHumanComponent;
		var commandState : AICommandState;
		if( !( AIHumanComponent.Get( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), aiComponent ) ) )
		{
			return false;
		}
		rawCommand = ScriptExecutionContext.GetScriptableMappingValue( context, m_inCommand );
		typedCommand = ( ( AIMoveToCoverCommand )( rawCommand ) );
		if( !( typedCommand ) || releaseSignalOnCoverEnter )
		{
			return false;
		}
		commandState = typedCommand.state;
		if( commandState == AICommandState.Executing )
		{
			aiComponent.StopExecutingCommand( typedCommand, true );
		}
		return true;
	}

	public static function SendGracefulInterruptionSignal( context : ScriptExecutionContext )
	{
		var puppet : weak< ScriptedPuppet >;
		puppet = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		if( !( puppet ) )
		{
			return;
		}
		ScriptedPuppet.SendActionSignal( puppet, 'GracefullyInterruptMoveToCover', 1.0 );
	}

	public static function ResetGracefulInterruptionSignal( context : ScriptExecutionContext )
	{
		var puppet : weak< ScriptedPuppet >;
		puppet = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		if( !( puppet ) )
		{
			return;
		}
		ScriptedPuppet.ResetActionSignal( puppet, 'GracefullyInterruptMoveToCover' );
	}

}

