enum TweakWeaponPose
{
	Nothing = 0,
	Position = 1,
	Rotation = 2,
}

class WeaponPositionComponent extends ScriptableComponent
{
	private var m_playerPuppet : weak< PlayerPuppet >;
	private var m_tweakPoseState : TweakWeaponPose;
	private var m_tweakPosition : Bool;
	private var m_tweakRotation : Bool;
	private var m_fineTuneWeaponPose : Bool;
	private var m_positionSensitivity : Float;
	private var m_positionSensitivityFineTuning : Float;
	private var m_rotationSensitivity : Float;
	private var m_rotationSensitivityFineTuning : Float;
	private var m_visionSwitch : Bool;
	private var m_visSys : VisionModeSystem;

	private function GetBlackboardIntVariable( id : BlackboardID_Int ) : Int32
	{
		var blackboardSystem : BlackboardSystem;
		var blackboard : IBlackboard;
		blackboardSystem = GameInstance.GetBlackboardSystem( GetOwner().GetGame() );
		blackboard = blackboardSystem.GetLocalInstanced( m_playerPuppet.GetEntityID(), GetAllBlackboardDefs().PlayerStateMachine );
		return blackboard.GetInt( id );
	}

	private function SetBlackboardIntVariable( id : BlackboardID_Int, value : Int32 )
	{
		var blackboardSystem : BlackboardSystem;
		var blackboard : IBlackboard;
		blackboardSystem = GameInstance.GetBlackboardSystem( GetOwner().GetGame() );
		blackboard = blackboardSystem.GetLocalInstanced( m_playerPuppet.GetEntityID(), GetAllBlackboardDefs().PlayerStateMachine );
		return blackboard.SetInt( id, value );
	}

	private function GetBlackboardBoolVariable( id : BlackboardID_Bool ) : Bool
	{
		var blackboardSystem : BlackboardSystem;
		var blackboard : IBlackboard;
		blackboardSystem = GameInstance.GetBlackboardSystem( GetOwner().GetGame() );
		blackboard = blackboardSystem.GetLocalInstanced( m_playerPuppet.GetEntityID(), GetAllBlackboardDefs().PlayerStateMachine );
		return blackboard.GetBool( id );
	}

	private function SetBlackboardBoolVariable( id : BlackboardID_Bool, varValue : Bool )
	{
		var blackboardSystem : BlackboardSystem;
		var blackboard : IBlackboard;
		blackboardSystem = GameInstance.GetBlackboardSystem( GetOwner().GetGame() );
		blackboard = blackboardSystem.GetLocalInstanced( m_playerPuppet.GetEntityID(), GetAllBlackboardDefs().PlayerStateMachine );
		return blackboard.SetBool( id, varValue );
	}

	private export function OnGameAttach()
	{
		m_playerPuppet = ( ( PlayerPuppet )( GetOwner() ) );
		GetOwner().RegisterInputListener( this, 'Debug_ModifyWeaponPosition' );
		GetOwner().RegisterInputListener( this, 'Debug_ModifyWeaponRotation' );
		GetOwner().RegisterInputListener( this, 'Debug_ResetWeaponPosition' );
		GetOwner().RegisterInputListener( this, 'Debug_FineTuneWeaponPose' );
		GetOwner().RegisterInputListener( this, 'DebugWeaponPosX' );
		GetOwner().RegisterInputListener( this, 'DebugWeaponPosY' );
		GetOwner().RegisterInputListener( this, 'DebugWeaponPosZ' );
		GetOwner().RegisterInputListener( this, 'DebugWeaponRotX' );
		GetOwner().RegisterInputListener( this, 'DebugWeaponRotY' );
		GetOwner().RegisterInputListener( this, 'DebugWeaponRotZ' );
		GetOwner().RegisterInputListener( this, 'Debug_ToggleFocusMode' );
		ResetData();
	}

