class BaseChunkGameController extends inkGameController
{
	protected var m_chunkBlackboard : weak< IBlackboard >;
	protected var m_chunkBlackboardDef : UI_ScannerModulesDef;
	protected var m_questClueBlackboardDef : UI_ScannerDef;

	protected event OnInitialize()
	{
		m_chunkBlackboardDef = GetAllBlackboardDefs().UI_ScannerModules;
		m_chunkBlackboard = GetBlackboardSystem().Get( m_chunkBlackboardDef );
	}

}

class ScannerNPCHeaderGameController extends BaseChunkGameController
{
	private editable var m_nameText : inkTextRef;
	private editable var skullIndicator : inkWidgetRef;
	private editable var m_archetypeIcon : inkImageRef;
	private var m_levelCallbackID : CallbackHandle;
	private var m_nameCallbackID : CallbackHandle;
	private var m_attitudeCallbackID : CallbackHandle;
	private var m_archtypeCallbackID : CallbackHandle;
	private var m_isValidName : Bool;
	private var m_isValidRarity : Bool;
	private var m_isValidArchetype : Bool;

	protected event OnInitialize()
	{
		super.OnInitialize();
		m_nameCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerName, this, 'OnNameChanged' );
		m_attitudeCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerAttitude, this, 'OnAttitudeChange' );
		m_archtypeCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerArchetype, this, 'OnArchetypeChanged' );
		m_levelCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerLevel, this, 'OnLevelChanged' );
		OnNameChanged( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerName ) );
		OnAttitudeChange( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerAttitude ) );
		OnArchetypeChanged( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerArchetype ) );
		OnLevelChanged( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerLevel ) );
	}

	protected event OnUninitialize()
	{
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerName, m_nameCallbackID );
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerAttitude, m_attitudeCallbackID );
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerLevel, m_levelCallbackID );
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerArchetype, m_archtypeCallbackID );
	}

	protected event OnNameChanged( value : Variant )
	{
		var nameData : ScannerName;
		var displayNmae : String;
		nameData = ( ( ScannerName )value );
		if( nameData )
		{
			displayNmae = nameData.GetDisplayName();
			if( IsStringValid( displayNmae ) )
			{
				if( nameData.GetTextParams() )
				{
					inkTextRef.SetLocalizedTextScript( m_nameText, displayNmae, nameData.GetTextParams() );
				}
				else
				{
					inkTextRef.SetText( m_nameText, displayNmae );
				}
				m_isValidName = true;
			}
			else
			{
				inkTextRef.SetText( m_nameText, "" );
				m_isValidName = false;
			}
		}
		else
		{
			m_isValidName = false;
		}
		UpdateGlobalVisibility();
	}

	protected event OnLevelChanged( value : Variant )
	{
		var levelData : ScannerLevel;
		levelData = ( ( ScannerLevel )value );
		inkWidgetRef.SetVisible( skullIndicator, levelData.GetIndicator() );
	}

	protected event OnAttitudeChange( value : Variant )
	{
		var attitudeData : ScannerAttitude;
		var attitude : EAIAttitude;
		attitudeData = ( ( ScannerAttitude )value );
		attitude = attitudeData.GetAttitude();
		switch( attitude )
		{
			case EAIAttitude.AIA_Friendly:
				inkTextRef.SetState( m_nameText, 'Friendly' );
			break;
			case EAIAttitude.AIA_Neutral:
				inkTextRef.SetState( m_nameText, 'Neutral' );
			break;
			case EAIAttitude.AIA_Hostile:
				inkTextRef.SetState( m_nameText, 'Hostile' );
			break;
		}
	}

	protected event OnArchetypeChanged( value : Variant )
	{
		var archetypeData : ScannerArchetype;
		var archetype : gamedataArchetypeType;
		var iconRecord : UIIcon_Record;
		archetypeData = ( ( ScannerArchetype )value );
		if( archetypeData )
		{
			m_isValidArchetype = true;
			archetype = archetypeData.GetArchtype();
			iconRecord = TweakDBInterface.GetUIIconRecord( TDBID.Create( "UIIcon." + ( ( String )( archetype ) ) ) );
			inkImageRef.SetTexturePart( m_archetypeIcon, iconRecord.AtlasPartName() );
		}
		else
		{
			m_isValidArchetype = false;
		}
		UpdateGlobalVisibility();
	}

	private function UpdateGlobalVisibility()
	{
		GetRootWidget().SetVisible( m_isValidName );
		inkImageRef.SetVisible( m_archetypeIcon, m_isValidArchetype );
	}

}

class ScannerDeviceHeaderGameController extends BaseChunkGameController
{
	private editable var m_nameText : inkTextRef;
	private editable var m_fluffText : inkTextRef;
	private editable var m_separator1 : inkRectangleRef;
	private editable var m_separator2 : inkRectangleRef;
	private editable var m_levelText : inkTextRef;
	private editable var m_status : inkTextRef;
	private editable var m_statusIcon : inkImageRef;
	private editable var m_levelWrapper : inkWidgetRef;
	private var m_nameCallbackID : CallbackHandle;
	private var m_networkLevelCallbackID : CallbackHandle;
	private var m_networkStatusCallbackID : CallbackHandle;
	private var m_deviceStatusCallbackID : CallbackHandle;
	private var m_attitudeCallbackID : CallbackHandle;
	private var m_isValidName : Bool;
	private var m_isValidNetworkLevel : Bool;
	private var m_isValidnetworkStatus : Bool;
	private var m_isValidDeviceStatus : Bool;

	protected event OnInitialize()
	{
		super.OnInitialize();
		m_nameCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerName, this, 'OnNameChanged' );
		m_networkLevelCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerNetworkLevel, this, 'OnNetworkLevelChanged' );
		m_networkStatusCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerNetworkStatus, this, 'OnNetworkStatusChanged' );
		m_attitudeCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerAttitude, this, 'OnAttitudeChange' );
		m_deviceStatusCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerDeviceStatus, this, 'OnDeviceStatusChange' );
		OnNameChanged( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerName ) );
		OnNetworkLevelChanged( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerNetworkLevel ) );
		OnAttitudeChange( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerAttitude ) );
		OnDeviceStatusChange( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerDeviceStatus ) );
	}

	protected event OnUninitialize()
	{
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerName, m_nameCallbackID );
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerNetworkLevel, m_networkLevelCallbackID );
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerNetworkStatus, m_nameCallbackID );
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerAttitude, m_attitudeCallbackID );
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerDeviceStatus, m_attitudeCallbackID );
	}

	protected event OnDeviceStatusChange( value : Variant )
	{
		var deviceStatusData : ScannerDeviceStatus;
		deviceStatusData = ( ( ScannerDeviceStatus )value );
		if( deviceStatusData )
		{
			inkTextRef.SetText( m_status, deviceStatusData.GetDeviceStatus() );
			switch( deviceStatusData.GetDeviceStatusFriendlyName() )
			{
				case "disabled":
					inkImageRef.SetTexturePart( m_statusIcon, 'ico_device_disabled' );
				break;
				case "unpowered":
					inkImageRef.SetTexturePart( m_statusIcon, 'ico_device_unpowered' );
				break;
				case "off":
					inkImageRef.SetTexturePart( m_statusIcon, 'ico_device_off' );
				break;
				case "on":
					inkImageRef.SetTexturePart( m_statusIcon, 'ico_device_on' );
				break;
				default:
				;
			}
			m_isValidDeviceStatus = true;
		}
		else
		{
			m_isValidDeviceStatus = false;
		}
		UpdateGlobalVisibility();
	}

	protected event OnNameChanged( value : Variant )
	{
		var nameData : ScannerName;
		nameData = ( ( ScannerName )value );
		if( nameData )
		{
			inkTextRef.SetLocalizedTextScript( m_nameText, nameData.GetDisplayName() );
			m_isValidName = true;
		}
		else
		{
			m_isValidName = false;
		}
		UpdateGlobalVisibility();
	}

	protected event OnNetworkStatusChanged( value : Variant )
	{
		var networkStatusData : ScannerNetworkStatus;
		networkStatusData = ( ( ScannerNetworkStatus )value );
		if( networkStatusData )
		{
			inkTextRef.SetText( m_levelText, ( ( String )( networkStatusData.GetNetworkStatus() ) ) );
			m_isValidnetworkStatus = true;
		}
		else
		{
			m_isValidnetworkStatus = false;
		}
		UpdateGlobalVisibility();
	}

	protected event OnNetworkLevelChanged( value : Variant )
	{
		var networkLevelData : ScannerNetworkLevel;
		networkLevelData = ( ( ScannerNetworkLevel )value );
		if( ( networkLevelData && !( m_isValidnetworkStatus ) ) && ( networkLevelData.GetNetworkLevel() > 0 ) )
		{
			m_isValidNetworkLevel = true;
			inkTextRef.SetText( m_levelText, IntToString( networkLevelData.GetNetworkLevel() ) );
		}
		else
		{
			m_isValidNetworkLevel = false;
		}
		UpdateGlobalVisibility();
	}

	protected event OnAttitudeChange( value : Variant )
	{
		var attitudeData : ScannerAttitude;
		var attitude : EAIAttitude;
		attitudeData = ( ( ScannerAttitude )value );
		attitude = attitudeData.GetAttitude();
		switch( attitude )
		{
			case EAIAttitude.AIA_Friendly:
				inkTextRef.SetState( m_nameText, 'Friendly' );
			inkTextRef.SetState( m_fluffText, 'Friendly' );
			inkRectangleRef.SetState( m_separator1, 'Friendly' );
			inkRectangleRef.SetState( m_separator2, 'Friendly' );
			inkTextRef.SetState( m_levelText, 'Friendly' );
			inkWidgetRef.SetState( m_levelWrapper, 'Friendly' );
			break;
			case EAIAttitude.AIA_Neutral:
				inkTextRef.SetState( m_fluffText, 'Neutral' );
			inkRectangleRef.SetState( m_separator1, 'Neutral' );
			inkRectangleRef.SetState( m_separator2, 'Neutral' );
			inkTextRef.SetState( m_nameText, 'Neutral' );
			inkTextRef.SetState( m_levelText, 'Neutral' );
			inkWidgetRef.SetState( m_levelWrapper, 'Neutral' );
			break;
			case EAIAttitude.AIA_Hostile:
				inkTextRef.SetState( m_fluffText, 'Hostile' );
			inkRectangleRef.SetState( m_separator1, 'Hostile' );
			inkRectangleRef.SetState( m_separator2, 'Hostile' );
			inkTextRef.SetState( m_nameText, 'Hostile' );
			inkTextRef.SetState( m_levelText, 'Hostile' );
			inkWidgetRef.SetState( m_levelWrapper, 'Hostile' );
			break;
		}
	}

	private function UpdateGlobalVisibility()
	{
		inkWidgetRef.SetVisible( m_levelWrapper, m_isValidNetworkLevel );
		inkTextRef.SetVisible( m_nameText, m_isValidName );
		inkTextRef.SetVisible( m_status, m_isValidDeviceStatus );
		inkImageRef.SetVisible( m_statusIcon, m_isValidDeviceStatus );
		GetRootWidget().SetVisible( m_isValidName || m_isValidNetworkLevel );
	}

}

