class SecurityGateForceUnlock extends Event
{
	var entranceAllowedFor : EntityID;
	var shouldUnlock : Bool;
}

class UpdateGatePosition extends Event
{
}

class SecurityGateLockController extends ScriptableDeviceComponent
{

	public const override function GetPS() : SecurityGateLockControllerPS
	{
		return ( ( SecurityGateLockControllerPS )( GetBasePS() ) );
	}

}

class SecurityGateLockControllerPS extends ScriptableDeviceComponentPS
{
	var m_tresspasserList : array< TrespasserEntry >;
	var m_entranceToken : EntityID;
	var m_isLeaving : Bool;
	var m_isLocked : Bool;
	default m_isLocked = true;

	public const function IsLocked() : Bool
	{
		return m_isLocked;
	}

	public function UpdateTrespassersList( evt : TriggerEvent, isEntering : Bool )
	{
		var index : Int32;
		var trespasser : ScriptedPuppet;
		if( ( evt.componentName != 'enteringArea' && evt.componentName != 'centeredArea' ) && evt.componentName != 'leavingArea' )
		{
			return;
		}
		trespasser = ( ( ScriptedPuppet )( EntityGameInterface.GetEntity( evt.activator ) ) );
		if( !( trespasser ) )
		{
			return;
		}
		if( !( ( ( PlayerPuppet )( trespasser ) ) ) )
		{
			return;
		}
		if( IsTrespasserOnTheList( trespasser, index ) )
		{
			UpdateTrespasserEntry( index, isEntering, evt.componentName );
		}
		else
		{
			AddTrespasserEntry( trespasser, evt.componentName );
		}
	}

	private function IsTrespasserOnTheList( trespasser : ScriptedPuppet, out index : Int32 ) : Bool
	{
		var i : Int32;
		for( i = 0; i < m_tresspasserList.Size(); i += 1 )
		{
			if( m_tresspasserList[ i ].trespasser == trespasser )
			{
				index = i;
				return true;
			}
		}
		index = -1;
		return false;
	}

	private function UpdateTrespasserEntry( index : Int32, isEntering : Bool, areaName : CName )
	{
		var t : TrespasserEntry;
		t = m_tresspasserList[ index ];
		switch( areaName )
		{
			case 'enteringArea':
				m_tresspasserList[ index ].isInsideA = isEntering;
			break;
			case 'leavingArea':
				m_tresspasserList[ index ].isInsideB = isEntering;
			break;
			case 'centeredArea':
				m_tresspasserList[ index ].isInsideScanner = isEntering;
			break;
			default:
				if( !( IsFinal() ) )
				{
				}
			return;
		}
		if( IsTrespasserOutside( index ) )
		{
			if( ( t.trespasser.GetEntityID() == m_entranceToken ) && IsLegallyLeaving( t ) )
			{
				LockGate( true );
			}
			RemoveTrespasserEntry( index );
		}
		if( isEntering )
		{
			m_tresspasserList[ index ].areaStack.PushBack( areaName );
		}
	}

	private const function IsLegallyLeaving( const t : ref< TrespasserEntry > ) : Bool
	{
		var entrance : CName;
		var center : CName;
		var leaving : CName;
		var stackSize : Int32;
		entrance = 'enteringArea';
		center = 'centeredArea';
		leaving = 'leavingArea';
		if( t.areaStack.Size() < 3 )
		{
			return false;
		}
		if( t.areaStack[ 0 ] != entrance )
		{
			return false;
		}
		if( t.areaStack.Last() == leaving )
		{
			stackSize = t.areaStack.Size();
			if( t.areaStack[ stackSize - 2 ] == center )
			{
				return true;
			}
			return false;
		}
		return false;
	}

	private function AddTrespasserEntry( trespasser : ScriptedPuppet, areaName : CName )
	{
		var newEntry : TrespasserEntry;
		newEntry.trespasser = trespasser;
		m_tresspasserList.PushBack( newEntry );
		UpdateTrespasserEntry( m_tresspasserList.Size() - 1, true, areaName );
	}

	private function RemoveTrespasserEntry( index : Int32 )
	{
		m_tresspasserList.Erase( index );
	}

	private function IsTrespasserOutside( index : Int32 ) : Bool
	{
		if( ( m_tresspasserList[ index ].isInsideA || m_tresspasserList[ index ].isInsideB ) || m_tresspasserList[ index ].isInsideScanner )
		{
			return false;
		}
		return true;
	}

	private function OnForceUnlock( evt : SecurityGateForceUnlock ) : EntityNotificationType
	{
		if( !( IsPowered() ) )
		{
			return EntityNotificationType.DoNotNotifyEntity;
		}
		if( evt.shouldUnlock )
		{
			m_entranceToken = evt.entranceAllowedFor;
			UnlockGate();
		}
		else
		{
			LockGate( false );
		}
		return EntityNotificationType.SendThisEventToEntity;
	}

	private function UnlockGate()
	{
		if( !( m_isLocked ) )
		{
			return;
		}
		m_isLocked = false;
		UpdateGatePosition();
	}

	private function LockGate( expireToken : Bool )
	{
		var emptyID : EntityID;
		if( expireToken )
		{
			m_entranceToken = emptyID;
		}
		if( m_isLocked )
		{
			return;
		}
		m_isLocked = true;
		UpdateGatePosition();
	}

	private function UpdateGatePosition()
	{
		var updateGatePosition : UpdateGatePosition;
		updateGatePosition = new UpdateGatePosition;
		QueueEntityEvent( PersistentID.ExtractEntityID( GetID() ), updateGatePosition );
	}

	protected override function GetDeviceIconTweakDBID() : TweakDBID
	{
		return T"DeviceIcons.SecuritySystemDeviceIcon";
	}

	protected override function GetBackgroundTextureTweakDBID() : TweakDBID
	{
		return T"DeviceIcons.SecuritySystemDeviceBackground";
	}

}