	private function OnUpdate( deltaTime : Float )
	{
		ClearDebugInfo();
		UpdateTweakDBParams();
		UpdateData();
		if( m_tweakPosition || m_tweakRotation )
		{
			UpdateWeaponPositionDataFromInput();
		}
		ResetDeltas();
		m_weaponAimPosVec += m_weaponAimPosOffsetFromInput;
		m_weaponAimRotVec += m_weaponAimRotOffsetFromInput;
		m_weaponPosVec += m_weaponPosOffsetFromInput;
		m_weaponRotVec += m_weaponRotOffsetFromInput;
		SendData();
		if( ShouldDisplayDebugInfo() )
		{
			UpdateDebugInfo();
		}
	}

	protected event OnAction( action : ListenerAction, consumer : ListenerActionConsumer )
	{
		if( ListenerAction.GetName( action ) == 'Debug_ModifyWeaponPosition' )
		{
			if( ListenerAction.IsButtonJustPressed( action ) )
			{
				m_tweakPosition = true;
			}
			else if( ListenerAction.IsButtonJustReleased( action ) )
			{
				m_tweakPosition = false;
			}
		}
		if( ListenerAction.GetName( action ) == 'Debug_ModifyWeaponRotation' )
		{
			if( ListenerAction.IsButtonJustPressed( action ) )
			{
				m_tweakRotation = true;
			}
			else if( ListenerAction.IsButtonJustReleased( action ) )
			{
				m_tweakRotation = false;
			}
		}
		if( ListenerAction.GetName( action ) == 'Debug_ResetWeaponPosition' )
		{
			if( IsOwnerAiming() )
			{
				ResetWeaponAimOffsetFromInput();
			}
			else
			{
				ResetWeaponOffsetFromInput();
			}
		}
		if( ListenerAction.GetName( action ) == 'Debug_FineTuneWeaponPose' )
		{
			if( ListenerAction.IsButtonJustPressed( action ) )
			{
				m_fineTuneWeaponPose = true;
			}
			else if( ListenerAction.IsButtonJustReleased( action ) )
			{
				m_fineTuneWeaponPose = false;
			}
		}
		if( m_tweakPosition )
		{
			if( ListenerAction.GetName( action ) == 'DebugWeaponPosX' )
			{
				if( m_fineTuneWeaponPose )
				{
					m_weaponPosDeltaX += ( ListenerAction.GetValue( action ) * m_positionSensitivityFineTuning );
				}
				else
				{
					m_weaponPosDeltaX += ( ListenerAction.GetValue( action ) * m_positionSensitivity );
				}
			}
			if( ListenerAction.GetName( action ) == 'DebugWeaponPosY' )
			{
				if( m_fineTuneWeaponPose )
				{
					m_weaponPosDeltaY -= ( ListenerAction.GetValue( action ) * m_positionSensitivityFineTuning );
				}
				else
				{
					m_weaponPosDeltaY -= ( ListenerAction.GetValue( action ) * m_positionSensitivity );
				}
			}
			if( ListenerAction.GetName( action ) == 'DebugWeaponPosZ' )
			{
				if( m_fineTuneWeaponPose )
				{
					m_weaponPosDeltaZ += ( ListenerAction.GetValue( action ) * m_positionSensitivityFineTuning );
				}
				else
				{
					m_weaponPosDeltaZ += ( ListenerAction.GetValue( action ) * m_positionSensitivity );
				}
			}
		}
		if( m_tweakRotation )
		{
			if( ListenerAction.GetName( action ) == 'DebugWeaponRotX' )
			{
				if( m_fineTuneWeaponPose )
				{
					m_weaponRotDeltaX -= ( ListenerAction.GetValue( action ) * m_rotationSensitivityFineTuning );
				}
				else
				{
					m_weaponRotDeltaX -= ( ListenerAction.GetValue( action ) * m_rotationSensitivity );
				}
				if( m_tweakPosition && m_tweakRotation )
				{
					m_weaponRotDeltaX *= -1.0;
				}
			}
			if( ListenerAction.GetName( action ) == 'DebugWeaponRotY' )
			{
				if( m_fineTuneWeaponPose )
				{
					m_weaponRotDeltaY += ( ListenerAction.GetValue( action ) * m_rotationSensitivityFineTuning );
				}
				else
				{
					m_weaponRotDeltaY += ( ListenerAction.GetValue( action ) * m_rotationSensitivity );
				}
			}
			if( ListenerAction.GetName( action ) == 'DebugWeaponRotZ' )
			{
				if( m_fineTuneWeaponPose )
				{
					m_weaponRotDeltaZ += ( ListenerAction.GetValue( action ) * m_rotationSensitivityFineTuning );
				}
				else
				{
					m_weaponRotDeltaZ += ( ListenerAction.GetValue( action ) * m_rotationSensitivity );
				}
				if( m_tweakPosition && m_tweakRotation )
				{
					m_weaponRotDeltaZ *= -1.0;
				}
			}
		}
		if( ListenerAction.GetName( action ) == 'Debug_ToggleFocusMode' )
		{
			m_visionSwitch = GetBlackboardIntVariable( GetAllBlackboardDefs().PlayerStateMachine.VisionDebug ) == ( ( Int32 )( gamePSMVisionDebug.VisionToggle ) );
			if( ListenerAction.IsButtonJustPressed( action ) )
			{
				if( m_visionSwitch )
				{
					SetBlackboardIntVariable( GetAllBlackboardDefs().PlayerStateMachine.VisionDebug, ( ( Int32 )( gamePSMVisionDebug.Default ) ) );
				}
				else if( !( m_visionSwitch ) )
				{
					SetBlackboardIntVariable( GetAllBlackboardDefs().PlayerStateMachine.VisionDebug, ( ( Int32 )( gamePSMVisionDebug.VisionToggle ) ) );
				}
			}
		}
	}


