class KiroshiHighlightEffectorCallback extends AttachmentSlotsScriptCallback
{
	var m_effector : KiroshiHighlightEffector;

	public override function OnItemEquipped( slot : TweakDBID, item : ItemID )
	{
		var weaponRecord : WeaponItem_Record;
		var weaponEvolution : gamedataWeaponEvolution;
		var isMeleeWeapon : Bool;
		weaponRecord = TDB.GetWeaponItemRecord( ItemID.GetTDBID( item ) );
		weaponEvolution = RPGManager.GetWeaponEvolution( item );
		isMeleeWeapon = weaponRecord.TagsContains( WeaponObject.GetMeleeWeaponTag() );
		m_effector.m_isTechWeaponEquipped = weaponEvolution == gamedataWeaponEvolution.Tech;
		m_effector.m_isMeleeWeaponEquipped = isMeleeWeapon;
	}

	public override function OnItemUnequipped( slot : TweakDBID, item : ItemID )
	{
		m_effector.m_isMeleeWeaponEquipped = false;
		m_effector.m_isTechWeaponEquipped = false;
	}

}

class KiroshiEffectorIsAimingStatListener extends ScriptStatsListener
{
	var m_effector : weak< KiroshiHighlightEffector >;

	public override function OnStatChanged( ownerID : StatsObjectID, statType : gamedataStatType, diff : Float, total : Float )
	{
		m_effector.m_IsAiming = total == 1.0;
	}

}

class KiroshiEffectorTechPreviewStatListener extends ScriptStatsListener
{
	var m_effector : weak< KiroshiHighlightEffector >;

	public override function OnStatChanged( ownerID : StatsObjectID, statType : gamedataStatType, diff : Float, total : Float )
	{
		m_effector.m_isTechPreviewEnabled = total == 1.0;
	}

}

class KiroshiHighlightEffector extends HighlightEffector
{
	private var m_onlyWhileAiming : Bool;
	private var m_onlyClosestToCrosshair : Bool;
	private var m_onlyClosestByDistance : Bool;
	private var m_aimingStatListener : KiroshiEffectorIsAimingStatListener;
	private var m_techPreviewStatListener : KiroshiEffectorTechPreviewStatListener;
	private var m_slotCallback : KiroshiHighlightEffectorCallback;
	private var m_slotListener : AttachmentSlotsScriptListener;
	var m_IsAiming : Bool;
	var m_isTechWeaponEquipped : Bool;
	var m_isMeleeWeaponEquipped : Bool;
	var m_isTechPreviewEnabled : Bool;

	protected export override function Initialize( record : TweakDBID, game : GameInstance, parentRecord : TweakDBID )
	{
		super.Initialize( record, game, parentRecord );
		m_onlyWhileAiming = TDB.GetBool( record + T".onlyWhileAiming" );
		m_onlyClosestToCrosshair = TDB.GetBool( record + T".onlyClosestToCrosshair" );
		m_onlyClosestByDistance = TDB.GetBool( record + T".onlyClosestByDistance" );
	}

	protected export override function Uninitialize( game : GameInstance )
	{
		if( m_slotListener )
		{
			GameInstance.GetTransactionSystem( game ).UnregisterAttachmentSlotListener( m_owner, m_slotListener );
			m_slotListener = NULL;
			m_slotCallback = NULL;
		}
		if( m_aimingStatListener )
		{
			GameInstance.GetStatsSystem( game ).UnregisterListener( m_owner.GetEntityID(), m_aimingStatListener );
			m_aimingStatListener = NULL;
		}
		if( m_techPreviewStatListener )
		{
			GameInstance.GetStatsSystem( game ).UnregisterListener( m_owner.GetEntityID(), m_techPreviewStatListener );
			m_techPreviewStatListener = NULL;
		}
	}

