class PerfectDischargePrereqListener extends ScriptStatPoolsListener
{
	protected var m_state : weak< PerfectDischargePrereqState >;

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

	public export override function OnStatPoolValueChanged( oldValue : Float, newValue : Float, percToPoints : Float )
	{
		if( m_state )
		{
			m_state.StatPoolUpdate( oldValue, newValue );
		}
	}

}

class PerfectDischargePrereqState extends StatPoolPrereqState
{
	var m_owner : weak< GameObject >;
	var m_perfectDischargeListener : PerfectDischargePrereqListener;
	var m_wasPerfectlyCharged : Bool;

	public override function StatPoolUpdate( oldValue : Float, newValue : Float )
	{
		var checkPassed : Bool;
		var weaponObject : WeaponObject;
		var perfectDischargeWindowStart : Float;
		var perfectDischargeWindowEnd : Float;
		const var prereq : PerfectDischargePrereq;
		var perfectChargeWindow : Float;
		var player : GameObject;
		var game : GameInstance;
		if( !( m_owner ) )
		{
			return;
		}
		prereq = ( ( PerfectDischargePrereq )( GetPrereq() ) );
		weaponObject = ScriptedPuppet.GetActiveWeapon( m_owner );
		if( !( weaponObject ) )
		{
			return;
		}
		game = weaponObject.GetGame();
		player = ( ( GameObject )( GameInstance.GetPlayerSystem( game ).GetLocalPlayerControlledGameObject() ) );
		perfectChargeWindow = GameInstance.GetStatsSystem( game ).GetStatValue( player.GetEntityID(), gamedataStatType.PerfectChargeWindow );
		perfectDischargeWindowEnd = weaponObject.GetMaxChargeTreshold();
		perfectDischargeWindowStart = ( ( 100.0 - perfectChargeWindow ) * perfectDischargeWindowEnd ) / 100.0;
		if( ( oldValue == 0.0 ) || ( newValue == 0.0 ) )
		{
			m_wasPerfectlyCharged = false;
		}
		checkPassed = ( newValue >= perfectDischargeWindowStart ) && ( newValue < ( perfectDischargeWindowEnd - 1.0 ) );
		checkPassed = prereq.AddTimeWindow( game, player, checkPassed, this );
		OnChanged( checkPassed ^ prereq.m_invert );
	}

	public override function RegisterStatPoolListener( game : GameInstance, statPoolType : gamedataStatPoolType, valueToCheck : Float )
	{
		if( StatsObjectID.IsDefined( m_statsObjID ) )
		{
			m_perfectDischargeListener = new PerfectDischargePrereqListener;
			m_perfectDischargeListener.RegisterState( this );
			GameInstance.GetStatPoolsSystem( game ).RequestRegisteringListener( m_statsObjID, statPoolType, m_perfectDischargeListener );
		}
	}

	public override function UnregisterStatPoolListener( game : GameInstance, statPoolType : gamedataStatPoolType )
	{
		if( m_perfectDischargeListener )
		{
			GameInstance.GetStatPoolsSystem( game ).RequestUnregisteringListener( m_statsObjID, statPoolType, m_perfectDischargeListener );
		}
		m_perfectDischargeListener = NULL;
	}

}

class PerfectDischargePrereq extends StatPoolPrereq
{
	var m_invert : Bool;

	protected export const override function OnRegister( state : PrereqState, game : GameInstance, context : IScriptable ) : Bool
	{
		var weaponObject : WeaponObject;
		var castedState : PerfectDischargePrereqState;
		weaponObject = ScriptedPuppet.GetActiveWeapon( ( ( GameObject )( context ) ) );
		if( !( weaponObject ) )
		{
			return false;
		}
		castedState = ( ( PerfectDischargePrereqState )( state ) );
		castedState.m_owner = ( ( GameObject )( context ) );
		castedState.m_statsObjID = GetStatsObjectID( ( ( GameObject )( context ) ) );
		castedState.RegisterStatPoolListener( game, m_statPoolType, GetValueToCheck( castedState ) );
		castedState.m_wasPerfectlyCharged = false;
		return false;
	}