class ScannerNPCBodyGameController extends BaseChunkGameController
{
	private editable var m_factionText : inkTextRef;
	private editable var m_dataBaseWidgetHolder : inkWidgetRef;
	private var m_factionCallbackID : CallbackHandle;
	private var m_rarityCallbackID : CallbackHandle;
	private var m_isValidFaction : Bool;
	private var m_asyncSpawnRequest : weak< inkAsyncSpawnRequest >;

	protected event OnInitialize()
	{
		super.OnInitialize();
		m_factionCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerFaction, this, 'OnFactionChanged' );
		m_rarityCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerRarity, this, 'OnRarityChanged' );
		OnFactionChanged( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerFaction ) );
		OnRarityChanged( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerRarity ) );
	}

	protected event OnUninitialize()
	{
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerFaction, m_factionCallbackID );
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerRarity, m_rarityCallbackID );
	}

	protected event OnFactionChanged( value : Variant )
	{
		var factionData : ScannerFaction;
		factionData = ( ( ScannerFaction )value );
		if( factionData )
		{
			inkTextRef.SetLocalizedTextScript( m_factionText, factionData.GetFaction() );
			m_isValidFaction = true;
		}
		else
		{
			m_isValidFaction = false;
		}
		UpdateGlobalVisibility();
	}

	protected event OnRarityChanged( value : Variant )
	{
		var rarityData : ScannerRarity;
		m_asyncSpawnRequest.Cancel();
		rarityData = ( ( ScannerRarity )value );
		if( rarityData.IsCivilian() && !( m_asyncSpawnRequest ) )
		{
			m_asyncSpawnRequest = AsyncSpawnFromLocal( inkWidgetRef.Get( m_dataBaseWidgetHolder ), 'ScannerCitizenDB', this, 'OnCitizenDBSpawned' );
		}
	}

	protected event OnCitizenDBSpawned( widget : inkWidget, userData : IScriptable )
	{
		m_asyncSpawnRequest = NULL;
	}

	private function UpdateGlobalVisibility()
	{
		GetRootWidget().SetVisible( m_isValidFaction );
		inkTextRef.SetVisible( m_factionText, m_isValidFaction );
	}

}

class ScannerDeviceBodyGameController extends BaseChunkGameController
{
	private editable var m_networkStatusText : inkTextRef;
	private editable var m_deviceAuthorizationText : inkTextRef;
	private editable var m_deviceAuthorizationRow : inkCompoundRef;
	private editable var m_networkStatusRow : inkCompoundRef;
	private var m_networkStatusCallbackID : CallbackHandle;
	private var m_deviceAuthorizationCallbackID : CallbackHandle;
	private var m_isValidnetworkStatus : Bool;
	private var m_isValidDeviceAuthorization : Bool;

	protected event OnInitialize()
	{
		super.OnInitialize();
		m_networkStatusCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerNetworkStatus, this, 'OnNetworkStatusChanged' );
		m_deviceAuthorizationCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerAuthorization, this, 'OnDeviceAuthorizationChanged' );
		OnNetworkStatusChanged( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerNetworkStatus ) );
		OnDeviceAuthorizationChanged( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerAuthorization ) );
	}

	protected event OnUninitialize()
	{
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerNetworkStatus, m_networkStatusCallbackID );
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerAuthorization, m_deviceAuthorizationCallbackID );
	}

	protected event OnNetworkStatusChanged( value : Variant )
	{
		var networkStatusData : ScannerNetworkStatus;
		networkStatusData = ( ( ScannerNetworkStatus )value );
		if( networkStatusData )
		{
			if( networkStatusData.GetNetworkStatus() != ScannerNetworkState.NOT_BREACHED )
			{
				inkTextRef.SetText( m_networkStatusText, ( ( String )( networkStatusData.GetNetworkStatus() ) ) );
				m_isValidnetworkStatus = true;
			}
			else
			{
				m_isValidnetworkStatus = false;
			}
		}
		else
		{
			m_isValidnetworkStatus = false;
		}
		UpdateGlobalVisibility();
	}

	protected event OnDeviceAuthorizationChanged( value : Variant )
	{
		var deviceAuthorizationData : ScannerAuthorization;
		deviceAuthorizationData = ( ( ScannerAuthorization )value );
		if( deviceAuthorizationData )
		{
			m_isValidDeviceAuthorization = true;
			if( deviceAuthorizationData.ProtectedByKeycard() )
			{
				inkTextRef.SetLocalizedTextScript( m_deviceAuthorizationText, "Gameplay-Devices-DisplayNames-Keycard" );
			}
			if( deviceAuthorizationData.ProtectedByPassword() )
			{
				inkTextRef.SetLocalizedTextScript( m_deviceAuthorizationText, "Gameplay-Devices-DisplayNames-PasssodeRequired" );
			}
		}
		else
		{
			m_isValidDeviceAuthorization = false;
		}
		UpdateGlobalVisibility();
	}

	private function UpdateGlobalVisibility()
	{
		GetRootWidget().SetVisible( m_isValidnetworkStatus || m_isValidDeviceAuthorization );
		inkCompoundRef.SetVisible( m_networkStatusRow, m_isValidnetworkStatus );
		inkCompoundRef.SetVisible( m_deviceAuthorizationRow, m_isValidDeviceAuthorization );
	}

}

class ScannerBountySystemGameController extends BaseChunkGameController
{
	private editable var m_moneyReward : inkTextRef;
	private editable var m_moneyRewardRow : inkWidgetRef;
	private editable var m_streetCredReward : inkTextRef;
	private editable var m_streetCredRewardRow : inkWidgetRef;
	private editable var m_transgressions : inkTextRef;
	private editable var m_transgressionsWidget : inkWidgetRef;
	private editable var m_rewardPanel : inkCompoundRef;
	private editable var m_mugShot : inkRectangleRef;
	private editable var m_wanted : inkTextRef;
	private editable var m_notFound : inkTextRef;
	private editable var m_deadNotice : inkTextRef;
	private editable var m_crossedOut : inkWidgetRef;
	private const editable var starsWidget : array< inkWidgetRef >;
	private var m_bountyCallbackID : CallbackHandle;
	private var m_healthCallbackID : CallbackHandle;
	private var m_objectCallbackID : CallbackHandle;
	private var m_isValidBounty : Bool;
	private var m_isAlive : Bool;
	private var m_objectType : ScannerObjectType;
	private var m_showScanBountyAnimProxy : inkAnimProxy;

