class VentilationArea extends InteractiveMasterDevice
{
	default m_controllerTypeName = 'VentilationAreaController';
	protected instanceeditable var m_areaComponent : TriggerComponent;
	protected instanceeditable var m_RestartGameEffectOnAttach : Bool;
	default m_RestartGameEffectOnAttach = false;
	protected instanceeditable var m_AttackRecord : String;
	default m_AttackRecord = "Attacks.FragGrenade";
	private editable var m_gameEffectRef : EffectRef;
	private var m_gameEffect : EffectInstance;
	private var m_highLightActive : Bool;

	protected event OnRequestComponents( ri : EntityRequestComponentsInterface )
	{
		super.OnRequestComponents( ri );
		EntityRequestComponentsInterface.RequestComponent( ri, 'area', 'TriggerComponent', false );
	}

	protected event OnTakeControl( ri : EntityResolveComponentsInterface )
	{
		super.OnTakeControl( ri );
		m_areaComponent = ( ( TriggerComponent )( EntityResolveComponentsInterface.GetComponent( ri, 'area' ) ) );
		m_controller = ( ( VentilationAreaController )( EntityResolveComponentsInterface.GetComponent( ri, 'controller' ) ) );
	}

	protected event OnGameAttached()
	{
		super.OnGameAttached();
		if( GetDevicePS().IsAreaActive() && m_RestartGameEffectOnAttach )
		{
			PlayGameEffect();
		}
	}

	protected event OnDetach()
	{
		super.OnDetach();
		StopGameEffect();
	}

	private const override function GetController() : VentilationAreaController
	{
		return ( ( VentilationAreaController )( m_controller ) );
	}

	public const override function GetDevicePS() : VentilationAreaControllerPS
	{
		return GetController().GetPS();
	}

	protected event OnActivateDevice( evt : ActivateDevice )
	{
		PlayGameEffect();
	}

	protected event OnRevealDeviceRequest( evt : RevealDeviceRequest )
	{
		super.OnRevealDeviceRequest( evt );
		if( !( GetDevicePS().ShouldRevealDevicesGrid() ) )
		{
			return true;
		}
		ToggleHighlightOnTargets( evt.shouldReveal );
	}

	private function ToggleHighlightOnTargets( toogle : Bool )
	{
		var i : Int32;
		var entities : array< Entity >;
		entities = GetEntitiesInArea();
		m_highLightActive = toogle;
		for( i = 0; i < entities.Size(); i += 1 )
		{
			if( ( ( NPCPuppet )( entities[ i ] ) ) != NULL )
			{
				ToggleHighlightOnSingleTarget( toogle, entities[ i ].GetEntityID() );
			}
		}
	}

	private function ToggleHighlightOnSingleTarget( toogle : Bool, id : EntityID )
	{
		var evt : ForceVisionApperanceEvent;
		var highlight : FocusForcedHighlightData;
		highlight = CreateHighlight( EFocusForcedHighlightType.DISTRACTION );
		evt = new ForceVisionApperanceEvent;
		evt.apply = toogle;
		evt.forcedHighlight = highlight;
		QueueEventForEntityID( id, evt );
	}

	private function CreateHighlight( highlightType : EFocusForcedHighlightType ) : FocusForcedHighlightData
	{
		var highlight : FocusForcedHighlightData;
		highlight = new FocusForcedHighlightData;
		highlight.sourceID = GetEntityID();
		highlight.sourceName = GetClassName();
		highlight.highlightType = highlightType;
		highlight.inTransitionTime = 0.0;
		highlight.outTransitionTime = 0.0;
		highlight.priority = EPriority.VeryHigh;
		return highlight;
	}

