class StatPrereqListener extends ScriptStatsListener
{
	protected var m_state : weak< StatPrereqState >;

	public export override function OnStatChanged( ownerID : StatsObjectID, statType : gamedataStatType, diff : Float, total : Float )
	{
		m_state.StatUpdate( diff, total );
	}

	public function RegisterState( state : PrereqState )
	{
		m_state = ( ( StatPrereqState )( state ) );
	}

}

class StatPrereqState extends PrereqState
{
	var m_listener : StatPrereqListener;
	var m_modifiersValueToCheck : Float;

	public virtual function StatUpdate( diff : Float, total : Float )
	{
		var checkPassed : Bool;
		const var prereq : StatPrereq;
		prereq = ( ( StatPrereq )( GetPrereq() ) );
		if( prereq.m_statModifiersUsed )
		{
			checkPassed = ProcessCompare( prereq.m_comparisonType, total, m_modifiersValueToCheck );
		}
		else
		{
			checkPassed = ProcessCompare( prereq.m_comparisonType, total, prereq.m_valueToCheck );
		}
		OnChanged( checkPassed );
		if( prereq.m_notifyOnAnyChange )
		{
			OnChangedRepeated( prereq.m_notifyOnlyOnStateFulfilled );
		}
	}

	public function UpdateModifiersValueToCheck( value : Float )
	{
		m_modifiersValueToCheck = value;
	}

}

class StatPrereq extends IScriptablePrereq
{
	var m_notifyOnAnyChange : Bool;
	var m_notifyOnlyOnStateFulfilled : Bool;
	editable var m_statType : gamedataStatType;
	editable var m_valueToCheck : Float;
	editable var m_comparisonType : EComparisonType;
	var m_statModifiersUsed : Bool;
	private var m_statPrereqRecordID : TweakDBID;
	var m_objToCheck : CName;

	protected export const override function OnRegister( state : PrereqState, game : GameInstance, context : IScriptable ) : Bool
	{
		var object : GameObject;
		var castedState : StatPrereqState;
		object = GetObjectToCheck( context, game );
		castedState = ( ( StatPrereqState )( state ) );
		castedState.m_listener = new StatPrereqListener;
		castedState.m_listener.RegisterState( castedState );
		castedState.m_listener.SetStatType( m_statType );
		GameInstance.GetStatsSystem( game ).RegisterListener( object.GetEntityID(), castedState.m_listener );
		return false;
	}

	protected export const override function OnUnregister( state : PrereqState, game : GameInstance, context : IScriptable )
	{
		var object : GameObject;
		var castedState : StatPrereqState;
		object = GetObjectToCheck( context, game );
		castedState = ( ( StatPrereqState )( state ) );
		GameInstance.GetStatsSystem( game ).UnregisterListener( object.GetEntityID(), castedState.m_listener );
		castedState.m_listener = NULL;
	}

	protected export override function Initialize( recordID : TweakDBID )
	{
		var record : StatPrereq_Record;
		record = TweakDBInterface.GetStatPrereqRecord( recordID );
		m_statType = ( ( gamedataStatType )( ( ( Int32 )( EnumValueFromName( 'gamedataStatType', record.StatType() ) ) ) ) );
		m_valueToCheck = record.ValueToCheck();
		m_comparisonType = ( ( EComparisonType )( ( ( Int32 )( EnumValueFromName( 'EComparisonType', record.ComparisonType() ) ) ) ) );
		m_notifyOnAnyChange = TDB.GetBool( recordID + T".notifyOnAnyChange", false );
		m_notifyOnlyOnStateFulfilled = TDB.GetBool( recordID + T".notifyOnlyOnStateFulfilled", false );
		m_statPrereqRecordID = recordID;
		m_statModifiersUsed = record.GetStatModifiersCount() > 0;
		m_objToCheck = TDB.GetCName( recordID + T".objectToCheck" );
	}

	public export const override function IsFulfilled( game : GameInstance, context : IScriptable ) : Bool
	{
		var object : GameObject;
		var currentValue : Float;
		var modifiersValueToCheck : Float;
		object = GetObjectToCheck( context, game );
		currentValue = GameInstance.GetStatsSystem( game ).GetStatValue( object.GetEntityID(), m_statType );
		if( m_statModifiersUsed )
		{
			modifiersValueToCheck = StatsSystemHelper.GetStatPrereqModifiersValue( game, object.GetEntityID(), m_statPrereqRecordID );
			return ProcessCompare( m_comparisonType, currentValue, modifiersValueToCheck );
		}
		else
		{
			return ProcessCompare( m_comparisonType, currentValue, m_valueToCheck );
		}
	}

	public const function IsFulfilled( game : GameInstance, context : IScriptable, itemStatsID : StatsObjectID ) : Bool
	{
		var object : GameObject;
		var currentValue : Float;
		var modifiersValueToCheck : Float;
		object = GetObjectToCheck( context, game );
		currentValue = GameInstance.GetStatsSystem( game ).GetStatValue( object.GetEntityID(), m_statType );
		if( m_statModifiersUsed )
		{
			modifiersValueToCheck = StatsSystemHelper.GetStatPrereqModifiersValue( game, itemStatsID, m_statPrereqRecordID );
			return ProcessCompare( m_comparisonType, currentValue, modifiersValueToCheck );
		}
		else
		{
			return ProcessCompare( m_comparisonType, currentValue, m_valueToCheck );
		}
	}

	protected export const override function OnApplied( state : PrereqState, game : GameInstance, context : IScriptable )
	{
		var object : weak< GameObject >;
		var castedState : StatPrereqState;
		var statValue : Float;
		var modifiersValueToCheck : Float;
		object = GetObjectToCheck( context, game );
		castedState = ( ( StatPrereqState )( state ) );
		if( m_statModifiersUsed )
		{
			modifiersValueToCheck = StatsSystemHelper.GetStatPrereqModifiersValue( game, object.GetEntityID(), m_statPrereqRecordID );
			castedState.UpdateModifiersValueToCheck( modifiersValueToCheck );
		}
		statValue = GameInstance.GetStatsSystem( object.GetGame() ).GetStatValue( object.GetEntityID(), m_statType );
		castedState.StatUpdate( 0.0, statValue );
	}

	private const function GetObjectToCheck( context : IScriptable, game : GameInstance ) : GameObject
	{
		return ( ( m_objToCheck == 'Player' ) ? ( GetPlayer( game ) ) : ( ( ( GameObject )( context ) ) ) );
	}

}