	protected event OnInitialize()
	{
		super.OnInitialize();
		m_bountyCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerBountySystem, this, 'OnBountySystemChanged' );
		m_healthCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerHealth, this, 'OnHealthChanged' );
		m_objectCallbackID = m_chunkBlackboard.RegisterDelayedListenerInt( m_chunkBlackboardDef.ObjectType, this, 'OnObjectTypeChanged' );
		OnObjectTypeChanged( m_chunkBlackboard.GetInt( m_chunkBlackboardDef.ObjectType ) );
		OnHealthChanged( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerHealth ) );
		OnBountySystemChanged( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerBountySystem ) );
	}

	protected event OnUninitialize()
	{
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerBountySystem, m_bountyCallbackID );
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerHealth, m_healthCallbackID );
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ObjectType, m_objectCallbackID );
		m_showScanBountyAnimProxy.Stop();
	}

	protected event OnBountySystemChanged( value : Variant )
	{
		var bountyData : ScannerBountySystem;
		var bountyStruct : BountyUI;
		var transgressionsList : array< String >;
		var transgressionsText : String;
		var i, limit : Int32;
		bountyData = ( ( ScannerBountySystem )value );
		m_isValidBounty = false;
		if( IsNPC() )
		{
			bountyStruct = bountyData.GetBounty();
			m_isValidBounty = true;
			if( !( bountyStruct.hasAccess ) )
			{
				m_isValidBounty = false;
				return false;
			}
			if( bountyData )
			{
				inkCompoundRef.SetVisible( m_rewardPanel, true );
				transgressionsList = bountyStruct.transgressions;
				limit = transgressionsList.Size();
				if( limit > 0 )
				{
					if( bountyStruct.streetCredReward > 0 )
					{
						inkWidgetRef.SetVisible( m_streetCredRewardRow, true );
						inkTextRef.SetText( m_streetCredReward, IntToString( bountyStruct.streetCredReward ) );
					}
					else
					{
						inkWidgetRef.SetVisible( m_streetCredRewardRow, false );
					}
					if( bountyStruct.moneyReward > 0 )
					{
						inkWidgetRef.SetVisible( m_moneyRewardRow, true );
						inkTextRef.SetText( m_moneyReward, IntToString( bountyStruct.moneyReward ) );
					}
					else
					{
						inkWidgetRef.SetVisible( m_moneyRewardRow, false );
					}
					for( i = 0; i < starsWidget.Size(); i += 1 )
					{
						if( i < bountyStruct.level )
						{
							inkWidgetRef.SetVisible( starsWidget[ i ], true );
						}
						else
						{
							inkWidgetRef.SetVisible( starsWidget[ i ], false );
						}
					}
				}
				if( m_isAlive )
				{
					if( limit > 0 )
					{
						inkWidgetRef.SetVisible( m_transgressionsWidget, true );
						for( i = 0; i < limit; i += 1 )
						{
							transgressionsText = transgressionsText + GetLocalizedText( transgressionsList[ i ] );
							if( i < limit )
							{
								transgressionsText = transgressionsText + "; ";
							}
						}
						inkTextRef.SetText( m_transgressions, transgressionsText );
					}
					else
					{
						inkWidgetRef.SetVisible( m_transgressionsWidget, false );
					}
					ProcessBountyTutorial();
				}
				else
				{
					inkWidgetRef.SetVisible( m_transgressionsWidget, false );
					inkTextRef.SetLocalizedTextScript( m_wanted, "LocKey#40654" );
					inkRectangleRef.SetVisible( m_mugShot, false );
				}
			}
			else
			{
				m_isValidBounty = true;
				inkWidgetRef.SetVisible( m_transgressionsWidget, false );
				inkCompoundRef.SetVisible( m_rewardPanel, false );
				inkTextRef.SetVisible( m_notFound, true );
				inkTextRef.SetLocalizedTextScript( m_notFound, "LocKey#40655" );
				inkRectangleRef.SetVisible( m_mugShot, false );
				inkTextRef.SetVisible( m_wanted, false );
			}
		}
		UpdateGlobalVisibility();
	}

	private function ProcessBountyTutorial()
	{
		var questsSystem : QuestsSystem;
		questsSystem = GameInstance.GetQuestsSystem( ( ( GameObject )( GetOwnerEntity() ) ).GetGame() );
		if( questsSystem.GetFact( 'tutorial_scanner_bounty_displayed' ) == 0 )
		{
			questsSystem.SetFact( 'tutorial_scanner_bounty_displayed', 1 );
		}
	}

	protected event OnHealthChanged( value : Variant )
	{
		var healthData : ScannerHealth;
		healthData = ( ( ScannerHealth )value );
		m_isAlive = healthData.GetCurrentHealth() > 0;
		UpdateGlobalVisibility();
	}

	protected event OnObjectTypeChanged( value : Int32 )
	{
		m_objectType = ( ( ScannerObjectType )( value ) );
	}

	private function IsNPC() : Bool
	{
		return ( ( m_objectType == ScannerObjectType.PUPPET ) ? ( true ) : ( false ) );
	}

	private function UpdateGlobalVisibility()
	{
		GetRootWidget().SetVisible( m_isValidBounty );
		m_showScanBountyAnimProxy = PlayLibraryAnimation( 'bounty' );
	}

}

class ScannerVulnerabilitiesGameController extends BaseChunkGameController
{
	private editable var m_ScannerVulnerabilitiesRightPanel : inkCompoundRef;
	private var m_vulnerabilitiesCallbackID : CallbackHandle;
	private var m_isValidVulnerabilities : Bool;
	private var m_asyncSpawnRequests : array< weak< inkAsyncSpawnRequest > >;

	protected event OnInitialize()
	{
		super.OnInitialize();
		m_vulnerabilitiesCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerVulnerabilities, this, 'OnVulnerabilitiesChanged' );
		OnVulnerabilitiesChanged( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerVulnerabilities ) );
	}

	protected event OnUninitialize()
	{
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerVulnerabilities, m_vulnerabilitiesCallbackID );
	}

	protected event OnVulnerabilitiesChanged( value : Variant )
	{
		var vulnerabilitiesData : ScannerVulnerabilities;
		var vulnerabilityStruct : Vulnerability;
		var vulnerabilitiesList : array< Vulnerability >;
		var vulnerabilityUserData : VulnerabilityUserData;
		var asyncSpawnRequest : weak< inkAsyncSpawnRequest >;
		var i, limit : Int32;
		vulnerabilitiesData = ( ( ScannerVulnerabilities )value );
		ClearAllAsyncSpawnRequests();
		if( vulnerabilitiesData )
		{
			vulnerabilitiesList = vulnerabilitiesData.GetVulnerabilities();
			limit = vulnerabilitiesList.Size();
			for( i = 0; i < limit; i += 1 )
			{
				vulnerabilityStruct = vulnerabilitiesList[ i ];
				vulnerabilityUserData = new VulnerabilityUserData;
				vulnerabilityUserData.vulnerabilityName = vulnerabilityStruct.vulnerabilityName;
				vulnerabilityUserData.icon = vulnerabilityStruct.icon;
				vulnerabilityUserData.isActive = vulnerabilityStruct.isActive;
				asyncSpawnRequest = AsyncSpawnFromLocal( inkCompoundRef.Get( m_ScannerVulnerabilitiesRightPanel ), 'ScannerVulnerabilityItemWidget', this, 'OnVulnerabilitySpawned', vulnerabilityUserData );
				vulnerabilityUserData.asyncSpawnRequest = asyncSpawnRequest;
				m_asyncSpawnRequests.PushBack( asyncSpawnRequest );
			}
			m_isValidVulnerabilities = true;
		}
		else
		{
			m_isValidVulnerabilities = false;
		}
		UpdateGlobalVisibility();
	}

	protected event OnVulnerabilitySpawned( widget : inkWidget, userData : IScriptable )
	{
		var vulnerabilityUserData : VulnerabilityUserData;
		vulnerabilityUserData = ( ( VulnerabilityUserData )( userData ) );
		if( vulnerabilityUserData )
		{
			ClearAsyncSpawnRequest( vulnerabilityUserData.asyncSpawnRequest );
			( ( ScannerVulnerabilityItemLogicController )( widget.GetController() ) ).Setup( userData );
		}
	}

	private function UpdateGlobalVisibility()
	{
		GetRootWidget().SetVisible( m_isValidVulnerabilities );
	}

	private function ClearAsyncSpawnRequest( request : weak< inkAsyncSpawnRequest > )
	{
		var i : Int32;
		for( i = 0; i < m_asyncSpawnRequests.Size(); i += 1 )
		{
			if( m_asyncSpawnRequests[ i ] == request )
			{
				m_asyncSpawnRequests[ i ] = NULL;
				m_asyncSpawnRequests.Erase( i );
				break;
			}
		}
	}

	private function ClearAllAsyncSpawnRequests()
	{
		var i : Int32;
		for( i = 0; i < m_asyncSpawnRequests.Size(); i += 1 )
		{
			m_asyncSpawnRequests[ i ].Cancel();
			m_asyncSpawnRequests[ i ] = NULL;
		}
		m_asyncSpawnRequests.Clear();
	}

}

class VulnerabilityUserData extends IScriptable
{
	var vulnerabilityName : CName;
	var icon : TweakDBID;
	var isActive : Bool;
	var asyncSpawnRequest : weak< inkAsyncSpawnRequest >;
}

class ScannerVulnerabilityItemLogicController extends inkLogicController
{
	private editable var m_vulnerabilityNameText : inkTextRef;
	private editable var m_vulnerabilityIcon : inkImageRef;

	public function Setup( vulnerability : IScriptable )
	{
		var iconRecordID : TweakDBID;
		var vulnerabilityUserData : VulnerabilityUserData;
		vulnerabilityUserData = ( ( VulnerabilityUserData )( vulnerability ) );
		inkTextRef.SetLocalizedTextScript( m_vulnerabilityNameText, vulnerabilityUserData.vulnerabilityName );
		iconRecordID = vulnerabilityUserData.icon;
		SetTexture( m_vulnerabilityIcon, iconRecordID );
		if( !( vulnerabilityUserData.isActive ) )
		{
			inkTextRef.SetState( m_vulnerabilityNameText, 'Failed' );
			inkImageRef.SetState( m_vulnerabilityIcon, 'Failed' );
		}
		else
		{
			inkTextRef.SetState( m_vulnerabilityNameText, 'Passed' );
			inkImageRef.SetState( m_vulnerabilityIcon, 'Passed' );
		}
	}

}

class ScannerAbilitiesGameController extends BaseChunkGameController
{
	private editable var m_ScannerAbilitiesRightPanel : inkCompoundRef;
	private var m_abilitiesCallbackID : CallbackHandle;
	private var m_isValidAbilities : Bool;
	private var m_asyncSpawnRequests : array< weak< inkAsyncSpawnRequest > >;

	protected event OnInitialize()
	{
		super.OnInitialize();
		m_abilitiesCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerAbilities, this, 'OnAbilitiesChanged' );
		OnAbilitiesChanged( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerAbilities ) );
	}

	protected event OnUninitialize()
	{
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerAbilities, m_abilitiesCallbackID );
	}

	protected event OnAbilitiesChanged( value : Variant )
	{
		var abilitiesData : ScannerAbilities;
		var abilityStruct : GameplayAbility_Record;
		var abilitiesList : array< weak< GameplayAbility_Record > >;
		var abilityData : AbilityUserData;
		var asyncSpawnRequest : weak< inkAsyncSpawnRequest >;
		var i, limit : Int32;
		abilitiesData = ( ( ScannerAbilities )value );
		ClearAllAsyncSpawnRequests();
		if( abilitiesData )
		{
			abilitiesList = abilitiesData.GetAbilities();
			limit = abilitiesList.Size();
			for( i = 0; i < limit; i += 1 )
			{
				abilityStruct = abilitiesList[ i ];
				if( abilityStruct.ShowInCodex() )
				{
					abilityData = new AbilityUserData;
					abilityData.abilityID = abilityStruct.GetID();
					abilityData.locKeyName = abilityStruct.Loc_key_name();
					asyncSpawnRequest = AsyncSpawnFromLocal( inkCompoundRef.Get( m_ScannerAbilitiesRightPanel ), 'ScannerAbilityItemWidget', this, 'OnAbilitySpawned', abilityData );
					abilityData.asyncSpawnRequest = asyncSpawnRequest;
					m_asyncSpawnRequests.PushBack( asyncSpawnRequest );
				}
			}
			m_isValidAbilities = true;
		}
		else
		{
			m_isValidAbilities = false;
		}
		UpdateGlobalVisibility();
	}

	protected event OnAbilitySpawned( widget : inkWidget, userData : IScriptable )
	{
		var abilityData : AbilityUserData;
		abilityData = ( ( AbilityUserData )( userData ) );
		if( abilityData )
		{
			ClearAsyncSpawnRequest( abilityData.asyncSpawnRequest );
			( ( ScannerAbilityItemLogicController )( widget.GetController() ) ).Setup( userData );
		}
	}

	private function ClearAsyncSpawnRequest( request : weak< inkAsyncSpawnRequest > )
	{
		var i : Int32;
		for( i = 0; i < m_asyncSpawnRequests.Size(); i += 1 )
		{
			if( m_asyncSpawnRequests[ i ] == request )
			{
				m_asyncSpawnRequests[ i ] = NULL;
				m_asyncSpawnRequests.Erase( i );
				break;
			}
		}
	}

	private function ClearAllAsyncSpawnRequests()
	{
		var i : Int32;
		for( i = 0; i < m_asyncSpawnRequests.Size(); i += 1 )
		{
			m_asyncSpawnRequests[ i ].Cancel();
			m_asyncSpawnRequests[ i ] = NULL;
		}
		m_asyncSpawnRequests.Clear();
	}

	private function UpdateGlobalVisibility()
	{
		GetRootWidget().SetVisible( m_isValidAbilities );
	}

}

