import enum gameTelemetryDamageSituation
{
	Irrelevant,
	EnemyToPlayer,
	EnemyToCompanion,
	PlayerToEnemy,
	CompanionToEnemy,
	PlayerToPlayer,
}

import enum telemetryHitDefenseType
{
	Block,
	Deflect,
}

import enum telemetryInitalChoiceStage
{
	None,
	Difficulty,
	LifePath,
	Gender,
	Customizations,
	Attributes,
	Finished,
}

import enum telemetryMovementType
{
	Jump,
	DoubleJump,
	ChargedJump,
	Dodge,
	AirDodge,
}

import struct TelemetryLevelGained
{
	import var playerPuppet : weak< GameObject >;
	import var proficiencyType : gamedataProficiencyType;
	import var proficiencyValue : Int32;
	import var perkPointsAwarded : Int32;
	import var attributePointsAwarded : Int32;
	import var isDebugEvt : Bool;
}

import struct TelemetryInventoryItem
{
	import var friendlyName : String;
	import var localizedName : String;
	import var itemID : ItemID;
	import var quality : gamedataQuality;
	import var itemType : gamedataItemType;
	import var iconic : Bool;
	import var itemLevel : Int32;
	import var isSilenced : Bool;
}

import struct TelemetryEnemy
{
	import var characterRecord : TweakDBID;
	import var enemyAffiliation : String;
	import var enemy : weak< GameObject >;
	import var enemyEntityID : EntityID;
	import var archetype : gamedataArchetypeType;
	import var level : Int32;
}

import struct TelemetrySourceEntity
{
	import var className : String;
	import var sourceEntityRecord : TweakDBID;
}

import struct TelemetryDamage
{
	import var attackType : gamedataAttackType;
	import var attackRecord : TweakDBID;
	import var damageAmount : Float;
	import var weapon : TelemetryInventoryItem;
	import var sourceEntity : TelemetrySourceEntity;
	import var distance : Float;
	import var time : Float;
}

import struct TelemetryDamageDealt
{
	import var situation : gameTelemetryDamageSituation;
	import var damage : TelemetryDamage;
	import var enemy : TelemetryEnemy;
}

import struct TelemetryEnemyDown
{
	import var enemy : TelemetryEnemy;
	import var situation : gameTelemetryDamageSituation;
	import var killType : gameKillType;
}

import struct TelemetryQuickHack
{
	import var actionName : CName;
	import var titleLocKey : String;
	import var targetType : String;
	import var quickHackRecordID : TweakDBID;
	import var quality : gamedataQuality;
}

import abstract class ITelemetrySystem extends IGameSystem
{
	public import function LogInitialChoiceSetStatege( state : telemetryInitalChoiceStage );
	public import function LogInitialChoiceDifficultySelected( difficulty : gameDifficulty );
	public import function LogInitialChoiceLifePathSelected( lifePathID : TweakDBID );
	public import function LogInitialChoiceBodyGenderSelected( isMale : Bool );
	public import function LogInitialChoiceBrainGenderSelected( isMale : Bool );
	public import function LogInitialChoiceOptionSelected( const option : CharacterCustomizationOption, value : Uint32 );
	public import function LogInitialChoicePresetSelected( presetName : CName, optional fromInit : Bool );
	public import function LogInitialChoiceAttributeChanged( attribute : gamedataStatType );
	public import function LogNewGameStarted();
	public import function LogCharacterCustomizationChanged();
	public import function LogCharacterCustomizationCancelled();
	public import function LogPlaythroughEp1();
	public import function ClearPlaythroughEp1();
}

