importonly abstract class AIBaseMountCommand extends AICommand
{
	import var mountData : MountEventData;
}

import class AIMountCommand extends AIBaseMountCommand
{
}

import class AIUnmountCommand extends AIBaseMountCommand
{
}

class MountCommandHandlerTask extends AIbehaviortaskScript
{
	editable inlined var m_command : AIArgumentMapping;
	editable inlined var m_mountEventData : AIArgumentMapping;
	editable var m_callbackName : CName;

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

	protected export override function Update( context : ScriptExecutionContext ) : AIbehaviorUpdateOutcome
	{
		var command : AIBaseMountCommand;
		command = ( ( AIBaseMountCommand )( ScriptExecutionContext.GetScriptableMappingValue( context, m_command ) ) );
		ScriptExecutionContext.SetMappingValue( context, m_mountEventData, command.mountData );
		ScriptExecutionContext.InvokeBehaviorCallback( context, m_callbackName );
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

}

class MountRequestCondition extends AIbehaviorconditionScript
{
	editable inlined var m_testMountRequest : Bool;
	default m_testMountRequest = true;
	editable inlined var m_testUnmountRequest : Bool;
	default m_testUnmountRequest = false;
	editable inlined var m_acceptInstant : Bool;
	default m_acceptInstant = true;
	editable inlined var m_acceptNotInstant : Bool;
	default m_acceptNotInstant = true;

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

	protected function TestRequest( context : ref< ScriptExecutionContext >, argumentName : CName ) : AIbehaviorConditionOutcomes
	{
		var request : MountEventData;
		var hls : gamedataNPCHighLevelState;
		request = ( ( MountEventData )( ScriptExecutionContext.GetArgumentScriptable( context, argumentName ) ) );
		if( !( request ) )
		{
			return AIbehaviorConditionOutcomes.False;
		}
		if( request.isInstant )
		{
			return m_acceptInstant;
		}
		if( !( request.ignoreHLS ) )
		{
			hls = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetHighLevelStateFromBlackboard();
			if( hls == gamedataNPCHighLevelState.Alerted || hls == gamedataNPCHighLevelState.Combat )
			{
				return false;
			}
		}
		return m_acceptNotInstant;
	}

	protected override function Check( context : ScriptExecutionContext ) : AIbehaviorConditionOutcomes
	{
		var outcome : AIbehaviorConditionOutcomes;
		if( m_testMountRequest )
		{
			outcome = TestRequest( context, 'MountRequest' );
			if( outcome != AIbehaviorConditionOutcomes.False )
			{
				return outcome;
			}
		}
		if( m_testUnmountRequest )
		{
			return TestRequest( context, 'UnmountRequest' );
		}
		return AIbehaviorConditionOutcomes.Failure;
	}

}

class MountRequestPassiveCondition extends AIbehaviorexpressionScript
{
	private editable var m_unmountRequest : Bool;
	default m_unmountRequest = false;
	hint m_unmountRequest = "If 'false' (default), condition checks for 'Mount' event. If 'true', condition checks for 'Unmount' event.";
	private editable var m_acceptInstant : Bool;
	default m_acceptInstant = true;
	hint m_acceptInstant = "If 'true', condition accepts instant mount/unmount requests.";
	private editable var m_acceptNotInstant : Bool;
	default m_acceptNotInstant = true;
	hint m_acceptNotInstant = "If 'true', condition accepts mount/unmount requests that are not instant.";
	private editable var m_acceptForcedTransition : Bool;
	default m_acceptForcedTransition = false;
	hint m_acceptForcedTransition = "If 'true' transition is allowed only if conditions in 'request.IsTransitionForced()' are met";
	private editable var m_succeedOnMissingMountedEntity : Bool;
	default m_succeedOnMissingMountedEntity = false;
	hint m_succeedOnMissingMountedEntity = "If 'true', the condition will succeed if parent entity is detached";
	private var m_callbackId : Uint32;
	private var m_highLevelStateCallbackId : Uint32;

	private function GetCallbackName() : CName
	{
		return ( ( m_unmountRequest ) ? ( 'OnUnmountRequest' ) : ( 'OnMountRequest' ) );
	}

	private function GetRequestArgumentName() : CName
	{
		return ( ( m_unmountRequest ) ? ( 'UnmountRequest' ) : ( 'MountRequest' ) );
	}

	public export function Activate( ctx : ScriptExecutionContext )
	{
		m_callbackId = ScriptExecutionContext.AddBehaviorCallback( ctx, GetCallbackName(), this );
		if( m_acceptNotInstant )
		{
			m_highLevelStateCallbackId = ScriptExecutionContext.AddBehaviorCallback( ctx, 'OnHighLevelChanged', this );
		}
	}

	public export function Deactivate( ctx : ScriptExecutionContext )
	{
		ScriptExecutionContext.RemoveBehaviorCallback( ctx, m_callbackId );
		if( m_acceptNotInstant )
		{
			ScriptExecutionContext.RemoveBehaviorCallback( ctx, m_highLevelStateCallbackId );
		}
	}

	public export function CalculateValue( ctx : ScriptExecutionContext ) : Variant
	{
		var request : MountEventData;
		var hls : gamedataNPCHighLevelState;
		var ss : gamedataNPCStanceState;
		var mountInfo : MountingInfo;
		var vehicle : weak< VehicleObject >;
		request = ( ( MountEventData )( ScriptExecutionContext.GetArgumentScriptable( ctx, GetRequestArgumentName() ) ) );
		if( !( request ) )
		{
			return false;
		}
		if( !( m_unmountRequest ) )
		{
			if( !( request.isInstant ) && !( request.ignoreHLS ) )
			{
				hls = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( ctx ) ) ).GetHighLevelStateFromBlackboard();
				if( hls == gamedataNPCHighLevelState.Alerted || hls == gamedataNPCHighLevelState.Combat )
				{
					return false;
				}
			}
			ss = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( ctx ) ) ).GetStanceStateFromBlackboard();
			if( ss == gamedataNPCStanceState.Vehicle || ss == gamedataNPCStanceState.VehicleWindow )
			{
				mountInfo = GameInstance.GetMountingFacility( ScriptExecutionContext.GetOwner( ctx ).GetGame() ).GetMountingInfoSingleWithObjects( ScriptExecutionContext.GetOwner( ctx ) );
				if( ( mountInfo.parentId == request.mountParentEntityId ) && VehicleComponent.IsSameSlot( mountInfo.slotId.id, request.slotName ) )
				{
					return false;
				}
			}
		}
		else if( !( request.isInstant ) && !( request.ignoreHLS ) )
		{
			hls = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( ctx ) ) ).GetHighLevelStateFromBlackboard();
			if( ( hls == gamedataNPCHighLevelState.Alerted && GetPuppet( ctx ).IsAggressive() ) && !( ScriptedPuppet.IsPlayerCompanion( GetPuppet( ctx ) ) ) )
			{
				return false;
			}
		}
		if( request.isInstant && m_acceptInstant )
		{
			return true;
		}
		if( !( request.isInstant ) && m_acceptNotInstant )
		{
			return true;
		}
		if( request.IsTransitionForced() && m_acceptForcedTransition )
		{
			return true;
		}
		if( m_succeedOnMissingMountedEntity && EntityID.IsDefined( request.mountParentEntityId ) )
		{
			if( !( VehicleComponent.GetVehicleFromID( ScriptExecutionContext.GetOwner( ctx ).GetGame(), request.mountParentEntityId, vehicle ) ) )
			{
				return true;
			}
		}
		return false;
	}

}