	private var m_weaponPosDeltaX : Float;
	private var m_weaponPosDeltaY : Float;
	private var m_weaponPosDeltaZ : Float;
	private var m_weaponRotDeltaX : Float;
	private var m_weaponRotDeltaY : Float;
	private var m_weaponRotDeltaZ : Float;

	private function ResetDeltas()
	{
		m_weaponPosDeltaX = 0.0;
		m_weaponPosDeltaY = 0.0;
		m_weaponPosDeltaZ = 0.0;
		m_weaponRotDeltaX = 0.0;
		m_weaponRotDeltaY = 0.0;
		m_weaponRotDeltaZ = 0.0;
	}

	private function ResetData()
	{
		m_weaponPosVec = Vector4( 0.0, 0.0, 0.0, 1.0 );
		m_weaponRotVec = Vector4( 0.0, 0.0, 0.0, 1.0 );
		m_weaponAimPosVec = Vector4( 0.0, 0.0, 0.0, 1.0 );
		m_weaponAimRotVec = Vector4( 0.0, 0.0, 0.0, 1.0 );
		ResetWeaponOffsetFromInput();
		ResetWeaponAimOffsetFromInput();
	}

	private function ResetWeaponOffsetFromInput()
	{
		m_weaponPosOffsetFromInput = Vector4( 0.0, 0.0, 0.0, 1.0 );
		m_weaponRotOffsetFromInput = Vector4( 0.0, 0.0, 0.0, 1.0 );
	}

	private function ResetWeaponAimOffsetFromInput()
	{
		m_weaponAimPosOffsetFromInput = Vector4( 0.0, 0.0, 0.0, 1.0 );
		m_weaponAimRotOffsetFromInput = Vector4( 0.0, 0.0, 0.0, 1.0 );
	}

	private function ShouldDisplayDebugInfo() : Bool
	{
		return ( ( m_weaponPosOffsetFromInput != Vector4( 0.0, 0.0, 0.0, 1.0 ) || m_weaponRotOffsetFromInput != Vector4( 0.0, 0.0, 0.0, 1.0 ) ) || m_weaponAimPosOffsetFromInput != Vector4( 0.0, 0.0, 0.0, 1.0 ) ) || m_weaponAimRotOffsetFromInput != Vector4( 0.0, 0.0, 0.0, 1.0 );
	}