import final class TelemetrySystem extends ITelemetrySystem
{
	public import function LogDamageDealt( damage : TelemetryDamageDealt );
	public import function LogHeadshotGGP( num : Int32 );
	public import function LogPlayerInDangerousArea( dangerous : Bool );
	public import function LogNumberOfCombatants( numberOfCombatants : Int32 );
	public import function LogEnemyDown( telemetryEnemyDown : TelemetryEnemyDown );
	public import function LogCombatGadgetUsed( owner : weak< GameObject >, itemID : ItemID );
	public import function LogActiveCyberwareUsed( owner : weak< GameObject >, itemID : ItemID );
	public import function LogConsumableUsed( owner : weak< GameObject >, itemID : ItemID );
	public import function LogSpecialMovementPerformed( mvtType : telemetryMovementType );
	public import function LogPlayerReachedCriticalHealth( healthIsCritical : Bool );
	public import function LogPlayerDeathEvent( evt : gameDeathEvent );
	public import function LogLevelGained( evt : TelemetryLevelGained );
	public import function LogDistrictChanged( districtName : String, isNew : Bool );
	public import function LogRewardGiven( rewardName : CName, rewardTDBID : TweakDBID, rewardMoney : Int32 );
	public import function LogAttributeUpgraded( attributeType : gamedataStatType, lvl : Int32 );
	public import function LogPerkUpgraded( perkUpgraded : gamedataPerkType, lvl : Int32 );
	public import function LogNewPerkUpgraded( newPerkUpgraded : gamedataNewPerkType, lvl : Int32, developementPointType : gamedataDevelopmentPointType );
	public import function LogPartInstalled( modifiedItem : TelemetryInventoryItem, itemPart : TelemetryInventoryItem, slotID : TweakDBID );
	public import function LogInventoryMenuClosed();
	public import function LogQuickHack( telemetryQuickHack : TelemetryQuickHack );
	public import function LogTakedown( takedownAction : CName, target : weak< GameObject > );
	public import function LogBodyDisposed();
	public import function LogWeaponAttackPerformed( weapon : weak< WeaponObject > );
	public import function LogHitDefense( defenseType : telemetryHitDefenseType );
	public import function LogItemTransaction( buyer : weak< GameObject >, seller : weak< GameObject >, itemID : ItemID, pricePerItem : Uint32, itemQuantity : Uint32, totalPrice : Uint32 );
	public import function LogVendorMenuState( vendorid : TweakDBID, isOpening : Bool );
	public import function LogSkillbookUsed( owner : weak< GameObject >, itemID : ItemID );
	public import function LogItemAcquired( itemTDBID : TweakDBID, meanOfAcquisition : String );
	public import function LogItemDrop( owner : weak< GameObject >, itemID : ItemID );
	public import function LogItemCrafting( telemetryInventoryItem : TelemetryInventoryItem, craftingAction : CName );
	public import function LogItemDisassembled( owner : weak< GameObject >, itemID : ItemID );
	public import function LogItemReward( owner : weak< GameObject >, itemID : ItemID );
	public import function LogDamageByVehicle( hitEvent : gameHitEvent );
	public import function LogXPReward( xpRecordID : TweakDBID, amount : Int32, type : gamedataProficiencyType );
	public import function LogDevPointsAddedFromReward( addDevPointEffectorTDBID : TweakDBID, amount : Int32, type : gamedataDevelopmentPointType );
	public import function OnSettingsSave();
	public import function LogBraindanceReset();
	public import function LogLastCheckpointLoaded();
	public import function LogPerksRemoved( respecCost : Int32, perksRemoved : array< gamedataPerkType > );
	public import function LogNewPerkRemoved( perkRemoved : gamedataNewPerkType );
	public import function LogPhotomodeAttributeChanged();
	public import function LogWardrobeUsed( slotsUsed : Int32 );
	public import function LogEnteringOrExitingVehicle( isExiting : Bool );
	public import function LogPlayerVehicleExploded();
	public import function LogPlayerVehicleDamageReceived( damage : Int32 );
	public import function LogPlayerVehicleImpact();
	public import function LogHeatLevelChanged( heatLevel : Uint32, reason : String, crimescore : Uint32 );
	public import static function GetTelemetryInventoryItemFromID( owner : weak< GameObject >, itemID : ItemID ) : TelemetryInventoryItem;
	public import static function GetTelemetryInventoryItemFromdata( itemData : weak< gameItemData > ) : TelemetryInventoryItem;
}

function ToInventoryItemData( owner : weak< GameObject >, itemID : ItemID ) : InventoryItemData
{
	var equipmentSystem : EquipmentSystem;
	var transactionSystem : weak< TransactionSystem >;
	var inventoryManager : weak< InventoryDataManagerV2 >;
	var itemData : weak< gameItemData >;
	var playerPuppet : weak< GameObject >;
	if( owner )
	{
		equipmentSystem = ( ( EquipmentSystem )( GameInstance.GetScriptableSystemsContainer( owner.GetGame() ).Get( 'EquipmentSystem' ) ) );
		transactionSystem = GameInstance.GetTransactionSystem( owner.GetGame() );
		playerPuppet = GameInstance.GetPlayerSystem( owner.GetGame() ).GetLocalPlayerMainGameObject();
		if( ( equipmentSystem && transactionSystem ) && playerPuppet )
		{
			inventoryManager = equipmentSystem.GetInventoryManager( playerPuppet );
			if( inventoryManager )
			{
				itemData = transactionSystem.GetItemData( owner, itemID );
				if( itemData )
				{
					return inventoryManager.GetInventoryItemData( itemData );
				}
			}
		}
	}
	return EmptyInventoryItemData();
}

function EmptyInventoryItemData() : InventoryItemData
{
	var inventoryItemData : InventoryItemData;
	return inventoryItemData;
}

function ToTelemetryInventoryItem( const inventoryItemData : ref< InventoryItemData > ) : TelemetryInventoryItem
{
	var telemetryItem : TelemetryInventoryItem;
	telemetryItem.friendlyName = InventoryItemData.GetGameItemData( inventoryItemData ).GetNameAsString();
	telemetryItem.localizedName = InventoryItemData.GetName( inventoryItemData );
	telemetryItem.itemID = InventoryItemData.GetID( inventoryItemData );
	telemetryItem.quality = InventoryItemData.GetComparedQuality( inventoryItemData );
	telemetryItem.itemType = InventoryItemData.GetItemType( inventoryItemData );
	telemetryItem.itemLevel = InventoryItemData.GetItemLevel( inventoryItemData );
	telemetryItem.iconic = InventoryItemData.GetGameItemData( inventoryItemData ).GetStatValueByType( gamedataStatType.IsItemIconic ) > 0.0;
	return telemetryItem;
}