class AbilityUserData extends IScriptable
{
	var abilityID : TweakDBID;
	var locKeyName : CName;
	var asyncSpawnRequest : weak< inkAsyncSpawnRequest >;
}

class ScannerAbilityItemLogicController extends inkLogicController
{
	private editable var m_abilityNameText : inkTextRef;
	private editable var m_abilityIcon : inkImageRef;

	public function Setup( ability : IScriptable )
	{
		var iconName : TweakDBID;
		var iconPrefix : String;
		var iconRecord : UIIcon_Record;
		var abilityData : AbilityUserData;
		abilityData = ( ( AbilityUserData )( ability ) );
		iconPrefix = "UIIcon.";
		iconName = TDBID.Create( iconPrefix );
		TDBID.Append( iconName, abilityData.abilityID );
		inkTextRef.SetLocalizedTextScript( m_abilityNameText, abilityData.locKeyName );
		iconRecord = TweakDBInterface.GetUIIconRecord( iconName );
		inkImageRef.SetTexturePart( m_abilityIcon, iconRecord.AtlasPartName() );
	}

}

class ScannerResistancesGameController extends BaseChunkGameController
{
	private editable var m_physicalResistText : inkTextRef;
	private editable var m_physicalResistContainer : inkCompoundRef;
	private editable var m_thermalResistText : inkTextRef;
	private editable var m_thermalResistContainer : inkCompoundRef;
	private editable var m_chemicalResistText : inkTextRef;
	private editable var m_chemicalResistContainer : inkCompoundRef;
	private editable var m_electricResistText : inkTextRef;
	private editable var m_electricResistContainer : inkCompoundRef;
	private editable var m_hackingResistText : inkTextRef;
	private editable var m_hackingResistContainer : inkCompoundRef;
	private editable var m_physicalWeaknessText : inkTextRef;
	private editable var m_physicalWeaknessContainer : inkCompoundRef;
	private editable var m_thermalWeaknessText : inkTextRef;
	private editable var m_thermalWeaknessContainer : inkCompoundRef;
	private editable var m_chemicalWeaknessText : inkTextRef;
	private editable var m_chemicalWeaknessContainer : inkCompoundRef;
	private editable var m_electricWeaknessText : inkTextRef;
	private editable var m_electricWeaknessContainer : inkCompoundRef;
	private editable var m_hackingWeaknessText : inkTextRef;
	private editable var m_hackingWeaknessContainer : inkCompoundRef;
	private editable var m_leftPanel : inkCompoundRef;
	private editable var m_rightPanel : inkCompoundRef;
	private var m_resistancesCallbackID : CallbackHandle;
	private var m_isValidResistances : Bool;

	protected event OnInitialize()
	{
		super.OnInitialize();
		m_resistancesCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerResistances, this, 'OnResistancesChanged' );
		OnResistancesChanged( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerResistances ) );
	}

	protected event OnUninitialize()
	{
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerResistances, m_resistancesCallbackID );
	}

	protected event OnResistancesChanged( value : Variant )
	{
		var resistanceData : ScannerResistances;
		var resistancesList : array< ScannerStatDetails >;
		var physicalResistanceValue : Int32;
		var thermalResistanceValue : Int32;
		var electricResistanceValue : Int32;
		var chemicalResistanceValue : Int32;
		var hackingResistanceValue : Int32;
		var hackingBaseValue : Int32;
		var i : Int32;
		resistanceData = ( ( ScannerResistances )value );
		if( resistanceData )
		{
			resistancesList = resistanceData.GetResistances();
			inkCompoundRef.SetVisible( m_leftPanel, false );
			inkCompoundRef.SetVisible( m_rightPanel, false );
			inkCompoundRef.SetVisible( m_physicalResistContainer, false );
			inkCompoundRef.SetVisible( m_thermalResistContainer, false );
			inkCompoundRef.SetVisible( m_chemicalResistContainer, false );
			inkCompoundRef.SetVisible( m_electricResistContainer, false );
			inkCompoundRef.SetVisible( m_hackingResistContainer, false );
			inkCompoundRef.SetVisible( m_physicalWeaknessContainer, false );
			inkCompoundRef.SetVisible( m_thermalWeaknessContainer, false );
			inkCompoundRef.SetVisible( m_chemicalWeaknessContainer, false );
			inkCompoundRef.SetVisible( m_electricWeaknessContainer, false );
			inkCompoundRef.SetVisible( m_hackingWeaknessContainer, false );
			for( i = 0; i < resistancesList.Size(); i += 1 )
			{
				switch( resistancesList[ i ].statType )
				{
					case gamedataStatType.PhysicalResistance:
						physicalResistanceValue = RoundMath( resistancesList[ i ].value );
					if( physicalResistanceValue > 0 )
					{
						inkCompoundRef.SetVisible( m_rightPanel, true );
						inkCompoundRef.SetVisible( m_physicalResistContainer, true );
						inkTextRef.SetText( m_physicalResistText, ( ( String )( Abs( physicalResistanceValue ) + " %" ) ) );
						m_isValidResistances = true;
					}
					else if( physicalResistanceValue < 0 )
					{
						inkCompoundRef.SetVisible( m_leftPanel, true );
						inkCompoundRef.SetVisible( m_physicalWeaknessContainer, true );
						inkTextRef.SetText( m_physicalWeaknessText, ( ( String )( Abs( physicalResistanceValue ) + " %" ) ) );
						m_isValidResistances = true;
					}
					else
					{
						inkCompoundRef.SetVisible( m_physicalResistContainer, false );
						inkCompoundRef.SetVisible( m_physicalWeaknessContainer, false );
					}
					break;
					case gamedataStatType.ThermalResistance:
						thermalResistanceValue = RoundMath( resistancesList[ i ].value );
					if( thermalResistanceValue > 0 )
					{
						inkCompoundRef.SetVisible( m_rightPanel, true );
						inkCompoundRef.SetVisible( m_thermalResistContainer, true );
						inkTextRef.SetText( m_thermalResistText, ( ( String )( Abs( thermalResistanceValue ) + " %" ) ) );
						m_isValidResistances = true;
					}
					else if( thermalResistanceValue < 0 )
					{
						inkCompoundRef.SetVisible( m_leftPanel, true );
						inkCompoundRef.SetVisible( m_thermalWeaknessContainer, true );
						inkTextRef.SetText( m_thermalWeaknessText, ( ( String )( Abs( thermalResistanceValue ) + " %" ) ) );
						m_isValidResistances = true;
					}
					else
					{
						inkCompoundRef.SetVisible( m_thermalResistContainer, false );
						inkCompoundRef.SetVisible( m_thermalWeaknessContainer, false );
					}
					break;
					case gamedataStatType.ElectricResistance:
						electricResistanceValue = RoundMath( resistancesList[ i ].value );
					if( electricResistanceValue > 0 )
					{
						inkCompoundRef.SetVisible( m_rightPanel, true );
						inkCompoundRef.SetVisible( m_electricResistContainer, true );
						inkTextRef.SetText( m_electricResistText, ( ( String )( Abs( electricResistanceValue ) + " %" ) ) );
						m_isValidResistances = true;
					}
					else if( electricResistanceValue < 0 )
					{
						inkCompoundRef.SetVisible( m_leftPanel, true );
						inkCompoundRef.SetVisible( m_electricWeaknessContainer, true );
						inkTextRef.SetText( m_electricWeaknessText, ( ( String )( Abs( electricResistanceValue ) + " %" ) ) );
						m_isValidResistances = true;
					}
					else
					{
						inkCompoundRef.SetVisible( m_electricResistContainer, false );
						inkCompoundRef.SetVisible( m_electricWeaknessContainer, false );
					}
					break;
					case gamedataStatType.ChemicalResistance:
						chemicalResistanceValue = RoundMath( resistancesList[ i ].value );
					if( chemicalResistanceValue > 0 )
					{
						inkCompoundRef.SetVisible( m_rightPanel, true );
						inkCompoundRef.SetVisible( m_chemicalResistContainer, true );
						inkTextRef.SetText( m_chemicalResistText, ( ( String )( Abs( chemicalResistanceValue ) + " %" ) ) );
						m_isValidResistances = true;
					}
					else if( chemicalResistanceValue < 0 )
					{
						inkCompoundRef.SetVisible( m_leftPanel, true );
						inkCompoundRef.SetVisible( m_chemicalWeaknessContainer, true );
						inkTextRef.SetText( m_chemicalWeaknessText, ( ( String )( Abs( chemicalResistanceValue ) + " %" ) ) );
						m_isValidResistances = true;
					}
					else
					{
						inkCompoundRef.SetVisible( m_chemicalResistContainer, false );
						inkCompoundRef.SetVisible( m_chemicalWeaknessContainer, false );
					}
					break;
					case gamedataStatType.HackingResistance:
						hackingResistanceValue = RoundMath( resistancesList[ i ].value );
					hackingBaseValue = RoundMath( resistancesList[ i ].baseValue );
					if( ( hackingBaseValue > 0 ) && ( hackingResistanceValue > 0 ) )
					{
						inkCompoundRef.SetVisible( m_rightPanel, true );
						inkCompoundRef.SetVisible( m_hackingResistContainer, true );
						inkTextRef.SetText( m_hackingResistText, "+" + ( ( String )( Abs( hackingResistanceValue ) ) ) );
						m_isValidResistances = true;
					}
					else if( ( hackingBaseValue < 0 ) && ( hackingResistanceValue < 0 ) )
					{
						inkCompoundRef.SetVisible( m_leftPanel, true );
						inkCompoundRef.SetVisible( m_hackingWeaknessContainer, true );
						inkTextRef.SetText( m_hackingWeaknessText, "-" + ( ( String )( Abs( hackingResistanceValue ) ) ) );
						m_isValidResistances = true;
					}
					else
					{
						inkCompoundRef.SetVisible( m_hackingResistContainer, false );
						inkCompoundRef.SetVisible( m_hackingWeaknessContainer, false );
					}
					break;
					default:
						m_isValidResistances = false;
				}
			}
		}
		else
		{
			m_isValidResistances = false;
		}
		UpdateGlobalVisibility();
	}

	private function UpdateGlobalVisibility()
	{
		GetRootWidget().SetVisible( m_isValidResistances );
	}

}