	private function InitializeListeners()
	{
		var statsSystem : StatsSystem;
		statsSystem = GameInstance.GetStatsSystem( m_owner.GetGame() );
		if( !( m_aimingStatListener ) )
		{
			m_aimingStatListener = new KiroshiEffectorIsAimingStatListener;
			m_aimingStatListener.m_effector = this;
			m_aimingStatListener.SetStatType( gamedataStatType.IsAimingWithWeapon );
			statsSystem.RegisterListener( m_owner.GetEntityID(), m_aimingStatListener );
			m_IsAiming = statsSystem.GetStatValue( m_owner.GetEntityID(), gamedataStatType.IsAimingWithWeapon ) == 1.0;
		}
		if( !( m_techPreviewStatListener ) )
		{
			m_techPreviewStatListener = new KiroshiEffectorTechPreviewStatListener;
			m_techPreviewStatListener.m_effector = this;
			m_techPreviewStatListener.SetStatType( gamedataStatType.TechPierceHighlightsEnabled );
			statsSystem.RegisterListener( m_owner.GetEntityID(), m_techPreviewStatListener );
			m_isTechPreviewEnabled = statsSystem.GetStatValue( m_owner.GetEntityID(), gamedataStatType.TechPierceHighlightsEnabled ) == 1.0;
		}
		if( !( m_slotListener ) )
		{
			m_slotCallback = new KiroshiHighlightEffectorCallback;
			m_slotCallback.slotID = T"AttachmentSlots.WeaponRight";
			m_slotCallback.m_effector = this;
			m_slotListener = GameInstance.GetTransactionSystem( m_owner.GetGame() ).RegisterAttachmentSlotListener( m_owner, m_slotCallback );
		}
	}

	protected override function ContinuousAction( owner : GameObject, instigator : GameObject )
	{
		m_owner = owner;
		InitializeListeners();
		if( ( m_isTechWeaponEquipped && m_IsAiming ) && m_isTechPreviewEnabled )
		{
			return;
		}
		if( m_onlyWhileAiming && ( !( m_IsAiming ) || m_isMeleeWeaponEquipped ) )
		{
			return;
		}
		ProcessEffector();
	}

	private override function ProcessHighlight( searchQuery : TargetSearchQuery )
	{
		if( m_onlyClosestToCrosshair )
		{
			RevealClosestToCrosshair( m_owner, searchQuery );
			return;
		}
		if( m_onlyClosestByDistance )
		{
			RevealClosestByDistance( m_owner, searchQuery );
			return;
		}
		RevealAllObjects( m_owner, searchQuery );
	}

	private function RevealClosestToCrosshair( owner : GameObject, query : TargetSearchQuery )
	{
		var angleDistance : EulerAngles;
		var closestTarget : GameObject;
		closestTarget = GameInstance.GetTargetingSystem( owner.GetGame() ).GetObjectClosestToCrosshair( owner, angleDistance, query );
		if( !( closestTarget ) )
		{
			return;
		}
		if( m_highlightVisible || !( GameInstance.GetTargetingSystem( owner.GetGame() ).IsVisibleTarget( owner, closestTarget ) ) )
		{
			RevealObject( owner, closestTarget, true, m_effectDuraton );
		}
	}

	private function RevealClosestByDistance( owner : GameObject, query : TargetSearchQuery )
	{
		var closestTarget : TS_TargetPartInfo;
		var targetObject : GameObject;
		GameInstance.GetTargetingSystem( owner.GetGame() ).GetTargetClosestByDistance( owner, query, owner.GetWorldPosition(), closestTarget );
		targetObject = ( ( GameObject )( TS_TargetPartInfo.GetComponent( closestTarget ).GetEntity() ) );
		if( targetObject && ( m_highlightVisible || !( GameInstance.GetTargetingSystem( owner.GetGame() ).IsVisibleTarget( owner, targetObject ) ) ) )
		{
			RevealObject( owner, targetObject, true, m_effectDuraton );
		}
	}

}

