import class DistrictEnteredEvent extends ScriptableSystemRequest
{
	import editable var entered : Bool;
	import editable var sendNewLocationNotification : Bool;
	[ customEditor = "TweakDBGroupInheritance;District" ]
	import editable var district : TweakDBID;
}

class District extends IScriptable
{
	private var m_districtID : TweakDBID;
	private var m_presetID : TweakDBID;
	private var m_districtRecord : District_Record;

	public const function GetDistrictID() : TweakDBID
	{
		return m_districtID;
	}

	public const function GetDistrictRecord() : District_Record
	{
		return m_districtRecord;
	}

	public const function GetPresetID() : TweakDBID
	{
		return m_presetID;
	}

	public const function GetGunshotStimRange() : Float
	{
		return m_districtRecord.GunShotStimRange();
	}

	public const function GetCrimeMultiplier() : Float
	{
		return m_districtRecord.CrimeMultiplier();
	}

	public const function GetExplosiveDeviceStimRange() : Float
	{
		return m_districtRecord.ExplosiveDeviceStimRangeMultiplier();
	}

	public const function GetRadioEntryName() : CName
	{
		var entry : CName;
		var record : weak< District_Record >;
		record = m_districtRecord;
		entry = record.PoliceRadioSceneEntryPoint();
		if( IsNameValid( entry ) )
		{
			return entry;
		}
		record = record.ParentDistrict();
		if( !( record ) )
		{
			return entry;
		}
		entry = record.PoliceRadioSceneEntryPoint();
		if( IsNameValid( entry ) )
		{
			return entry;
		}
		record = record.ParentDistrict();
		if( !( record ) )
		{
			return entry;
		}
		entry = record.PoliceRadioSceneEntryPoint();
		return entry;
	}

	public const function IsDogTown() : Bool
	{
		if( m_districtRecord )
		{
			if( m_districtRecord.Type() == gamedataDistrict.Dogtown )
			{
				return true;
			}
			if( m_districtRecord.ParentDistrictHandle() )
			{
				return m_districtRecord.ParentDistrictHandle().Type() == gamedataDistrict.Dogtown;
			}
		}
		return false;
	}

	public const function IsBadlands() : Bool
	{
		if( m_districtRecord )
		{
			if( m_districtRecord.Type() == gamedataDistrict.Badlands )
			{
				return true;
			}
			if( m_districtRecord.ParentDistrictHandle() )
			{
				return m_districtRecord.ParentDistrictHandle().Type() == gamedataDistrict.Badlands;
			}
		}
		return false;
	}

	public function Initialize( district : TweakDBID )
	{
		m_districtID = district;
		m_districtRecord = TweakDBInterface.GetDistrictRecord( m_districtID );
		if( !( m_districtRecord ) )
		{
			m_presetID = T"PreventionData.NCPD";
			return;
		}
		if( TDBID.IsValid( m_districtRecord.PreventionPreset().GetID() ) )
		{
			m_presetID = m_districtRecord.PreventionPreset().GetID();
		}
		else if( TDBID.IsValid( m_districtRecord.ParentDistrict().PreventionPreset().GetID() ) )
		{
			m_presetID = m_districtRecord.ParentDistrict().PreventionPreset().GetID();
		}
		else
		{
			m_presetID = T"PreventionData.NCPD";
		}
	}

}

class DistrictManager extends IScriptable
{
	private var m_system : weak< PreventionSystem >;
	private var m_stack : array< District >;
	private persistent var m_visitedDistricts : array< TweakDBID >;

	public function Initialize( system : PreventionSystem )
	{
		m_system = system;
	}

	public function Update( evt : DistrictEnteredEvent )
	{
		ManageDistrictStack( evt );
	}

	private function ManageDistrictStack( request : DistrictEnteredEvent )
	{
		if( request.entered )
		{
			PushDistrict( request );
		}
		else
		{
			PopDistrict( request );
		}
		Refresh();
		NotifySystem();
	}

	private function PushDistrict( request : DistrictEnteredEvent )
	{
		var i : Int32;
		var d : District;
		var playerNotification : PlayerEnteredNewDistrictEvent;
		if( !( TDBID.IsValid( request.district ) ) )
		{
			return;
		}
		for( i = 0; i < m_stack.Size(); i += 1 )
		{
			if( m_stack[ i ].GetDistrictID() == request.district )
			{
				m_stack.Erase( i );
				break;
			}
		}
		d = new District;
		d.Initialize( request.district );
		m_stack.PushBack( d );
		playerNotification = new PlayerEnteredNewDistrictEvent;
		playerNotification.gunshotRange = d.GetGunshotStimRange();
		playerNotification.explosionRange = d.GetExplosiveDeviceStimRange();
		GameInstance.GetPlayerSystem( m_system.GetGame() ).GetLocalPlayerMainGameObject().QueueEvent( playerNotification );
	}

	private function PopDistrict( request : DistrictEnteredEvent )
	{
		var i : Int32;
		for( i = m_stack.Size() - 1; i >= 0; i -= 1 )
		{
			if( m_stack[ i ].GetDistrictID() == request.district )
			{
				m_stack.Erase( i );
				return;
			}
		}
	}

	private function Refresh()
	{
		var d : weak< District >;
		var isNew : Bool;
		var blackboard : IBlackboard;
		var districtRecord : weak< District_Record >;
		d = GetCurrentDistrict();
		if( !( d ) )
		{
			return;
		}
		if( !( m_visitedDistricts.Contains( d.GetDistrictID() ) ) )
		{
			m_visitedDistricts.PushBack( d.GetDistrictID() );
			isNew = true;
		}
		districtRecord = d.GetDistrictRecord();
		blackboard = GameInstance.GetBlackboardSystem( m_system.GetGame() ).Get( GetAllBlackboardDefs().UI_Map );
		if( blackboard )
		{
			blackboard.SetString( GetAllBlackboardDefs().UI_Map.currentLocationEnumName, districtRecord.EnumName(), true );
			blackboard.SetString( GetAllBlackboardDefs().UI_Map.currentLocation, districtRecord.LocalizedName(), true );
			blackboard.SetBool( GetAllBlackboardDefs().UI_Map.newLocationDiscovered, isNew, true );
		}
		GameInstance.GetTelemetrySystem( m_system.GetGame() ).LogDistrictChanged( districtRecord.EnumName(), isNew );
	}

	private function NotifySystem()
	{
		var request : RefreshDistrictRequest;
		request = new RefreshDistrictRequest;
		request.preventionPreset = TweakDBInterface.GetDistrictPreventionDataRecord( GetCurrentDistrict().GetPresetID() );
		m_system.QueueRequest( request );
	}

	public const function GetCurrentDistrict() : weak< District >
	{
		var size : Int32;
		size = m_stack.Size();
		if( size == 0 )
		{
			return NULL;
		}
		return m_stack[ size - 1 ];
	}

}