class ScannerDescriptionGameController extends BaseChunkGameController
{
	private editable var m_descriptionText : inkTextRef;
	private editable var m_customDescriptionText : inkTextRef;
	private var m_descriptionCallbackID : CallbackHandle;
	private var m_isValidDescription : Bool;
	private var m_isValidCustomDescription : Bool;

	protected event OnInitialize()
	{
		super.OnInitialize();
		m_descriptionCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerDescription, this, 'OnDescriptionChanged' );
		OnDescriptionChanged( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerDescription ) );
	}

	protected event OnUninitialize()
	{
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerDescription, m_descriptionCallbackID );
	}

	protected event OnDescriptionChanged( value : Variant )
	{
		var descriptionData : ScannerDescription;
		var defaultFluffDescription : String;
		var customDescriptionsConcatenated : String;
		var customDescriptions : array< String >;
		var i : Int32;
		descriptionData = ( ( ScannerDescription )value );
		defaultFluffDescription = descriptionData.GetDefaultDescription();
		customDescriptions = descriptionData.GetCustomDescriptions();
		if( defaultFluffDescription == "" && ( customDescriptions.Size() == 0 ) )
		{
			m_isValidDescription = false;
		}
		if( defaultFluffDescription != "" )
		{
			inkTextRef.SetLocalizedTextScript( m_descriptionText, defaultFluffDescription );
			m_isValidDescription = true;
		}
		if( customDescriptions.Size() > 0 )
		{
			for( i = 0; i < customDescriptions.Size(); i += 1 )
			{
				if( i > 0 )
				{
					customDescriptionsConcatenated = customDescriptionsConcatenated + "\n";
				}
				customDescriptionsConcatenated = customDescriptionsConcatenated + customDescriptions[ i ];
			}
			inkTextRef.SetLocalizedTextScript( m_customDescriptionText, customDescriptionsConcatenated );
			m_isValidCustomDescription = true;
		}
		UpdateGlobalVisibility();
	}

	private function UpdateGlobalVisibility()
	{
		GetRootWidget().SetVisible( m_isValidDescription || m_isValidCustomDescription );
		inkTextRef.SetVisible( m_descriptionText, m_isValidDescription );
		inkTextRef.SetVisible( m_customDescriptionText, m_isValidCustomDescription );
	}

}

class ScannerRequirementsGameController extends BaseChunkGameController
{
	private editable var m_ScannerRequirementsRightPanel : inkCompoundRef;
	private var m_requirementsCallbackID : CallbackHandle;
	private var m_isValidRequirements : Bool;
	private var m_asyncSpawnRequests : array< weak< inkAsyncSpawnRequest > >;

	protected event OnInitialize()
	{
		super.OnInitialize();
		m_requirementsCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerSkillChecks, this, 'OnRequirementsChanged' );
		OnRequirementsChanged( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerSkillChecks ) );
	}

	protected event OnUninitialize()
	{
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerSkillChecks, m_requirementsCallbackID );
	}

	protected event OnRequirementsChanged( value : Variant )
	{
		var requirementsData : ScannerSkillchecks;
		var requirementStruct : UIInteractionSkillCheck;
		var requirementList : array< UIInteractionSkillCheck >;
		var requirementUserData : RequirementUserData;
		var asyncSpawnRequest : weak< inkAsyncSpawnRequest >;
		var i, limit : Int32;
		requirementsData = ( ( ScannerSkillchecks )value );
		ClearAllAsyncSpawnRequests();
		if( requirementsData )
		{
			requirementList = requirementsData.GetSkillchecks();
			limit = requirementList.Size();
			for( i = 0; i < limit; i += 1 )
			{
				requirementStruct = requirementList[ i ];
				requirementUserData = new RequirementUserData;
				requirementUserData.skillName = requirementStruct.skillName;
				requirementUserData.requiredSkill = requirementStruct.requiredSkill;
				requirementUserData.skillCheck = requirementStruct.skillCheck;
				requirementUserData.isPassed = requirementStruct.isPassed;
				asyncSpawnRequest = AsyncSpawnFromLocal( inkCompoundRef.Get( m_ScannerRequirementsRightPanel ), 'ScannerRequirementItemWidget', this, 'OnRequirementSpawned', requirementUserData );
				requirementUserData.asyncSpawnRequest = asyncSpawnRequest;
				m_asyncSpawnRequests.PushBack( asyncSpawnRequest );
			}
			m_isValidRequirements = true;
		}
		else
		{
			m_isValidRequirements = false;
		}
		UpdateGlobalVisibility();
	}

	protected event OnRequirementSpawned( widget : inkWidget, userData : IScriptable )
	{
		var requirementUserData : RequirementUserData;
		requirementUserData = ( ( RequirementUserData )( userData ) );
		if( requirementUserData )
		{
			ClearAsyncSpawnRequest( requirementUserData.asyncSpawnRequest );
			( ( ScannerRequirementItemLogicController )( widget.GetController() ) ).Setup( userData );
		}
	}

	private function UpdateGlobalVisibility()
	{
		GetRootWidget().SetVisible( m_isValidRequirements );
	}

	private function ClearAsyncSpawnRequest( request : weak< inkAsyncSpawnRequest > )
	{
		var i : Int32;
		for( i = 0; i < m_asyncSpawnRequests.Size(); i += 1 )
		{
			if( m_asyncSpawnRequests[ i ] == request )
			{
				m_asyncSpawnRequests[ i ] = NULL;
				m_asyncSpawnRequests.Erase( i );
				break;
			}
		}
	}

	private function ClearAllAsyncSpawnRequests()
	{
		var i : Int32;
		for( i = 0; i < m_asyncSpawnRequests.Size(); i += 1 )
		{
			m_asyncSpawnRequests[ i ].Cancel();
			m_asyncSpawnRequests[ i ] = NULL;
		}
		m_asyncSpawnRequests.Clear();
	}

}

class RequirementUserData extends IScriptable
{
	var skillName : String;
	var requiredSkill : Int32;
	var skillCheck : EDeviceChallengeSkill;
	var isPassed : Bool;
	var asyncSpawnRequest : weak< inkAsyncSpawnRequest >;
}

class ScannerRequirementItemLogicController extends inkLogicController
{
	private editable var m_requirementNameText : inkTextRef;
	private editable var m_requirementLevelText : inkTextRef;
	private editable var m_requirementIcon : inkImageRef;
	private var m_skillCheck : EDeviceChallengeSkill;
	private var requirementUserData : RequirementUserData;

	public function Setup( requirement : IScriptable )
	{
		requirementUserData = ( ( RequirementUserData )( requirement ) );
		inkTextRef.SetLocalizedTextScript( m_requirementNameText, requirementUserData.skillName );
		inkTextRef.SetText( m_requirementLevelText, ( "[ " + ( ( String )( requirementUserData.requiredSkill ) ) ) + " ]" );
		m_skillCheck = requirementUserData.skillCheck;
		switch( m_skillCheck )
		{
			case EDeviceChallengeSkill.Hacking:
				inkImageRef.SetTexturePart( m_requirementIcon, 'ico_int' );
			break;
			case EDeviceChallengeSkill.Engineering:
				inkImageRef.SetTexturePart( m_requirementIcon, 'ico_tech' );
			break;
			case EDeviceChallengeSkill.Athletics:
				inkImageRef.SetTexturePart( m_requirementIcon, 'ico_body' );
			break;
			case EDeviceChallengeSkill.Invalid:
				inkImageRef.SetTexturePart( m_requirementIcon, 'ico_cool' );
			break;
			default:
				inkImageRef.SetTexturePart( m_requirementIcon, 'ico_body' );
		}
		if( !( requirementUserData.isPassed ) )
		{
			inkTextRef.SetState( m_requirementNameText, 'inactive' );
			inkImageRef.SetState( m_requirementIcon, 'inactive' );
			inkTextRef.SetState( m_requirementLevelText, 'inactive' );
		}
	}

}

class ScannerQuestCluesGameController extends BaseChunkGameController
{
	private editable var m_ScannerQuestPanel : inkCompoundRef;
	private var m_questCluesCallbackID : CallbackHandle;
	private var m_scannerDataCallbackID : CallbackHandle;
	private var m_isValidQuestClues : Bool;
	private var m_ScannerData : scannerDataStructure;
	private var m_hasValidScannables : Bool;
	private var m_asyncSpawnRequests : array< weak< inkAsyncSpawnRequest > >;

