import class ProgressionViewData extends GenericNotificationViewData
{
	import var expValue : Int32;
	import var expProgress : Float;
	import var delta : Int32;
	import var notificationColorTheme : CName;
	import var type : gamedataProficiencyType;
	import var currentLevel : Int32;
	import var isLevelMaxed : Bool;

	public export override function CanMerge( data : GenericNotificationViewData ) : Bool
	{
		var newData : ProgressionViewData;
		newData = ( ( ProgressionViewData )( data ) );
		if( newData && newData.type == type )
		{
			expProgress = newData.expProgress;
			expValue = newData.expValue;
			delta += newData.delta;
			currentLevel = newData.currentLevel;
			isLevelMaxed = newData.isLevelMaxed;
			return true;
		}
		return false;
	}

}

class ProgressionWidgetGameController extends gameuiGenericNotificationGameController
{
	private editable var m_duration : Float;
	default m_duration = 3.0f;
	private var m_playerDevelopmentSystem : PlayerDevelopmentSystem;
	private var m_combatModePSM : gamePSMCombat;
	private var m_combatModeListener : CallbackHandle;
	private var m_playerObject : weak< GameObject >;
	private var m_gameInstance : GameInstance;

	public override function GetShouldSaveState() : Bool
	{
		return true;
	}

	public override function GetID() : Int32
	{
		return ( ( Int32 )( GenericNotificationType.ProgressionNotification ) );
	}

	protected event OnPlayerAttach( playerPuppet : GameObject )
	{
		var controlledPuppetRecordID : TweakDBID;
		var controlledPuppet : weak< gamePuppetBase >;
		m_playerObject = ( ( GameObject )( GetPlayerControlledObject() ) );
		m_playerDevelopmentSystem = ( ( PlayerDevelopmentSystem )( GameInstance.GetScriptableSystemsContainer( m_playerObject.GetGame() ).Get( 'PlayerDevelopmentSystem' ) ) );
		RegisterPSMListeners( m_playerObject );
		m_gameInstance = GetPlayerControlledObject().GetGame();
		controlledPuppet = ( ( gamePuppetBase )( GetPlayer( m_gameInstance ) ) );
		if( controlledPuppet != NULL )
		{
			controlledPuppetRecordID = controlledPuppet.GetRecordID();
			if( controlledPuppetRecordID == T"Character.johnny_replacer" )
			{
				GetRootWidget().SetVisible( false );
			}
			else
			{
				GetRootWidget().SetVisible( true );
			}
		}
		else
		{
			GetRootWidget().SetVisible( true );
		}
	}

	protected event OnPlayerDetach( playerGameObject : GameObject )
	{
		UnregisterPSMListeners( m_playerObject );
	}

	protected function RegisterPSMListeners( playerObject : GameObject )
	{
		var playerStateMachineBlackboard : IBlackboard;
		var playerSMDef : PlayerStateMachineDef;
		playerSMDef = GetAllBlackboardDefs().PlayerStateMachine;
		if( playerSMDef )
		{
			playerStateMachineBlackboard = GetPSMBlackboard( playerObject );
			if( playerStateMachineBlackboard )
			{
				m_combatModeListener = playerStateMachineBlackboard.RegisterListenerInt( playerSMDef.Combat, this, 'OnCombatStateChanged' );
			}
		}
	}

	protected function UnregisterPSMListeners( playerObject : GameObject )
	{
		var playerStateMachineBlackboard : IBlackboard;
		var playerSMDef : PlayerStateMachineDef;
		playerSMDef = GetAllBlackboardDefs().PlayerStateMachine;
		if( playerSMDef )
		{
			playerStateMachineBlackboard = GetPSMBlackboard( playerObject );
			if( playerStateMachineBlackboard )
			{
				playerStateMachineBlackboard.UnregisterDelayedListener( playerSMDef.Combat, m_combatModeListener );
			}
		}
	}

	protected event OnCombatStateChanged( value : Int32 )
	{
		m_combatModePSM = ( ( gamePSMCombat )( value ) );
		if( m_combatModePSM == gamePSMCombat.OutOfCombat || m_combatModePSM == gamePSMCombat.Default )
		{
			SetNotificationPaused( false );
			GetRootWidget().SetVisible( true );
		}
		else
		{
			SetNotificationPaused( true );
			GetRootWidget().SetVisible( false );
		}
	}

