struct AOEAreaSetup
{
	[ customEditor = "TweakDBGroupInheritance;DeviceAreaAttack" ]
	instanceeditable var m_areaEffect : TweakDBID;
	[ customEditor = "TweakDBGroupInheritance;InteractionBase" ]
	instanceeditable var m_actionName : TweakDBID;
	[ tooltip = "determines whether NPCs can see through the area while the effect is active. Don't forget to apply a proper visual effect which communicates this on the effector. Set to false by default." ]
	instanceeditable var m_blocksVisibility : Bool;
	default m_blocksVisibility = false;
	[ tooltip = "determines whether NPCs will try to avoid the area when it's active, so as not to walk directly into an obvious trap. Set to false by default." ]
	instanceeditable var m_isDangerous : Bool;
	default m_isDangerous = false;
	[ tooltip = "determines whether the device should automatically activate as soon as it's spawned. Set to false by default." ]
	instanceeditable var m_activateOnStartup : Bool;
	default m_activateOnStartup = false;
	[ tooltip = " if checked, effects will be local. This means that if the device gets deactivated, or an entity leaves the area, the status effects applied by the device will be removed. An example usage of this is an area with loud music playing. An AOE_ImpairedHearing effect with this option set to true will mute all the audio stims sent in the area. Set to false by default. NOTE: Please be careful while using this. There's no smart logic implemented here to prevent you from doing nonsensical things. You can remove effects that probably shouldn't be removed, eg. burning." ]
	instanceeditable var m_effectsOnlyActiveInArea : Bool;
	default m_effectsOnlyActiveInArea = false;
	[ tooltip = "determines how long the effects are active. It does not impact how long status effect (e.g. blindness) is applied on npc. This is determined by RPG for balance reasons Negative values are interpreted as infinity. Set to -1.0f by default." ]
	instanceeditable var m_duration : Float;
	default m_duration = -1.f;
	[ category = "UI" ][ customEditor = "TweakDBGroupInheritance;ActionWidgetDefinition" ]
	instanceeditable editable var m_actionWidgetRecord : TweakDBID;
	[ category = "UI" ][ customEditor = "TweakDBGroupInheritance;DeviceWidgetDefinition" ]
	instanceeditable editable var m_deviceWidgetRecord : TweakDBID;
	[ category = "UI" ][ customEditor = "TweakDBGroupInheritance;ThumbnailWidgetDefinition" ]
	instanceeditable editable var m_thumbnailWidgetRecord : TweakDBID;
}

class AOEAreaController extends MasterController
{

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

}

class AOEAreaControllerPS extends MasterControllerPS
{
	default m_deviceName = "LocKey#188";
	default m_tweakDBRecord = T"Devices.AOE_Area";
	default m_tweakDBDescriptionRecord = T"device_descriptions.AOE_Area";
	default m_revealDevicesGrid = true;
	default m_drawGridLink = false;
	private instanceeditable persistent var m_AOEAreaSetup : AOEAreaSetup;

	public function GetActionName() : CName
	{
		return StringToName( TweakDBInterface.GetInteractionBaseRecord( m_AOEAreaSetup.m_actionName ).Name() );
	}

	public function GetAreaEffect() : TweakDBID
	{
		return m_AOEAreaSetup.m_areaEffect;
	}

	public function GetEffectDuration() : Float
	{
		return m_AOEAreaSetup.m_duration;
	}

	public function BlocksVisibility() : Bool
	{
		return m_AOEAreaSetup.m_blocksVisibility;
	}

	public function IsDangerous() : Bool
	{
		return m_AOEAreaSetup.m_isDangerous;
	}

	public function EffectsOnlyActiveInArea() : Bool
	{
		return m_AOEAreaSetup.m_effectsOnlyActiveInArea;
	}

	public override function GetQuestActions( out outActions : array< DeviceAction >, const context : ref< GetActionsContext > )
	{
		outActions.PushBack( ActionActivateDevice() );
		outActions.PushBack( ActionDeactivateDevice() );
		super.GetQuestActions( outActions, context );
	}