	protected event OnInitialize()
	{
		m_questClueBlackboardDef = GetAllBlackboardDefs().UI_Scanner;
		m_chunkBlackboard = GetBlackboardSystem().Get( m_questClueBlackboardDef );
		m_questCluesCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_questClueBlackboardDef.Scannables, this, 'OnQuestCluesChanged' );
		m_scannerDataCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_questClueBlackboardDef.scannerData, this, 'OnScannerDataChange' );
		OnQuestCluesChanged( m_chunkBlackboard.GetVariant( m_questClueBlackboardDef.Scannables ) );
		OnScannerDataChange( m_chunkBlackboard.GetVariant( m_questClueBlackboardDef.scannerData ) );
	}

	protected event OnUninitialize()
	{
		m_chunkBlackboard.UnregisterDelayedListener( m_questClueBlackboardDef.Scannables, m_questCluesCallbackID );
		m_chunkBlackboard.UnregisterDelayedListener( m_questClueBlackboardDef.scannerData, m_scannerDataCallbackID );
	}

	protected event OnScannerDataChange( val : Variant )
	{
		if( val.IsValid() )
		{
			m_ScannerData = ( ( scannerDataStructure )val );
		}
		Refresh();
	}

	protected event OnQuestCluesChanged( value : Variant )
	{
		var questEntry : scannerQuestEntry;
		var scannables : array< ScanningTooltipElementData >;
		var i : Int32;
		if( value.IsValid() )
		{
			scannables = ( ( array< ScanningTooltipElementData > )value );
		}
		m_ScannerData.questEntries.Clear();
		if( scannables.Size() > 0 )
		{
			for( i = 0; i < scannables.Size(); i += 1 )
			{
				questEntry.categoryName = scannables[ i ].localizedName;
				questEntry.entryName = scannables[ i ].localizedDescription;
				questEntry.recordID = scannables[ i ].recordID;
				m_ScannerData.questEntries.PushBack( questEntry );
			}
		}
		m_hasValidScannables = false;
		for( i = 0; i < scannables.Size(); i += 1 )
		{
			if( TDBID.IsValid( scannables[ i ].recordID ) )
			{
				m_hasValidScannables = true;
				break;
			}
		}
		Refresh();
	}

	private function Refresh()
	{
		var i, limit : Int32;
		var questEntryUserData : QuestEntryUserData;
		var questEntry : scannerQuestEntry;
		var asyncSpawnRequest : weak< inkAsyncSpawnRequest >;
		for( i = 0; i < m_asyncSpawnRequests.Size(); i += 1 )
		{
			m_asyncSpawnRequests[ i ].Cancel();
			m_asyncSpawnRequests[ i ] = NULL;
		}
		m_asyncSpawnRequests.Clear();
		limit = m_ScannerData.questEntries.Size();
		inkCompoundRef.RemoveAllChildren( m_ScannerQuestPanel );
		inkCompoundRef.SetVisible( m_ScannerQuestPanel, m_hasValidScannables && ( limit > 0 ) );
		for( i = 0; i < limit; i += 1 )
		{
			questEntry = m_ScannerData.questEntries[ i ];
			questEntryUserData = new QuestEntryUserData;
			questEntryUserData.categoryName = questEntry.categoryName;
			questEntryUserData.entryName = questEntry.entryName;
			questEntryUserData.recordID = questEntry.recordID;
			asyncSpawnRequest = AsyncSpawnFromLocal( inkCompoundRef.Get( m_ScannerQuestPanel ), 'questDescription', this, 'OnQuestEntrySpawned', questEntryUserData );
			questEntryUserData.asyncSpawnRequest = asyncSpawnRequest;
			m_asyncSpawnRequests.PushBack( asyncSpawnRequest );
		}
	}

	protected event OnQuestEntrySpawned( widget : inkWidget, userData : IScriptable )
	{
		var questEntryUserData : QuestEntryUserData;
		questEntryUserData = ( ( QuestEntryUserData )( userData ) );
		if( questEntryUserData )
		{
			ClearAsyncSpawnRequest( questEntryUserData.asyncSpawnRequest );
			( ( ScannerQuestClue )( widget.GetController() ) ).Setup( userData );
		}
	}

	private function UpdateGlobalVisibility()
	{
		GetRootWidget().SetVisible( m_hasValidScannables );
	}

	private function ClearAsyncSpawnRequest( request : weak< inkAsyncSpawnRequest > )
	{
		var i : Int32;
		for( i = 0; i < m_asyncSpawnRequests.Size(); i += 1 )
		{
			if( m_asyncSpawnRequests[ i ] == request )
			{
				m_asyncSpawnRequests[ i ] = NULL;
				m_asyncSpawnRequests.Erase( i );
				break;
			}
		}
	}

}

class QuestEntryUserData extends IScriptable
{
	var categoryName : CName;
	var entryName : CName;
	var recordID : TweakDBID;
	var asyncSpawnRequest : weak< inkAsyncSpawnRequest >;
}

class ScannervehicleGameController extends BaseChunkGameController
{
	private var m_vehicleNameCallbackID : CallbackHandle;
	private var m_vehicleManufacturerCallbackID : CallbackHandle;
	private var m_vehicleProdYearsCallbackID : CallbackHandle;
	private var m_vehicleDriveLayoutCallbackID : CallbackHandle;
	private var m_vehicleHorsepowerCallbackID : CallbackHandle;
	private var m_vehicleMassCallbackID : CallbackHandle;
	private var m_vehicleStateCallbackID : CallbackHandle;
	private var m_vehicleInfoCallbackID : CallbackHandle;
	private var m_isValidVehicleManufacturer : Bool;
	private var m_isValidVehicleName : Bool;
	private var m_isValidVehicleProdYears : Bool;
	private var m_isValidVehicleDriveLayout : Bool;
	private var m_isValidVehicleHorsepower : Bool;
	private var m_isValidVehicleMass : Bool;
	private var m_isValidVehicleState : Bool;
	private var m_isValidVehicleInfo : Bool;
	private editable var m_vehicleNameText : inkTextRef;
	private editable var m_vehicleManufacturer : inkImageRef;
	private editable var m_vehicleProdYearsText : inkTextRef;
	private editable var m_vehicleDriveLayoutText : inkTextRef;
	private editable var m_vehicleHorsepowerText : inkTextRef;
	private editable var m_vehicleMassText : inkTextRef;
	private editable var m_vehicleStateText : inkTextRef;
	private editable var m_vehicleInfoText : inkTextRef;
	private editable var m_vehicleNameHolder : inkWidgetRef;
	private editable var m_vehicleProdYearsHolder : inkWidgetRef;
	private editable var m_vehicleDriveLayoutHolder : inkWidgetRef;
	private editable var m_vehicleHorsepowerHolder : inkWidgetRef;
	private editable var m_vehicleMassHolder : inkWidgetRef;
	private editable var m_vehicleStateHolder : inkWidgetRef;
	private editable var m_vehicleInfoHolder : inkWidgetRef;