	protected event OnCharacterProficiencyUpdated( evt : ProficiencyProgressEvent )
	{
		switch( evt.type )
		{
			case gamedataProficiencyType.StreetCred:
				AddToNotificationQueue( evt.expValue, evt.remainingXP, evt.delta, 'StreetCred', "LocKey#1210", evt.type, evt.currentLevel, evt.isLevelMaxed );
			break;
			case gamedataProficiencyType.Assault:
				AddToNotificationQueue( evt.expValue, evt.remainingXP, evt.delta, 'Skills', "LocKey#22315", evt.type, evt.currentLevel, evt.isLevelMaxed );
			break;
			case gamedataProficiencyType.Athletics:
				AddToNotificationQueue( evt.expValue, evt.remainingXP, evt.delta, 'Skills', "LocKey#22299", evt.type, evt.currentLevel, evt.isLevelMaxed );
			break;
			case gamedataProficiencyType.Brawling:
				AddToNotificationQueue( evt.expValue, evt.remainingXP, evt.delta, 'Skills', "LocKey#22306", evt.type, evt.currentLevel, evt.isLevelMaxed );
			break;
			case gamedataProficiencyType.ColdBlood:
				AddToNotificationQueue( evt.expValue, evt.remainingXP, evt.delta, 'Skills', "LocKey#22302", evt.type, evt.currentLevel, evt.isLevelMaxed );
			break;
			case gamedataProficiencyType.CombatHacking:
				AddToNotificationQueue( evt.expValue, evt.remainingXP, evt.delta, 'Skills', "LocKey#22332", evt.type, evt.currentLevel, evt.isLevelMaxed );
			break;
			case gamedataProficiencyType.Engineering:
				AddToNotificationQueue( evt.expValue, evt.remainingXP, evt.delta, 'Skills', "LocKey#22326", evt.type, evt.currentLevel, evt.isLevelMaxed );
			break;
			case gamedataProficiencyType.Gunslinger:
				AddToNotificationQueue( evt.expValue, evt.remainingXP, evt.delta, 'Skills', "LocKey#22311", evt.type, evt.currentLevel, evt.isLevelMaxed );
			break;
			case gamedataProficiencyType.Kenjutsu:
				AddToNotificationQueue( evt.expValue, evt.remainingXP, evt.delta, 'Skills', "LocKey#22318", evt.type, evt.currentLevel, evt.isLevelMaxed );
			break;
			case gamedataProficiencyType.Stealth:
				AddToNotificationQueue( evt.expValue, evt.remainingXP, evt.delta, 'Skills', "LocKey#22324", evt.type, evt.currentLevel, evt.isLevelMaxed );
			break;
			case gamedataProficiencyType.Demolition:
				AddToNotificationQueue( evt.expValue, evt.remainingXP, evt.delta, 'Skills', "LocKey#22320", evt.type, evt.currentLevel, evt.isLevelMaxed );
			break;
			case gamedataProficiencyType.Crafting:
				AddToNotificationQueue( evt.expValue, evt.remainingXP, evt.delta, 'Skills', "LocKey#22328", evt.type, evt.currentLevel, evt.isLevelMaxed );
			break;
			case gamedataProficiencyType.Hacking:
				AddToNotificationQueue( evt.expValue, evt.remainingXP, evt.delta, 'Skills', "LocKey#22330", evt.type, evt.currentLevel, evt.isLevelMaxed );
			break;
			case gamedataProficiencyType.StrengthSkill:
				AddToNotificationQueue( evt.expValue, evt.remainingXP, evt.delta, 'Skills', "LocKey#92105", evt.type, evt.currentLevel, evt.isLevelMaxed );
			break;
			case gamedataProficiencyType.ReflexesSkill:
				AddToNotificationQueue( evt.expValue, evt.remainingXP, evt.delta, 'Skills', "LocKey#92106", evt.type, evt.currentLevel, evt.isLevelMaxed );
			break;
			case gamedataProficiencyType.TechnicalAbilitySkill:
				AddToNotificationQueue( evt.expValue, evt.remainingXP, evt.delta, 'Skills', "LocKey#92108", evt.type, evt.currentLevel, evt.isLevelMaxed );
			break;
			case gamedataProficiencyType.IntelligenceSkill:
				AddToNotificationQueue( evt.expValue, evt.remainingXP, evt.delta, 'Skills', "LocKey#92107", evt.type, evt.currentLevel, evt.isLevelMaxed );
			break;
			case gamedataProficiencyType.CoolSkill:
				AddToNotificationQueue( evt.expValue, evt.remainingXP, evt.delta, 'Skills', "LocKey#92109", evt.type, evt.currentLevel, evt.isLevelMaxed );
			break;
		}
	}