export function ToTelemetryEnemy( target : weak< GameObject > ) : TelemetryEnemy
{
	var puppet : NPCPuppet;
	var telemtryNME : TelemetryEnemy;
	telemtryNME.enemy = target;
	if( target )
	{
		telemtryNME.enemyEntityID = target.GetEntityID();
		telemtryNME.level = ( ( Int32 )( GameInstance.GetStatsSystem( target.GetGame() ).GetStatValue( telemtryNME.enemyEntityID, gamedataStatType.PowerLevel ) ) );
	}
	telemtryNME.characterRecord = GameObject.GetTDBID( target );
	if( target.IsPuppet() )
	{
		puppet = ( ( NPCPuppet )( target ) );
		telemtryNME.enemyAffiliation = ( ( puppet.IsCharacterCivilian() ) ? ( "civilian" ) : ( puppet.GetAffiliation() ) );
		telemtryNME.archetype = TweakDBInterface.GetCharacterRecord( GameObject.GetTDBID( puppet ) ).ArchetypeData().Type().Type();
	}
	else if( target.IsTurret() )
	{
		telemtryNME.enemyAffiliation = "Turret";
	}
	else if( target.IsSensor() )
	{
		telemtryNME.enemyAffiliation = "Sensor";
	}
	else if( target.IsDevice() )
	{
		telemtryNME.enemyAffiliation = "Device";
	}
	else
	{
		telemtryNME.enemyAffiliation = "Other";
	}
	return telemtryNME;
}

function ToTelemetryDamage( evt : gameTargetDamageEvent ) : TelemetryDamage
{
	var telemetryDamage : TelemetryDamage;
	telemetryDamage = ToTelemetryDamage( evt.attackData );
	telemetryDamage.damageAmount = evt.damage;
	return telemetryDamage;
}

function ToTelemetryDamage( evt : gameDamageReceivedEvent ) : TelemetryDamage
{
	var telemetryDamage : TelemetryDamage;
	telemetryDamage = ToTelemetryDamage( evt.hitEvent.attackData );
	telemetryDamage.damageAmount = evt.totalDamageReceived;
	return telemetryDamage;
}

function ToTelemetryDamage( attackData : AttackData ) : TelemetryDamage
{
	var telemetryDamage : TelemetryDamage;
	var weapon : weak< WeaponObject >;
	var instigator : weak< GameObject >;
	var source : weak< GameObject >;
	var sourceIsAPuppet : weak< gamePuppetBase >;
	var itemObjectWeapon : weak< ItemObject >;
	telemetryDamage.attackType = attackData.GetAttackType();
	if( attackData.GetAttackDefinition() && attackData.GetAttackDefinition().GetRecord() )
	{
		telemetryDamage.attackRecord = attackData.GetAttackDefinition().GetRecord().GetID();
	}
	weapon = attackData.GetWeapon();
	instigator = attackData.GetInstigator();
	source = attackData.GetSource();
	sourceIsAPuppet = ( ( weak< weak< gamePuppetBase > > )( source ) );
	itemObjectWeapon = ( ( weapon ) ? ( weapon ) : ( ( ( weak< weak< ItemObject > > )( source ) ) ) );
	if( itemObjectWeapon && instigator )
	{
		telemetryDamage.weapon = TelemetrySystem.GetTelemetryInventoryItemFromdata( itemObjectWeapon.GetItemData() );
		if( weapon )
		{
			telemetryDamage.weapon.isSilenced = weapon.IsSilenced();
		}
	}
	else if( source && !( sourceIsAPuppet ) )
	{
		telemetryDamage.sourceEntity.className = NameToString( source.GetClassName() );
		telemetryDamage.sourceEntity.sourceEntityRecord = GameObject.GetTDBID( source );
	}
	return telemetryDamage;
}

function ToTelemetryDamageDealt( evt : gameTargetDamageEvent, situation : gameTelemetryDamageSituation, distance : Float, time : Float ) : TelemetryDamageDealt
{
	var telemetryDamageDealt : TelemetryDamageDealt;
	telemetryDamageDealt.situation = situation;
	telemetryDamageDealt.damage = ToTelemetryDamage( evt );
	telemetryDamageDealt.enemy = ToTelemetryEnemy( evt.target );
	telemetryDamageDealt.damage.distance = distance;
	telemetryDamageDealt.damage.time = time;
	return telemetryDamageDealt;
}

function ToTelemetryDamageDealt( evt : gameDamageReceivedEvent, situation : gameTelemetryDamageSituation, distance : Float, time : Float ) : TelemetryDamageDealt
{
	var telemetryDamageDealt : TelemetryDamageDealt;
	telemetryDamageDealt.situation = situation;
	telemetryDamageDealt.damage = ToTelemetryDamage( evt );
	telemetryDamageDealt.enemy = ToTelemetryEnemy( evt.hitEvent.attackData.GetInstigator() );
	telemetryDamageDealt.damage.distance = distance;
	telemetryDamageDealt.damage.time = time;
	return telemetryDamageDealt;
}