	protected event OnInitialize()
	{
		super.OnInitialize();
		m_vehicleNameCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerVehicleName, this, 'OnVehicleNameChanged' );
		m_vehicleManufacturerCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerVehicleManufacturer, this, 'OnVehicleNameChanged' );
		m_vehicleProdYearsCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerVehicleProductionYears, this, 'OnVehicleProdYearsChanged' );
		m_vehicleDriveLayoutCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerVehicleDriveLayout, this, 'OnVehicleeDriveLayoutChanged' );
		m_vehicleHorsepowerCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerVehicleHorsepower, this, 'OnVehicleHorsepowerChanged' );
		m_vehicleMassCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerVehicleMass, this, 'OnVehicleMassChanged' );
		m_vehicleStateCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerVehicleState, this, 'OnVehicleStateChanged' );
		m_vehicleInfoCallbackID = m_chunkBlackboard.RegisterDelayedListenerVariant( m_chunkBlackboardDef.ScannerVehicleInfo, this, 'OnVehicleInfoChanged' );
		OnVehicleNameChanged( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerVehicleName ) );
		OnVehicleManufacturerChanged( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerVehicleManufacturer ) );
		OnVehicleProdYearsChanged( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerVehicleProductionYears ) );
		OnVehicleeDriveLayoutChanged( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerVehicleDriveLayout ) );
		OnVehicleHorsepowerChanged( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerVehicleHorsepower ) );
		OnVehicleMassChanged( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerVehicleMass ) );
		OnVehicleStateChanged( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerVehicleState ) );
		OnVehicleInfoChanged( m_chunkBlackboard.GetVariant( m_chunkBlackboardDef.ScannerVehicleInfo ) );
	}

	protected event OnUninitialize()
	{
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerVehicleName, m_vehicleNameCallbackID );
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerVehicleManufacturer, m_vehicleManufacturerCallbackID );
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerVehicleProductionYears, m_vehicleProdYearsCallbackID );
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerVehicleDriveLayout, m_vehicleDriveLayoutCallbackID );
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerVehicleHorsepower, m_vehicleHorsepowerCallbackID );
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerVehicleMass, m_vehicleMassCallbackID );
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerVehicleState, m_vehicleStateCallbackID );
		m_chunkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_ScannerModules.ScannerVehicleInfo, m_vehicleInfoCallbackID );
	}

	protected event OnVehicleNameChanged( value : Variant )
	{
		var vehicleNameData : ScannerVehicleName;
		vehicleNameData = ( ( ScannerVehicleName )value );
		if( vehicleNameData )
		{
			inkTextRef.SetLocalizedTextScript( m_vehicleNameText, vehicleNameData.GetDisplayName() );
			m_isValidVehicleName = true;
		}
		else
		{
			m_isValidVehicleName = false;
		}
		UpdateGlobalVisibility();
	}

	protected event OnVehicleManufacturerChanged( value : Variant )
	{
		var vehicleManufacturer : ScannerVehicleManufacturer;
		var iconRecord : UIIcon_Record;
		vehicleManufacturer = ( ( ScannerVehicleManufacturer )value );
		if( vehicleManufacturer )
		{
			iconRecord = TweakDBInterface.GetUIIconRecord( TDBID.Create( "UIIcon." + vehicleManufacturer.GetVehicleManufacturer() ) );
			inkImageRef.SetTexturePart( m_vehicleManufacturer, iconRecord.AtlasPartName() );
			m_isValidVehicleManufacturer = true;
		}
		else
		{
			m_isValidVehicleManufacturer = false;
		}
		UpdateGlobalVisibility();
	}

	protected event OnVehicleProdYearsChanged( value : Variant )
	{
		var vehicleProductionYearsData : ScannerVehicleProdYears;
		vehicleProductionYearsData = ( ( ScannerVehicleProdYears )value );
		if( vehicleProductionYearsData )
		{
			inkTextRef.SetText( m_vehicleProdYearsText, vehicleProductionYearsData.GetProdYears() );
			m_isValidVehicleProdYears = true;
		}
		else
		{
			m_isValidVehicleProdYears = false;
		}
		UpdateGlobalVisibility();
	}

	protected event OnVehicleeDriveLayoutChanged( value : Variant )
	{
		var vehicleVehicleDriveLayoutData : ScannerVehicleDriveLayout;
		vehicleVehicleDriveLayoutData = ( ( ScannerVehicleDriveLayout )value );
		if( vehicleVehicleDriveLayoutData )
		{
			inkTextRef.SetLocalizedTextScript( m_vehicleDriveLayoutText, vehicleVehicleDriveLayoutData.GetDriveLayout() );
			m_isValidVehicleDriveLayout = true;
		}
		else
		{
			m_isValidVehicleDriveLayout = false;
		}
		UpdateGlobalVisibility();
	}

	protected event OnVehicleHorsepowerChanged( value : Variant )
	{
		var vehicleHorsepowerData : ScannerVehicleHorsepower;
		vehicleHorsepowerData = ( ( ScannerVehicleHorsepower )value );
		if( vehicleHorsepowerData )
		{
			inkTextRef.SetText( m_vehicleHorsepowerText, ( ( String )( vehicleHorsepowerData.GetHorsepower() ) ) );
			m_isValidVehicleHorsepower = true;
		}
		else
		{
			m_isValidVehicleHorsepower = false;
		}
		UpdateGlobalVisibility();
	}

	protected event OnVehicleMassChanged( value : Variant )
	{
		var vehicleMassData : ScannerVehicleMass;
		vehicleMassData = ( ( ScannerVehicleMass )value );
		if( vehicleMassData )
		{
			inkTextRef.SetText( m_vehicleMassText, ( ( String )( vehicleMassData.GetMass() ) ) );
			m_isValidVehicleMass = true;
		}
		else
		{
			m_isValidVehicleMass = false;
		}
		UpdateGlobalVisibility();
	}

	protected event OnVehicleStateChanged( value : Variant )
	{
		var vehicleStateData : ScannerVehicleState;
		vehicleStateData = ( ( ScannerVehicleState )value );
		if( vehicleStateData )
		{
			inkTextRef.SetLocalizedTextScript( m_vehicleStateText, vehicleStateData.GetVehicleState() );
			m_isValidVehicleState = true;
		}
		else
		{
			m_isValidVehicleState = false;
		}
		UpdateGlobalVisibility();
	}

	protected event OnVehicleInfoChanged( value : Variant )
	{
		var vehicleInfoData : ScannerVehicleInfo;
		vehicleInfoData = ( ( ScannerVehicleInfo )value );
		if( vehicleInfoData )
		{
			inkTextRef.SetLocalizedTextScript( m_vehicleInfoText, vehicleInfoData.GetVehicleInfo() );
			m_isValidVehicleInfo = true;
		}
		else
		{
			m_isValidVehicleInfo = false;
		}
		UpdateGlobalVisibility();
	}

	private function UpdateGlobalVisibility()
	{
		GetRootWidget().SetVisible( ( ( ( ( ( m_isValidVehicleName || m_isValidVehicleProdYears ) || m_isValidVehicleDriveLayout ) || m_isValidVehicleHorsepower ) || m_isValidVehicleMass ) || m_isValidVehicleState ) || m_isValidVehicleInfo );
		inkWidgetRef.SetVisible( m_vehicleNameHolder, m_isValidVehicleName );
		inkWidgetRef.SetVisible( m_vehicleProdYearsHolder, m_isValidVehicleProdYears );
		inkWidgetRef.SetVisible( m_vehicleDriveLayoutHolder, m_isValidVehicleDriveLayout );
		inkWidgetRef.SetVisible( m_vehicleHorsepowerHolder, m_isValidVehicleHorsepower );
		inkWidgetRef.SetVisible( m_vehicleMassHolder, m_isValidVehicleMass );
		inkWidgetRef.SetVisible( m_vehicleStateHolder, m_isValidVehicleState );
		inkWidgetRef.SetVisible( m_vehicleInfoHolder, m_isValidVehicleInfo );
		inkImageRef.SetVisible( m_vehicleManufacturer, m_isValidVehicleManufacturer );
	}

}

class QuickHackDescriptionGameController extends BaseChunkGameController
{
	private editable var m_subHeader : inkTextRef;
	private editable var m_tier : inkTextRef;
	private editable var m_description : inkTextRef;
	private editable var m_recompileTimer : inkTextRef;
	private editable var m_duration : inkTextRef;
	private editable var m_durationRoot : inkWidgetRef;
	private editable var m_cooldown : inkTextRef;
	private editable var m_cooldownRoot : inkWidgetRef;
	private editable var m_uploadTime : inkTextRef;
	private editable var m_uploadTimeRoot : inkWidgetRef;
	private editable var m_memoryCost : inkTextRef;
	private editable var m_memoryRawCost : inkTextRef;
	private editable var m_categoryText : inkTextRef;
	private editable var m_categoryContainer : inkWidgetRef;
	private editable var m_damageWrapper : inkWidgetRef;
	private editable var m_damageLabel : inkTextRef;
	private editable var m_damageValue : inkTextRef;
	private editable var m_healthPercentageLabel : inkTextRef;
	private editable var m_effectsList : inkCompoundRef;
	private var m_quickHackDataCallbackID : CallbackHandle;
	private var m_selectedData : QuickhackData;
	private var m_player : weak< PlayerPuppet >;
	private var m_equippedQuickHackData : EquippedQuickHackData;
	private var m_uiScriptableSystem : UIScriptableSystem;

	protected event OnInitialize()
	{
		super.OnInitialize();
		if( !( m_quickHackDataCallbackID ) )
		{
			m_quickHackDataCallbackID = GameInstance.GetBlackboardSystem( GetPlayerControlledObject().GetGame() ).Get( GetAllBlackboardDefs().UI_QuickSlotsData ).RegisterDelayedListenerVariant( GetAllBlackboardDefs().UI_QuickSlotsData.quickHackDataSelected, this, 'OnQuickHackDataChanged' );
		}
		m_player = ( ( weak< weak< PlayerPuppet > > )( GetPlayerControlledObject() ) );
		m_uiScriptableSystem = UIScriptableSystem.GetInstance( m_player.GetGame() );
		OnQuickHackDataChanged( GameInstance.GetBlackboardSystem( GetPlayerControlledObject().GetGame() ).Get( GetAllBlackboardDefs().UI_QuickSlotsData ).GetVariant( GetAllBlackboardDefs().UI_QuickSlotsData.quickHackDataSelected ) );
	}

	protected event OnUninitialize()
	{
		if( m_quickHackDataCallbackID )
		{
			GameInstance.GetBlackboardSystem( GetPlayerControlledObject().GetGame() ).Get( GetAllBlackboardDefs().UI_QuickSlotsData ).UnregisterDelayedListener( GetAllBlackboardDefs().UI_QuickSlotsData.quickHackDataSelected, m_quickHackDataCallbackID );
		}
	}

	protected event OnQuickHackDataChanged( value : Variant )
	{
		m_selectedData = ( ( QuickhackData )value );
		m_equippedQuickHackData = EquippedQuickHackData.Make( m_player );
		if( m_selectedData )
		{
			inkTextRef.SetLocalizedTextScript( m_subHeader, m_selectedData.m_title );
			SetupTier();
			SetupDuration();
			SetupMaxCooldown();
			SetupUploadTime();
			SetupMemoryCost();
			SetupCategory();
			SetupDamage();
			SetupMods();
			if( inkCompoundRef.IsVisible( m_effectsList ) )
			{
				inkTextRef.SetVisible( m_description, false );
			}
			else
			{
				inkTextRef.SetVisible( m_description, true );
				inkTextRef.SetLocalizedTextScript( m_description, m_selectedData.m_description );
			}
		}
	}

	private function SetupMods()
	{
		var i : Int32;
		var controller : ItemTooltipModController;
		var itemID : ItemID;
		var specialAbilities : array< InventoryItemAbility >;
		var size : Int32;
		itemID = m_selectedData.m_itemID;
		specialAbilities = m_equippedQuickHackData.GetAbilitiesByItemID( itemID );
		size = specialAbilities.Size();
		if( !( m_uiScriptableSystem.DEV_IsScanLongTooltipEnabled() ) )
		{
			inkCompoundRef.SetVisible( m_effectsList, false );
			return;
		}
		if( size > 0 )
		{
			while( inkCompoundRef.GetNumChildren( m_effectsList ) > size )
			{
				inkCompoundRef.RemoveChildByIndex( m_effectsList, 0 );
			}
			while( inkCompoundRef.GetNumChildren( m_effectsList ) < size )
			{
				SpawnFromLocal( inkCompoundRef.Get( m_effectsList ), 'programTooltipEffect' );
			}
			for( i = 0; i < size; i += 1 )
			{
				controller = ( ( ItemTooltipModController )( inkCompoundRef.GetWidgetByIndex( m_effectsList, i ).GetController() ) );
				controller.SetData( specialAbilities[ i ] );
			}
		}
		inkCompoundRef.SetVisible( m_effectsList, size > 0 );
	}

	private function SetupTier()
	{
		var value : Int32;
		var textParams : inkTextParams;
		value = m_selectedData.m_quality / 2;
		textParams = new inkTextParams;
		textParams.AddNumber( "VALUE", value );
		( ( inkText )( inkTextRef.Get( m_tier ) ) ).SetLocalizedTextScript( "LocKey#40895", textParams );
	}