	private function PlayGameEffect()
	{
		var explosionAttack : Attack_GameEffect;
		var attackContext : AttackInitContext;
		var hitFlags : array< hitFlag >;
		var statMods : array< gameStatModifierData >;
		if( !( m_gameEffect ) )
		{
			m_gameEffect = GameInstance.GetGameEffectSystem( GetGame() ).CreateEffect( m_gameEffectRef, GameInstance.GetPlayerSystem( GetGame() ).GetLocalPlayerMainGameObject(), this );
			attackContext.record = TweakDBInterface.GetAttackRecord( TDBID.Create( m_AttackRecord ) );
			attackContext.instigator = GetPlayer( GetGame() );
			attackContext.source = this;
			explosionAttack = ( ( Attack_GameEffect )( IAttack.Create( attackContext ) ) );
			explosionAttack.GetStatModList( statMods );
			hitFlags.PushBack( hitFlag.FriendlyFire );
			EffectData.SetVector( m_gameEffect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.position, this.GetWorldPosition() );
			EffectData.SetVariant( m_gameEffect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.flags, hitFlags );
			EffectData.SetVariant( m_gameEffect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.attack, ( ( IAttack )( explosionAttack ) ) );
			EffectData.SetVariant( m_gameEffect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.attackStatModList, statMods );
		}
		switch( GetDevicePS().GetAreaEffect() )
		{
			case ETrapEffects.SmokeScreen:
				ApplyStatusEffect( "BaseStatusEffect.SmokeScreen" );
			break;
			case ETrapEffects.Explosion:
				m_gameEffect.Run();
			break;
			case ETrapEffects.SmokeScreen:
				ApplyStatusEffect( "BaseStatusEffect.SmokeScreen" );
			break;
			case ETrapEffects.Bleeding:
				ApplyStatusEffect( "BaseStatusEffect.Bleeding" );
			break;
			case ETrapEffects.Burning:
				ApplyStatusEffect( "BaseStatusEffect.Burning" );
			break;
			case ETrapEffects.Blind:
				ApplyStatusEffect( "BaseStatusEffect.Blind" );
			break;
			case ETrapEffects.Stun:
				ApplyStatusEffect( "BaseStatusEffect.Stun" );
			break;
		}
	}

	private function StopGameEffect()
	{
		if( m_gameEffect )
		{
			m_gameEffect.Terminate();
			m_gameEffect = NULL;
		}
	}

	public const function GetEntitiesInArea() : array< Entity >
	{
		return m_areaComponent.GetOverlappingEntities();
	}

	protected function ApplyStatusEffect( const effectTDBID : ref< String > )
	{
		var statusEffectID : TweakDBID;
		var i : Int32;
		var entities : array< Entity >;
		statusEffectID = TDBID.Create( effectTDBID );
		entities = GetEntitiesInArea();
		for( i = 0; i < entities.Size(); i += 1 )
		{
			GameInstance.GetStatusEffectSystem( GetGame() ).ApplyStatusEffect( entities[ i ].GetEntityID(), statusEffectID );
		}
	}

	protected event OnAreaEnter( evt : AreaEnteredEvent )
	{
		var activator : weak< NPCPuppet >;
		super.OnAreaEnter( evt );
		activator = ( ( NPCPuppet )( EntityGameInterface.GetEntity( evt.activator ) ) );
		if( ( activator != NULL ) && m_highLightActive )
		{
			ToggleHighlightOnSingleTarget( true, activator.GetEntityID() );
		}
	}

	protected event OnAreaExit( evt : AreaExitedEvent )
	{
		var activator : weak< NPCPuppet >;
		super.OnAreaExit( evt );
		activator = ( ( NPCPuppet )( EntityGameInterface.GetEntity( evt.activator ) ) );
		if( ( activator != NULL ) && m_highLightActive )
		{
			ToggleHighlightOnSingleTarget( false, activator.GetEntityID() );
		}
	}

	public const override function GetDefaultHighlight() : FocusForcedHighlightData
	{
		return NULL;
	}

	public override function GetStimTarget() : GameObject
	{
		var children : array< DeviceComponentPS >;
		var entity : weak< Entity >;
		var i : Int32;
		GetDevicePS().GetChildren( children );
		for( i = 0; i <= children.Size(); i += 1 )
		{
			if( children[ i ].GetDeviceName() == "ActivatedDevice" )
			{
				entity = children[ i ].GetOwnerEntityWeak();
				return ( ( GameObject )( entity ) );
			}
		}
		return this;
	}

	public override function GetDistractionControllerSource( optional effectData : AreaEffectData ) : Entity
	{
		var ancestors : array< DeviceComponentPS >;
		var i : Int32;
		GetDevicePS().GetAncestors( ancestors );
		for( i = 0; i <= ancestors.Size(); i += 1 )
		{
			if( ancestors[ i ].GetDeviceName() == "Activator" )
			{
				return ancestors[ i ].GetOwnerEntityWeak();
			}
		}
		return this;
	}

}

class EffectObjectProvider_VentilationAreaEntities extends EffectObjectProvider_Scripted
{

	public function Process( ctx : EffectScriptContext, providerCtx : EffectProviderScriptContext )
	{
		var i : Int32;
		var entities : array< Entity >;
		entities = ( ( VentilationArea )( EffectScriptContext.GetWeapon( ctx ) ) ).GetEntitiesInArea();
		for( i = 0; i < entities.Size(); i += 1 )
		{
			EffectProviderScriptContext.AddTarget( ctx, providerCtx, entities[ i ] );
		}
	}

}