	protected export override function Initialize( recordID : TweakDBID )
	{
		var record : StatPoolPrereq_Record;
		var objectToCheck : CName;
		record = TweakDBInterface.GetStatPoolPrereqRecord( recordID );
		m_invert = TweakDBInterface.GetBool( recordID + T".invert", false );
		m_statPoolType = gamedataStatPoolType.WeaponCharge;
		record.ValueToCheck( m_valueToCheck );
		m_comparisonType = ( ( EComparisonType )( ( ( Int32 )( EnumValueFromName( 'EComparisonType', record.ComparisonType() ) ) ) ) );
		m_skipOnApply = TweakDBInterface.GetBool( recordID + T".skipOnApply", false );
		m_comparePercentage = TweakDBInterface.GetBool( recordID + T".comparePercentage", true );
		objectToCheck = record.ObjectToCheck();
		if( objectToCheck == 'Weapon' )
		{
			m_objToCheck = ObjectToCheck.Weapon;
		}
		else
		{
			m_objToCheck = ObjectToCheck.Player;
		}
	}

	public const override function IsFulfilled( game : GameInstance, context : IScriptable ) : Bool
	{
		return IsDischargePerfect( game, ScriptedPuppet.GetActiveWeapon( ( ( GameObject )( context ) ) ) );
	}

	protected export const override function OnApplied( state : PrereqState, game : GameInstance, context : IScriptable )
	{
		var result : Bool;
		var castedState : PerfectDischargePrereqState;
		if( m_skipOnApply )
		{
			return;
		}
		castedState = ( ( PerfectDischargePrereqState )( state ) );
		if( GameInstance.GetStatPoolsSystem( game ).IsStatPoolAdded( castedState.m_statsObjID, gamedataStatPoolType.WeaponCharge ) )
		{
			result = IsDischargePerfect( game, ScriptedPuppet.GetActiveWeapon( ( ( GameObject )( context ) ) ), castedState );
			castedState.OnChanged( result );
		}
	}

	protected const function IsDischargePerfect( game : GameInstance, weaponObject : WeaponObject, optional state : PerfectDischargePrereqState ) : Bool
	{
		var perfectDischargeWindowStart : Float;
		var perfectDischargeWindowEnd : Float;
		var statPoolSystem : StatPoolsSystem;
		var chargeVal : Float;
		var perfectChargeWindow : Float;
		var isDischargePerfect : Bool;
		var player : GameObject;
		statPoolSystem = GameInstance.GetStatPoolsSystem( game );
		if( !( weaponObject ) )
		{
			return false;
		}
		player = ( ( GameObject )( GameInstance.GetPlayerSystem( game ).GetLocalPlayerControlledGameObject() ) );
		perfectChargeWindow = GameInstance.GetStatsSystem( weaponObject.GetGame() ).GetStatValue( player.GetEntityID(), gamedataStatType.PerfectChargeWindow );
		chargeVal = statPoolSystem.GetStatPoolValue( weaponObject.GetEntityID(), gamedataStatPoolType.WeaponCharge, false );
		perfectDischargeWindowEnd = weaponObject.GetMaxChargeTreshold();
		perfectDischargeWindowStart = ( ( 100.0 - perfectChargeWindow ) * perfectDischargeWindowEnd ) / 100.0;
		isDischargePerfect = ( chargeVal >= perfectDischargeWindowStart ) && ( chargeVal < ( perfectDischargeWindowEnd - 1.0 ) );
		isDischargePerfect = AddTimeWindow( game, player, isDischargePerfect, state );
		return isDischargePerfect ^ m_invert;
	}

	public const function AddTimeWindow( game : GameInstance, player : GameObject, isDischargePerfect : Bool, state : PerfectDischargePrereqState ) : Bool
	{
		var statsSystem : StatsSystem;
		var canControlFullyChargedWeapon : Bool;
		statsSystem = GameInstance.GetStatsSystem( game );
		canControlFullyChargedWeapon = statsSystem.GetStatBoolValue( player.GetEntityID(), gamedataStatType.CanControlFullyChargedWeapon );
		if( !( state ) || !( canControlFullyChargedWeapon ) )
		{
			return isDischargePerfect;
		}
		if( isDischargePerfect && !( state.m_wasPerfectlyCharged ) )
		{
			state.m_wasPerfectlyCharged = true;
		}
		return state.m_wasPerfectlyCharged;
	}

}