	private function GetModifiedDuration( baseValue : Float ) : Float
	{
		var durationBonus : Float;
		var covertDurationBonus : Float;
		var controlDurationBonus : Float;
		var statsSystem : StatsSystem;
		var category : gamedataHackCategory;
		var result : Float;
		category = gamedataHackCategory.Invalid;
		statsSystem = GameInstance.GetStatsSystem( m_player.GetGame() );
		if( !( m_selectedData.m_category ) )
		{
			return baseValue;
		}
		category = m_selectedData.m_category.Type();
		result = baseValue;
		if( ( ( ( category == gamedataHackCategory.CovertHack || category == gamedataHackCategory.ControlHack ) || category == gamedataHackCategory.DeviceHack ) && PlayerDevelopmentSystem.GetData( m_player ).IsNewPerkBought( gamedataNewPerkType.Intelligence_Left_Milestone_1 ) ) && GetBlackboardSystem().GetLocalInstanced( m_player.GetEntityID(), GetAllBlackboardDefs().PlayerStateMachine ).GetBool( GetAllBlackboardDefs().PlayerStateMachine.IsControllingDevice ) )
		{
			result += ( baseValue * TDB.GetFloat( T"NewPerks.Intelligence_Left_Milestone_1.durationIncease", 0.0 ) );
		}
		if( category == gamedataHackCategory.CovertHack )
		{
			covertDurationBonus = statsSystem.GetStatValue( m_player.GetEntityID(), gamedataStatType.DurationBonusCovertQuickhack );
			result += ( baseValue * covertDurationBonus );
		}
		if( category == gamedataHackCategory.ControlHack )
		{
			controlDurationBonus = statsSystem.GetStatValue( m_player.GetEntityID(), gamedataStatType.DurationBonusControlQuickhack );
			result += ( baseValue * controlDurationBonus );
		}
		durationBonus = statsSystem.GetStatValue( m_player.GetEntityID(), gamedataStatType.DurationBonusQuickhack );
		return result + ( baseValue * durationBonus );
	}

	private function SetupDuration()
	{
		var value : Float;
		var textParams : inkTextParams;
		value = GetModifiedDuration( m_selectedData.m_duration );
		textParams = new inkTextParams;
		if( value < 0.0 )
		{
			textParams.AddLocalizedString( "value", "LocKey#49549" );
			textParams.AddString( "unit", "" );
			( ( inkText )( inkTextRef.Get( m_duration ) ) ).SetLocalizedTextScript( "LocKey#78476", textParams );
		}
		else
		{
			textParams.AddNumber( "VALUE", value );
			textParams.AddLocalizedString( "SEC", "LocKey#40730" );
			( ( inkText )( inkTextRef.Get( m_duration ) ) ).SetLocalizedTextScript( "LocKey#40736", textParams );
		}
		if( value == 0.0 )
		{
			inkTextRef.SetState( m_duration, 'Locked' );
			inkWidgetRef.SetVisible( m_durationRoot, false );
		}
		else
		{
			inkTextRef.SetState( m_duration, 'Default' );
			inkWidgetRef.SetVisible( m_durationRoot, true );
		}
	}

	private function SetupMaxCooldown()
	{
		var value : Float;
		var textParams : inkTextParams;
		value = m_selectedData.m_cooldown;
		textParams = new inkTextParams;
		textParams.AddNumber( "VALUE", value );
		textParams.AddLocalizedString( "SEC", "LocKey#40730" );
		( ( inkText )( inkTextRef.Get( m_cooldown ) ) ).SetLocalizedTextScript( "LocKey#40729", textParams );
		if( value < 0.1 )
		{
			inkTextRef.SetState( m_cooldown, 'Locked' );
			inkWidgetRef.SetVisible( m_cooldownRoot, false );
		}
		else
		{
			inkTextRef.SetState( m_cooldown, 'Default' );
			inkWidgetRef.SetVisible( m_cooldownRoot, true );
		}
	}

	private function GetModifiedUploadTime( baseValue : Float ) : Float
	{
		var queueCount : Int32;
		var firstInQueueUploadTimeDecrease : Float;
		var queueUploadTimeDecrease : Float;
		var uploadTimeDecrease : Float;
		var statsSystem : StatsSystem;
		statsSystem = GameInstance.GetStatsSystem( m_player.GetGame() );
		firstInQueueUploadTimeDecrease = statsSystem.GetStatValue( m_player.GetEntityID(), gamedataStatType.FirstHackInQueueUploadTimeDecrease );
		uploadTimeDecrease = statsSystem.GetStatValue( m_player.GetEntityID(), gamedataStatType.QuickHackUploadTimeDecrease );
		queueUploadTimeDecrease = statsSystem.GetStatValue( m_player.GetEntityID(), gamedataStatType.QuickHackQueueUploadTimeDecrease );
		queueCount = ( ( Int32 )( statsSystem.GetStatValue( m_player.GetEntityID(), gamedataStatType.QuickHackQueueCount ) ) );
		baseValue -= ( baseValue * MinF( uploadTimeDecrease, 1.0 ) );
		if( queueCount == 0 )
		{
			return baseValue - ( baseValue * MinF( firstInQueueUploadTimeDecrease + queueUploadTimeDecrease, 1.0 ) );
		}
		else
		{
			return baseValue - ( baseValue * MinF( queueUploadTimeDecrease * ( ( Float )( Min( queueCount + 1, 3 ) ) ), 1.0 ) );
		}
		return baseValue;
	}

	private function SetupUploadTime()
	{
		var value : Float;
		var textParams : inkTextParams;
		value = GetModifiedUploadTime( m_selectedData.m_uploadTime );
		textParams = new inkTextParams;
		textParams.AddNumber( "VALUE", value );
		textParams.AddLocalizedString( "SEC", "LocKey#40730" );
		( ( inkText )( inkTextRef.Get( m_uploadTime ) ) ).SetLocalizedTextScript( "LocKey#40737", textParams );
		if( value == 0.0 )
		{
			inkTextRef.SetState( m_uploadTime, 'Locked' );
			inkWidgetRef.SetVisible( m_uploadTimeRoot, false );
		}
		else
		{
			inkTextRef.SetState( m_uploadTime, 'Default' );
			inkWidgetRef.SetVisible( m_uploadTimeRoot, true );
		}
	}

	private function SetupMemoryCost()
	{
		var value : Int32;
		var textParams : inkTextParams;
		inkTextRef.SetText( m_memoryCost, IntToString( m_selectedData.m_cost ) );
		value = m_selectedData.m_costRaw;
		textParams = new inkTextParams;
		textParams.AddNumber( "VALUE", value );
		( ( inkText )( inkTextRef.Get( m_memoryRawCost ) ) ).SetLocalizedTextScript( "LocKey#40804", textParams );
	}

	private function SetupCategory()
	{
		if( m_selectedData.m_category && m_selectedData.m_category.Type() != gamedataHackCategory.NotAHack )
		{
			inkTextRef.SetText( m_categoryText, m_selectedData.m_category.LocalizedDescription() );
			inkWidgetRef.SetVisible( m_categoryContainer, true );
		}
		else
		{
			inkWidgetRef.SetVisible( m_categoryContainer, false );
		}
	}

	private function IsDamageStat( targetStat : gamedataStatType, valueStat : gamedataStatType ) : Bool
	{
		if( targetStat == gamedataStatType.Invalid )
		{
			switch( valueStat )
			{
				case gamedataStatType.BaseDamage:
				case gamedataStatType.PhysicalDamage:
				case gamedataStatType.ChemicalDamage:
				case gamedataStatType.ElectricDamage:
				case gamedataStatType.ThermalDamage:
					return true;
				default:
					return false;
			}
		}
		else
		{
			return targetStat == gamedataStatType.Health;
		}
		return false;
	}

	private function SetupDamage()
	{
		var i, j : Int32;
		var effect : DamageEffectUIEntry;
		var valueToDisplay : String;
		var isHealthPercentageStat : Bool;
		var effects : array< DamageEffectUIEntry >;
		var totalEffects : array< DamageEffectUIEntry >;
		var damageType : gamedataDamageType;
		var damageTypeRecord : Stat_Record;
		var damageTypeLocKey : String;
		inkWidgetRef.SetVisible( m_damageWrapper, false );
		inkTextRef.SetVisible( m_damageLabel, false );
		for( i = 0; i < m_selectedData.m_actionCompletionEffects.Size(); i += 1 )
		{
			if( !( InventoryDataManagerV2.ProcessQuickhackEffects( GetPlayerControlledObject(), m_selectedData.m_actionCompletionEffects[ i ].StatusEffect(), effects ) ) )
			{
				continue;
			}
			for( j = 0; j < effects.Size(); j += 1 )
			{
				totalEffects.PushBack( effects[ j ] );
			}
		}
		for( i = 0; i < totalEffects.Size(); i += 1 )
		{
			effect = totalEffects[ i ];
			if( !( IsDamageStat( effect.targetStat, effect.valueStat ) ) )
			{
				continue;
			}
			isHealthPercentageStat = effect.targetStat == gamedataStatType.Health;
			inkTextRef.SetVisible( m_healthPercentageLabel, isHealthPercentageStat );
			if( isHealthPercentageStat )
			{
				valueToDisplay = "-";
			}
			valueToDisplay += IntToString( CeilF( effect.valueToDisplay ) );
			if( isHealthPercentageStat )
			{
				valueToDisplay += "%";
			}
			if( effect.isContinuous )
			{
				valueToDisplay += ( "/" + GetLocalizedText( "UI-Quickhacks-Seconds" ) );
			}
			inkTextRef.SetText( m_damageValue, valueToDisplay );
			damageType = effect.damageType;
			if( damageType != gamedataDamageType.Invalid )
			{
				damageTypeRecord = RPGManager.GetStatRecord( UIItemsHelper.GetStatTypeByDamageType( damageType ) );
				damageTypeLocKey = UILocalizationHelper.GetStatNameLockey( damageTypeRecord );
				inkTextRef.SetVisible( m_damageLabel, true );
				inkWidgetRef.SetVisible( m_damageWrapper, true );
				inkTextRef.SetText( m_damageLabel, damageTypeLocKey );
			}
			else
			{
				inkTextRef.SetVisible( m_damageLabel, false );
			}
			break;
		}
	}

}