	public function AddToNotificationQueue( value : Int32, remainingPointsToLevelUp : Int32, delta : Int32, notificationColorTheme : CName, const notificationName : ref< String >, type : gamedataProficiencyType, currentLevel : Int32, isLevelMaxed : Bool )
	{
		var progress : Float;
		var userData : ProgressionViewData;
		var notificationData : gameuiGenericNotificationData;
		var sum : Int32;
		sum = remainingPointsToLevelUp + value;
		notificationData.time = m_duration;
		progress = ( ( Float )( value ) ) / ( ( Float )( sum ) );
		if( progress == 0.0 )
		{
			progress = ( ( Float )( sum ) );
		}
		notificationData.widgetLibraryItemName = 'progression';
		userData = new ProgressionViewData;
		userData.expProgress = progress;
		userData.expValue = value;
		userData.notificationColorTheme = notificationColorTheme;
		userData.title = notificationName;
		userData.delta = delta;
		userData.type = type;
		userData.currentLevel = currentLevel;
		userData.isLevelMaxed = isLevelMaxed;
		notificationData.notificationData = userData;
		AddNewNotificationData( notificationData );
	}

}

class ProgressionNotification extends GenericNotificationController
{
	private var progression_data : ProgressionViewData;
	private editable var m_expBar : inkWidgetRef;
	private editable var m_expText : inkTextRef;
	private editable var m_barFG : inkWidgetRef;
	private editable var m_barBG : inkWidgetRef;
	private editable var m_root : inkWidgetRef;
	private editable var m_currentLevel : inkTextRef;
	private editable var m_nextLevel : inkTextRef;
	private var m_expBarWidthSize : Float;
	private var m_expBarHeightSize : Float;
	private var m_animationProxy : inkAnimProxy;
	private var m_barAnimationProxy : inkAnimProxy;

	public export override function SetNotificationData( notificationData : GenericNotificationViewData )
	{
		var barStartSize : Vector2;
		var barEndSize : Vector2;
		m_expBarWidthSize = inkWidgetRef.GetWidth( m_expBar );
		m_expBarHeightSize = inkWidgetRef.GetHeight( m_expBar );
		progression_data = ( ( ProgressionViewData )( notificationData ) );
		inkTextRef.SetText( m_titleRef, progression_data.title );
		inkWidgetRef.SetState( m_root, progression_data.notificationColorTheme );
		barStartSize = Vector2( AbsF( ( progression_data.expProgress * m_expBarWidthSize ) - ( ( Float )( progression_data.delta ) ) ), m_expBarHeightSize );
		barEndSize = Vector2( progression_data.expProgress * m_expBarWidthSize, m_expBarHeightSize );
		inkTextRef.SetText( m_expText, IntToString( progression_data.delta ) );
		inkTextRef.SetText( m_currentLevel, IntToString( progression_data.currentLevel ) );
		if( progression_data.isLevelMaxed )
		{
			inkTextRef.SetText( m_nextLevel, "LocKey#42198" );
		}
		else
		{
			inkTextRef.SetText( m_nextLevel, IntToString( progression_data.currentLevel + 1 ) );
		}
		if( barStartSize.X > barEndSize.X )
		{
			barStartSize.X = barStartSize.X - barStartSize.X;
		}
		PlayAnim( 'intro' );
		GameInstance.GetAudioSystem( GetPlayerControlledObject().GetGame() ).Play( 'ui_menu_perk_level_up' );
		BarProgressAnim( m_expBar, barStartSize, barEndSize );
	}

	public function BarProgressAnim( animatingObject : inkWidgetRef, barStartSize : Vector2, barEndSize : Vector2 )
	{
		var barProgress : inkAnimDef;
		var sizeInterpolator : inkAnimSize;
		barProgress = new inkAnimDef;
		sizeInterpolator = new inkAnimSize;
		sizeInterpolator.SetDuration( 1.5 );
		sizeInterpolator.SetStartSize( barStartSize );
		sizeInterpolator.SetEndSize( barEndSize );
		sizeInterpolator.SetType( inkanimInterpolationType.Quintic );
		sizeInterpolator.SetMode( inkanimInterpolationMode.EasyInOut );
		barProgress.AddInterpolator( sizeInterpolator );
		m_barAnimationProxy = inkWidgetRef.PlayAnimation( animatingObject, barProgress );
		m_barAnimationProxy.RegisterToCallback( inkanimEventType.OnFinish, this, 'OnBarAnimationFinished' );
	}

	public function PlayAnim( animName : CName, optional callBack : CName )
	{
		if( m_animationProxy && m_animationProxy.IsPlaying() )
		{
			m_animationProxy.Stop();
		}
		m_animationProxy = PlayLibraryAnimation( animName );
	}

	protected event OnBarAnimationFinished( anim : inkAnimProxy )
	{
		PlayAnim( 'outro' );
	}

}

class ProficiencyProgressEvent extends Event
{
	var type : gamedataProficiencyType;
	var expValue : Int32;
	var remainingXP : Int32;
	var delta : Int32;
	var currentLevel : Int32;
	var isLevelMaxed : Bool;
}

class BountyCompletionEvent extends Event
{
	var streetCredAwarded : Int32;
	var moneyAwarded : Int32;
}