	private function UpdateTweakDBParams()
	{
		m_positionSensitivity = TDB.GetFloat( T"weapons.weaponPoseTweak.positionSensitivity", 0.001 );
		m_positionSensitivityFineTuning = TDB.GetFloat( T"weapons.weaponPoseTweak.positionSensitivityFineTuning", 0.00001 );
		m_rotationSensitivity = TDB.GetFloat( T"weapons.weaponPoseTweak.rotationSensitivity", 0.1 );
		m_rotationSensitivityFineTuning = TDB.GetFloat( T"weapons.weaponPoseTweak.rotationSensitivityFineTuning", 0.001 );
	}

	private function UpdateData()
	{
		if( TDB.GetBool( T"weapons.general.usePositionAndRotationFromTweakDB", false ) )
		{
			UpdateWeaponPositionDataFromTweakDB();
		}
		else
		{
			UpdateWeaponPositionDataFromWeaponStats();
		}
		UpdateCameraData();
	}

	private function SendData()
	{
		SendWeaponPositionData();
		SendCameraData();
	}


	private var m_weaponPosVec : Vector4;
	private var m_weaponRotVec : Vector4;
	private var m_weaponAimPosVec : Vector4;
	private var m_weaponAimRotVec : Vector4;
	private var m_weaponPosOffsetFromInput : Vector4;
	private var m_weaponRotOffsetFromInput : Vector4;
	private var m_weaponAimPosOffsetFromInput : Vector4;
	private var m_weaponAimRotOffsetFromInput : Vector4;

	private function UpdateWeaponPositionDataFromTweakDB()
	{
		m_weaponPosVec.X = TDB.GetFloat( T"weapons.position.posX", 0.0 );
		m_weaponPosVec.Y = TDB.GetFloat( T"weapons.position.posY", 0.0 );
		m_weaponPosVec.Z = TDB.GetFloat( T"weapons.position.posZ", 0.0 );
		m_weaponAimPosVec.X = TDB.GetFloat( T"weapons.position.posAimX", 0.0 );
		m_weaponAimPosVec.Y = TDB.GetFloat( T"weapons.position.posAimY", 0.0 );
		m_weaponAimPosVec.Z = TDB.GetFloat( T"weapons.position.posAimZ", 0.0 );
		m_weaponRotVec.X = TDB.GetFloat( T"weapons.rotation.rotZ", 0.0 );
		m_weaponRotVec.Y = TDB.GetFloat( T"weapons.rotation.rotY", 0.0 );
		m_weaponRotVec.Z = TDB.GetFloat( T"weapons.rotation.rotX", 0.0 );
		m_weaponAimRotVec.X = TDB.GetFloat( T"weapons.rotation.rotAimX", 0.0 );
		m_weaponAimRotVec.Y = TDB.GetFloat( T"weapons.rotation.rotAimY", 0.0 );
		m_weaponAimRotVec.Z = TDB.GetFloat( T"weapons.rotation.rotAimZ", 0.0 );
	}