	protected override function ActionDeactivateDevice() : DeactivateDevice
	{
		var action : DeactivateDevice;
		action = super.ActionDeactivateDevice();
		action.SetProperties( 'DeactivateDevice' );
		if( TDBID.IsValid( m_AOEAreaSetup.m_actionWidgetRecord ) )
		{
			action.CreateActionWidgetPackage( m_AOEAreaSetup.m_actionWidgetRecord );
		}
		else
		{
			action.CreateActionWidgetPackage( T"DevicesUIDefinitions.VentilationSystemActionWidget" );
		}
		return action;
	}

	public override function GetActions( out outActions : array< DeviceAction >, context : GetActionsContext ) : Bool
	{
		super.GetActions( outActions, context );
		if( !( IsAreaActive() ) )
		{
			outActions.PushBack( ActionActivateDevice() );
		}
		else
		{
			outActions.PushBack( ActionDeactivateDevice() );
		}
		SetActionIllegality( outActions, m_illegalActions.regularActions );
		return false;
	}

	protected override function GameAttached()
	{
		var activateAction : ActivateDevice;
		if( m_AOEAreaSetup.m_activateOnStartup )
		{
			activateAction = ActionActivateDevice();
			GetPersistencySystem().QueuePSDeviceEvent( activateAction );
		}
	}

	protected export override function OnActivateDevice( evt : ActivateDevice ) : EntityNotificationType
	{
		super.OnActivateDevice( evt );
		ToggleEffectors();
		if( m_AOEAreaSetup.m_duration >= 0.0 )
		{
			QueueDeactivateAction( m_AOEAreaSetup.m_duration );
		}
		return EntityNotificationType.SendThisEventToEntity;
	}

	protected override function OnActionForceResetDevice( evt : ActionForceResetDevice ) : EntityNotificationType
	{
		GetPersistencySystem().QueuePSDeviceEvent( ActionActivateDevice() );
		return EntityNotificationType.DoNotNotifyEntity;
	}

	private function QueueDeactivateAction( delayTime : Float )
	{
		var deactivateAction : DeactivateDevice;
		deactivateAction = ActionDeactivateDevice();
		GameInstance.GetDelaySystem( GetGameInstance() ).DelayPSEvent( GetID(), 'AOEAreaControllerPS', deactivateAction, delayTime );
	}

	protected export override function OnDeactivateDevice( evt : DeactivateDevice ) : EntityNotificationType
	{
		super.OnDeactivateDevice( evt );
		ToggleEffectors();
		return EntityNotificationType.SendThisEventToEntity;
	}

	private function ToggleEffectors()
	{
		var i : Int32;
		var action : ToggleAOEEffect;
		var entityID : EntityID;
		var devices : array< DeviceComponentPS >;
		entityID = PersistentID.ExtractEntityID( GetID() );
		GameInstance.GetDeviceSystem( GetGameInstance() ).GetChildren( entityID, devices );
		for( i = 0; i < devices.Size(); i += 1 )
		{
			action = ( ( ToggleAOEEffect )( ( ( ScriptableDeviceComponentPS )( devices[ i ] ) ).GetActionByName( 'ToggleAOEEffect' ) ) );
			if( action )
			{
				GetPersistencySystem().QueuePSDeviceEvent( action );
			}
		}
	}

	public quest const function IsAreaActive() : Bool
	{
		return GetActivationState() == EActivationState.ACTIVATED;
	}

	protected override function GetInkWidgetTweakDBID( const context : ref< GetActionsContext > ) : TweakDBID
	{
		if( TDBID.IsValid( m_AOEAreaSetup.m_deviceWidgetRecord ) )
		{
			return m_AOEAreaSetup.m_deviceWidgetRecord;
		}
		else
		{
			return T"DevicesUIDefinitions.VentilationSystemDeviceWidget";
		}
	}

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

}