	private function UpdateWeaponPositionDataFromWeaponStats()
	{
		var weapon : GameObject;
		var weaponID : StatsObjectID;
		var statsSystem : StatsSystem;
		weapon = GameInstance.GetTransactionSystem( m_playerPuppet.GetGame() ).GetItemInSlot( m_playerPuppet, T"AttachmentSlots.WeaponRight" );
		if( !( weapon ) )
		{
			return;
		}
		weaponID = weapon.GetEntityID();
		statsSystem = GameInstance.GetStatsSystem( m_playerPuppet.GetGame() );
		if( !( statsSystem ) )
		{
			return;
		}
		m_weaponPosVec.X = statsSystem.GetStatValue( weaponID, gamedataStatType.WeaponPosX );
		m_weaponPosVec.Y = statsSystem.GetStatValue( weaponID, gamedataStatType.WeaponPosY );
		m_weaponPosVec.Z = statsSystem.GetStatValue( weaponID, gamedataStatType.WeaponPosZ );
		m_weaponAimPosVec.X = statsSystem.GetStatValue( weaponID, gamedataStatType.WeaponPosAdsX );
		m_weaponAimPosVec.Y = statsSystem.GetStatValue( weaponID, gamedataStatType.WeaponPosAdsY );
		m_weaponAimPosVec.Z = statsSystem.GetStatValue( weaponID, gamedataStatType.WeaponPosAdsZ );
		m_weaponRotVec.X = statsSystem.GetStatValue( weaponID, gamedataStatType.WeaponRotX );
		m_weaponRotVec.Y = statsSystem.GetStatValue( weaponID, gamedataStatType.WeaponRotY );
		m_weaponRotVec.Z = statsSystem.GetStatValue( weaponID, gamedataStatType.WeaponRotZ );
		m_weaponAimRotVec.X = statsSystem.GetStatValue( weaponID, gamedataStatType.WeaponRotAdsX );
		m_weaponAimRotVec.Y = statsSystem.GetStatValue( weaponID, gamedataStatType.WeaponRotAdsY );
		m_weaponAimRotVec.Z = statsSystem.GetStatValue( weaponID, gamedataStatType.WeaponRotAdsZ );
	}

	private function UpdateWeaponPositionDataFromInput()
	{
		if( IsOwnerAiming() )
		{
			m_weaponAimPosOffsetFromInput.X += m_weaponPosDeltaX;
			m_weaponAimPosOffsetFromInput.Y += m_weaponPosDeltaY;
			m_weaponAimPosOffsetFromInput.Z += m_weaponPosDeltaZ;
			m_weaponAimRotOffsetFromInput.X += m_weaponRotDeltaX;
			m_weaponAimRotOffsetFromInput.Y += m_weaponRotDeltaY;
			m_weaponAimRotOffsetFromInput.Z += m_weaponRotDeltaZ;
		}
		else
		{
			m_weaponPosOffsetFromInput.X += m_weaponPosDeltaX;
			m_weaponPosOffsetFromInput.Y += m_weaponPosDeltaY;
			m_weaponPosOffsetFromInput.Z += m_weaponPosDeltaZ;
			m_weaponRotOffsetFromInput.X += m_weaponRotDeltaX;
			m_weaponRotOffsetFromInput.Y += m_weaponRotDeltaY;
			m_weaponRotOffsetFromInput.Z += m_weaponRotDeltaZ;
		}
	}

	private function SendWeaponPositionData()
	{
		AnimationControllerComponent.SetInputVector( GetOwner(), 'weapon_offset_shoulder', m_weaponPosVec );
		AnimationControllerComponent.SetInputVector( GetOwner(), 'weapon_offset_aiming', m_weaponAimPosVec );
		AnimationControllerComponent.SetInputVector( GetOwner(), 'weapon_rotation_shoulder', m_weaponRotVec );
		AnimationControllerComponent.SetInputVector( GetOwner(), 'weapon_rotation_aiming', m_weaponAimRotVec );
	}


	private var m_cameraStandHeight : Float;
	private var m_cameraCrouchHeight : Float;
	private var m_cameraResetPitch : Bool;
	private var m_cameraHeightOffset : Float;

	private function UpdateCameraData()
	{
		m_cameraStandHeight = TDB.GetFloat( T"player.camera.standHeight", -1.0 );
		m_cameraCrouchHeight = TDB.GetFloat( T"player.camera.crouchHeight", -1.0 );
		m_cameraHeightOffset = TDB.GetFloat( T"player.camera.cameraHeighOffset", 0.0 );
		m_cameraResetPitch = TDB.GetBool( T"player.camera.resetPitch", false );
	}

	private function SendCameraData()
	{
		var tempVectorCauseStuffsRetarted : Vector4;
		Vector4.Zero( tempVectorCauseStuffsRetarted );
		tempVectorCauseStuffsRetarted.Z = m_cameraStandHeight;
		AnimationControllerComponent.SetInputVector( GetOwner(), 'debug_stand_camera_position', tempVectorCauseStuffsRetarted );
		tempVectorCauseStuffsRetarted.Z = m_cameraCrouchHeight;
		AnimationControllerComponent.SetInputVector( GetOwner(), 'debug_crouch_camera_position', tempVectorCauseStuffsRetarted );
		AnimationControllerComponent.SetInputBool( GetOwner(), 'debug_camera_reset_pitch', m_cameraResetPitch );
		AnimationControllerComponent.SetInputFloat( GetOwner(), 'debug_camera_height_offset', m_cameraHeightOffset );
	}

	private function IsOwnerAiming() : Bool
	{
		return GetBlackboardIntVariable( GetAllBlackboardDefs().PlayerStateMachine.UpperBody ) == ( ( Int32 )( gamePSMUpperBodyStates.Aim ) );
	}


	private var UILayerID0 : Uint32;
	private var UILayerID1 : Uint32;
	private var UILayerID2 : Uint32;
	private var UILayerID3 : Uint32;

	private function UpdateDebugInfo()
	{
		UILayerID0 = GameInstance.GetDebugVisualizerSystem( GetOwner().GetGame() ).DrawText( Vector4( 20.0, 550.0, 0.0, 0.0 ), "Shoulder Position Offset: " + VectorToString( m_weaponPosVec ), gameDebugViewETextAlignment.Left, Color( 0, 255, 0, 255 ) );
		GameInstance.GetDebugVisualizerSystem( GetOwner().GetGame() ).SetScale( UILayerID0, Vector4( 1.0, 1.0, 0.0, 0.0 ) );
		UILayerID1 = GameInstance.GetDebugVisualizerSystem( GetOwner().GetGame() ).DrawText( Vector4( 20.0, 570.0, 0.0, 0.0 ), "Shoulder Rotation Offset: " + VectorToString( m_weaponRotVec ), gameDebugViewETextAlignment.Left, Color( 0, 255, 0, 255 ) );
		GameInstance.GetDebugVisualizerSystem( GetOwner().GetGame() ).SetScale( UILayerID1, Vector4( 1.0, 1.0, 0.0, 0.0 ) );
		UILayerID2 = GameInstance.GetDebugVisualizerSystem( GetOwner().GetGame() ).DrawText( Vector4( 20.0, 590.0, 0.0, 0.0 ), "Ironsight Position Offset: " + VectorToString( m_weaponAimPosVec ), gameDebugViewETextAlignment.Left, Color( 0, 255, 0, 255 ) );
		GameInstance.GetDebugVisualizerSystem( GetOwner().GetGame() ).SetScale( UILayerID2, Vector4( 1.0, 1.0, 0.0, 0.0 ) );
		UILayerID3 = GameInstance.GetDebugVisualizerSystem( GetOwner().GetGame() ).DrawText( Vector4( 20.0, 610.0, 0.0, 0.0 ), "Ironsight Rotation Offset: " + VectorToString( m_weaponAimRotVec ), gameDebugViewETextAlignment.Left, Color( 0, 255, 0, 255 ) );
		GameInstance.GetDebugVisualizerSystem( GetOwner().GetGame() ).SetScale( UILayerID3, Vector4( 1.0, 1.0, 0.0, 0.0 ) );
	}

	private function ClearDebugInfo()
	{
		GameInstance.GetDebugVisualizerSystem( GetOwner().GetGame() ).ClearLayer( UILayerID0 );
		GameInstance.GetDebugVisualizerSystem( GetOwner().GetGame() ).ClearLayer( UILayerID1 );
		GameInstance.GetDebugVisualizerSystem( GetOwner().GetGame() ).ClearLayer( UILayerID2 );
		GameInstance.GetDebugVisualizerSystem( GetOwner().GetGame() ).ClearLayer( UILayerID3 );
	}

}

