class InventoryTooltipData extends ATooltipData
{
	var itemID : ItemID;
	var isEquipped : Bool;
	var isLocked : Bool;
	var isVendorItem : Bool;
	var isCraftable : Bool;
	var isPerkRequired : Bool;
	var qualityStateName : CName;
	var description : String;
	var additionalDescription : String;
	var gameplayDescription : String;
	var category : String;
	var quality : String;
	var itemName : String;
	var perkRequiredName : String;
	var price : Float;
	var buyPrice : Float;
	var unlockProgress : Float;
	var primaryStats : array< InventoryTooltipData_StatData >;
	var comparedStats : array< InventoryTooltipData_StatData >;
	var additionalStats : array< InventoryTooltipData_StatData >;
	var randomDamageTypes : array< InventoryTooltipData_StatData >;
	var recipeAdditionalStats : array< InventoryTooltipData_StatData >;
	var damageType : gamedataDamageType;
	var isBroken : Bool;
	var levelRequired : Int32;
	var attachments : array< CName >;
	var specialAbilities : array< InventoryItemAbility >;
	var equipArea : gamedataEquipmentArea;
	var showCyclingDots : Bool;
	var numberOfCyclingDots : Int32;
	var selectedCyclingDot : Int32;
	var comparedQuality : gamedataQuality;
	default comparedQuality = gamedataQuality.Invalid;
	var qualityF : Float;
	var comparisonQualityF : Float;
	default comparisonQualityF = -1.0f;
	var showIcon : Bool;
	var randomizedStatQuantity : Int32;
	var itemType : gamedataItemType;
	default itemType = gamedataItemType.Invalid;
	var m_HasPlayerSmartGunLink : Bool;
	var m_PlayerLevel : Int32;
	var m_PlayerStrenght : Int32;
	var m_PlayerReflexes : Int32;
	var m_PlayerStreetCred : Int32;
	var itemAttachments : array< InventoryItemAttachments >;
	var inventoryItemData : InventoryItemData;
	var overrideRarity : Bool;
	var quickhackData : InventoryTooltipData_QuickhackData;
	var grenadeData : InventoryTooltiData_GrenadeData;
	var cyberdeckData : InventoryTooltipData_CyberdeckData;
	var cyberwareUpgradeData : InventoryTooltiData_CyberwareUpgradeData;
	var displayContext : InventoryTooltipDisplayContext;
	var parentItemData : weak< gameItemData >;
	var slotID : TweakDBID;
	var transmogItem : ItemID;
	private var managerRef : weak< UIInventoryItemsManager >;
	private var statsManager : UIInventoryItemStatsManager;
	private var statsManagerFetched : Bool;
	var DEBUG_iconErrorInfo : DEBUG_IconErrorInfo;

	public static function FromItemViewData( const itemViewData : ref< ItemViewData > ) : InventoryTooltipData
	{
		var outObject : InventoryTooltipData;
		outObject = new InventoryTooltipData;
		outObject.isCraftable = false;
		outObject.qualityStateName = UIItemsHelper.QualityStringToStateName( itemViewData.quality );
		outObject.description = itemViewData.description;
		outObject.category = itemViewData.categoryName;
		outObject.quality = itemViewData.quality;
		outObject.itemName = itemViewData.itemName;
		outObject.price = itemViewData.price;
		outObject.isBroken = itemViewData.isBroken;
		outObject.FillPrimaryStats( itemViewData.primaryStats );
		outObject.FillDetailedStats( itemViewData.secondaryStats );
		outObject.comparedQuality = itemViewData.comparedQuality;
		return outObject;
	}

	public function FillPrimaryStats( const rawStats : ref< array< StatViewData > > )
	{
		var i, limit : Int32;
		var parsedStat : InventoryTooltipData_StatData;
		var currStatViewData : StatViewData;
		var maxStat : Int32;
		var maxStatF : Float;
		for( i = 0, limit = rawStats.Size(); i < limit; i += 1 )
		{
			currStatViewData = rawStats[ i ];
			maxStat = 100;
			maxStatF = 100.0;
			parsedStat = InventoryTooltipData_StatData( currStatViewData.type, currStatViewData.statName, Min( ( ( Int32 )( Max( currStatViewData.statMinValue, 0 ) ) ), currStatViewData.value ), Max( ( ( Int32 )( Min( currStatViewData.statMaxValue, maxStat ) ) ), currStatViewData.value ), currStatViewData.value, currStatViewData.diffValue, MinF( MaxF( currStatViewData.statMinValueF, 0.0 ), currStatViewData.valueF ), MaxF( MinF( currStatViewData.statMaxValueF, maxStatF ), currStatViewData.valueF ), currStatViewData.valueF, currStatViewData.diffValueF, EInventoryDataStatDisplayType.Value );
			primaryStats.PushBack( parsedStat );
		}
	}

	public function FillRecipeDamageTypeData( gi : GameInstance, itemData : weak< gameItemData > )
	{
		var i : Int32;
		var damage : gamedataDamageType;
		var baseDamage : Float;
		var parsedStat : InventoryTooltipData_StatData;
		var localizedName : String;
		var statsSystem : StatsSystem;
		statsSystem = GameInstance.GetStatsSystem( gi );
		damage = RPGManager.GetDominatingDamageType( gi, itemData );
		baseDamage = itemData.GetStatValueByType( statsSystem.GetStatType( damage ) );
		for( i = 0; i < ( ( Int32 )( gamedataDamageType.Count ) ); i += 1 )
		{
			damage = ( ( gamedataDamageType )( i ) );
			localizedName = statsSystem.GetDamageRecordFromType( damage ).AssociatedStat().LocalizedName();
			parsedStat = InventoryTooltipData_StatData( statsSystem.GetStatType( damage ), localizedName, 0, 0, 0, 0, baseDamage, baseDamage, baseDamage, baseDamage, EInventoryDataStatDisplayType.Value );
			randomDamageTypes.PushBack( parsedStat );
		}
	}

	public function FillRecipeStatsData( const rawStats : ref< array< weak< Stat_Record > > > )
	{
		var i, limit : Int32;
		var parsedStat : InventoryTooltipData_StatData;
		var currStat : Stat_Record;
		for( i = 0, limit = rawStats.Size(); i < limit; i += 1 )
		{
			currStat = rawStats[ i ];
			parsedStat = InventoryTooltipData_StatData( currStat.StatType(), currStat.LocalizedName(), 0, 0, 0, 0, 0.0, 0.0, 0.0, 0.0, EInventoryDataStatDisplayType.Value );
			recipeAdditionalStats.PushBack( parsedStat );
		}
	}

	public function FillDetailedStats( const rawStats : ref< array< StatViewData > >, optional isIconicRecipe : Bool )
	{
		var i, limit : Int32;
		var parsedStat : InventoryTooltipData_StatData;
		var currStatViewData : StatViewData;
		var maxStat : Int32;
		var maxStatF : Float;
		for( i = 0, limit = rawStats.Size(); i < limit; i += 1 )
		{
			currStatViewData = rawStats[ i ];
			maxStat = 100;
			maxStatF = 100.0;
			if( currStatViewData.isCompared )
			{
				if( currStatViewData.diffValue < 0 )
				{
					maxStat = Max( maxStat, currStatViewData.value - currStatViewData.diffValue );
					maxStatF = MaxF( maxStatF, currStatViewData.valueF - currStatViewData.diffValueF );
				}
				parsedStat = InventoryTooltipData_StatData( currStatViewData.type, currStatViewData.statName, Min( ( ( Int32 )( Max( currStatViewData.statMinValue, 0 ) ) ), currStatViewData.value ), Max( ( ( Int32 )( Min( currStatViewData.statMaxValue, maxStat ) ) ), currStatViewData.value ), currStatViewData.value, currStatViewData.diffValue, MinF( MaxF( currStatViewData.statMinValueF, 0.0 ), currStatViewData.valueF ), MaxF( MinF( currStatViewData.statMaxValueF, maxStatF ), currStatViewData.valueF ), currStatViewData.valueF, currStatViewData.diffValueF, ( ( currStatViewData.canBeCompared ) ? ( EInventoryDataStatDisplayType.CompareBar ) : ( EInventoryDataStatDisplayType.Value ) ) );
			}
			else
			{
				parsedStat = InventoryTooltipData_StatData( currStatViewData.type, currStatViewData.statName, Min( ( ( Int32 )( Max( currStatViewData.statMinValue, 0 ) ) ), currStatViewData.value ), Max( ( ( Int32 )( Min( currStatViewData.statMaxValue, maxStat ) ) ), currStatViewData.value ), currStatViewData.value, 0, MinF( MaxF( currStatViewData.statMinValueF, 0.0 ), currStatViewData.valueF ), MaxF( MinF( currStatViewData.statMaxValueF, maxStatF ), currStatViewData.valueF ), currStatViewData.valueF, 0.0, ( ( currStatViewData.canBeCompared ) ? ( EInventoryDataStatDisplayType.DisplayBar ) : ( EInventoryDataStatDisplayType.Value ) ) );
			}
			if( isIconicRecipe && !( IsElementalDamageType( parsedStat.statType ) ) )
			{
				continue;
			}
			if( currStatViewData.canBeCompared )
			{
				comparedStats.PushBack( parsedStat );
			}
			else
			{
				additionalStats.PushBack( parsedStat );
			}
		}
	}

	private function IsElementalDamageType( statType : gamedataStatType ) : Bool
	{
		switch( statType )
		{
			case gamedataStatType.ChemicalDamage:
			case gamedataStatType.ThermalDamage:
			case gamedataStatType.ElectricDamage:
			case gamedataStatType.PhysicalDamage:
				return true;
		}
		return false;
	}

	public static function FromInventoryItemData( const itemData : ref< InventoryItemData > ) : InventoryTooltipData
	{
		var i, limit : Int32;
		var attachmentName : CName;
		var outObject : InventoryTooltipData;
		var attachmentsSize : Int32;
		var attachments : InventoryItemAttachments;
		outObject = new InventoryTooltipData;
		outObject.itemID = InventoryItemData.GetID( itemData );
		outObject.isCraftable = false;
		outObject.qualityStateName = InventoryItemData.GetQuality( itemData );
		outObject.description = InventoryItemData.GetDescription( itemData );
		outObject.additionalDescription = InventoryItemData.GetAdditionalDescription( itemData );
		outObject.gameplayDescription = InventoryItemData.GetGameplayDescription( itemData );
		outObject.isBroken = InventoryItemData.IsBroken( itemData );
		outObject.isVendorItem = InventoryItemData.IsVendorItem( itemData );
		outObject.category = InventoryItemData.GetCategoryName( itemData );
		outObject.quality = NameToString( InventoryItemData.GetQuality( itemData ) );
		outObject.levelRequired = InventoryItemData.GetRequiredLevel( itemData );
		outObject.itemName = InventoryItemData.GetName( itemData );
		outObject.price = InventoryItemData.GetPrice( itemData );
		outObject.buyPrice = InventoryItemData.GetBuyPrice( itemData );
		outObject.FillPrimaryStats( InventoryItemData.GetPrimaryStats( itemData ) );
		outObject.FillDetailedStats( InventoryItemData.GetSecondaryStats( itemData ) );
		outObject.comparedQuality = InventoryItemData.GetComparedQuality( itemData );
		outObject.qualityF = UIItemsHelper.GetQualityF( itemData );
		outObject.damageType = InventoryItemData.GetDamageType( itemData );
		outObject.equipArea = InventoryItemData.GetEquipmentArea( itemData );
		outObject.itemType = InventoryItemData.GetItemType( itemData );
		outObject.m_HasPlayerSmartGunLink = InventoryItemData.HasPlayerSmartGunLink( itemData );
		outObject.m_PlayerLevel = InventoryItemData.GetPlayerLevel( itemData );
		outObject.m_PlayerStrenght = InventoryItemData.GetPlayerStrenght( itemData );
		outObject.m_PlayerReflexes = InventoryItemData.GetPlayerReflexes( itemData );
		outObject.m_PlayerStreetCred = InventoryItemData.GetPlayerStreetCred( itemData );
		outObject.isEquipped = InventoryItemData.IsEquipped( itemData );
		outObject.isPerkRequired = InventoryItemData.GetIsPerkRequired( itemData );
		outObject.perkRequiredName = InventoryItemData.GetPerkRequiredName( itemData );
		attachmentsSize = InventoryItemData.GetAttachmentsSize( itemData );
		for( i = 0, limit = attachmentsSize; i < limit; i += 1 )
		{
			attachmentName = '';
			attachments = InventoryItemData.GetAttachment( itemData, i );
			if( !( InventoryItemData.IsEmpty( attachments.ItemData ) ) )
			{
				attachmentName = InventoryItemData.GetQuality( attachments.ItemData );
			}
			outObject.attachments.PushBack( attachmentName );
		}
		outObject.specialAbilities = InventoryItemData.GetAbilities( itemData );
		outObject.itemAttachments = InventoryItemData.GetAttachments( itemData );
		outObject.inventoryItemData = itemData;
		return outObject;
	}

	public static function FromRecipeAndItemData( context : GameInstance, recipe : RecipeData, const itemData : ref< InventoryItemData >, const recipeOutcome : ref< InventoryItemData >, recipeGameItemData : weak< gameItemData > ) : InventoryTooltipData
	{
		var i, limit : Int32;
		var attachmentName : CName;
		var outObject : InventoryTooltipData;
		var attachmentsSize : Int32;
		var attachments : InventoryItemAttachments;
		var weaponEvolution : gamedataWeaponEvolution;
		var stats : array< weak< Stat_Record > >;
		var itemRecord : weak< Item_Record >;
		itemRecord = recipe.id;
		outObject = FromInventoryItemData( recipeOutcome );
		if( InventoryItemData.GetEquipmentArea( itemData ) == gamedataEquipmentArea.Weapon )
		{
			weaponEvolution = TDB.GetWeaponItemRecord( ItemID.GetTDBID( InventoryItemData.GetID( itemData ) ) ).Evolution().Type();
			stats = RPGManager.GetListOfRandomStatsFromEvolutionType( weaponEvolution );
			outObject.FillRecipeStatsData( stats );
			if( !( RPGManager.IsItemIconic( recipeGameItemData ) ) )
			{
				outObject.FillRecipeDamageTypeData( context, recipeGameItemData );
			}
			outObject.randomizedStatQuantity = 1;
		}
		if( outObject && !( IsStringValid( outObject.itemName ) ) )
		{
			outObject.itemName = LocKeyToString( itemRecord.DisplayName() );
		}
		outObject.itemID = InventoryItemData.GetID( itemData );
		outObject.isCraftable = true;
		if( !( InventoryItemData.IsEmpty( recipeOutcome ) ) )
		{
			outObject.qualityStateName = InventoryItemData.GetQuality( recipeOutcome );
		}
		else
		{
			outObject.qualityStateName = InventoryItemData.GetQuality( itemData );
		}
		outObject.quality = NameToString( outObject.qualityStateName );
		outObject.category = InventoryItemData.GetCategoryName( itemData );
		outObject.equipArea = InventoryItemData.GetEquipmentArea( itemData );
		outObject.itemType = InventoryItemData.GetItemType( itemData );
		outObject.description = InventoryItemData.GetDescription( itemData );
		outObject.additionalDescription = InventoryItemData.GetAdditionalDescription( itemData );
		outObject.gameplayDescription = InventoryItemData.GetGameplayDescription( itemData );
		outObject.isBroken = InventoryItemData.IsBroken( itemData );
		outObject.isVendorItem = InventoryItemData.IsVendorItem( itemData );
		outObject.levelRequired = InventoryItemData.GetRequiredLevel( itemData );
		outObject.price = InventoryItemData.GetPrice( recipeOutcome );
		outObject.buyPrice = InventoryItemData.GetBuyPrice( recipeOutcome );
		outObject.FillPrimaryStats( InventoryItemData.GetPrimaryStats( recipeOutcome ) );
		if( InventoryItemData.GetEquipmentArea( itemData ) == gamedataEquipmentArea.Weapon && RPGManager.IsItemIconic( recipeGameItemData ) )
		{
			outObject.additionalStats.Clear();
			outObject.FillDetailedStats( InventoryItemData.GetSecondaryStats( recipeOutcome ), true );
		}
		else
		{
			outObject.FillDetailedStats( InventoryItemData.GetSecondaryStats( recipeOutcome ) );
		}
		outObject.comparedQuality = InventoryItemData.GetComparedQuality( itemData );
		outObject.damageType = InventoryItemData.GetDamageType( itemData );
		outObject.m_HasPlayerSmartGunLink = InventoryItemData.HasPlayerSmartGunLink( itemData );
		outObject.m_PlayerLevel = InventoryItemData.GetPlayerLevel( itemData );
		outObject.m_PlayerStrenght = InventoryItemData.GetPlayerStrenght( itemData );
		outObject.m_PlayerStreetCred = InventoryItemData.GetPlayerStreetCred( itemData );
		outObject.inventoryItemData = itemData;
		attachmentsSize = InventoryItemData.GetAttachmentsSize( recipeOutcome );
		for( i = 0, limit = attachmentsSize; i < limit; i += 1 )
		{
			attachmentName = '';
			attachments = InventoryItemData.GetAttachment( recipeOutcome, i );
			if( !( InventoryItemData.IsEmpty( attachments.ItemData ) ) )
			{
				attachmentName = InventoryItemData.GetQuality( attachments.ItemData );
			}
			outObject.attachments.PushBack( attachmentName );
		}
		outObject.specialAbilities = InventoryItemData.GetAbilities( recipeOutcome );
		outObject.itemAttachments = InventoryItemData.GetAttachments( recipeOutcome );
		outObject.displayContext = InventoryTooltipDisplayContext.Crafting;
		outObject.inventoryItemData = recipeOutcome;
		outObject.overrideRarity = true;
		return outObject;
	}

	public function ToCollapsedVersion()
	{
		if( equipArea == gamedataEquipmentArea.Weapon )
		{
			description = "";
			additionalDescription = "";
		}
	}

	public function SetCyclingDots( selectedDot : Int32, numberOfDots : Int32 )
	{
		if( numberOfDots > 1 )
		{
			showCyclingDots = true;
			this.selectedCyclingDot = selectedDot;
			this.numberOfCyclingDots = numberOfDots;
		}
		else
		{
			showCyclingDots = false;
			this.selectedCyclingDot = 0;
			this.numberOfCyclingDots = 0;
		}
	}

	public function SetManager( manager : weak< UIInventoryItemsManager > )
	{
		managerRef = manager;
	}

	public function GetManager() : weak< UIInventoryItemsManager >
	{
		return managerRef;
	}

	public function GetStatsManagerHandle( optional refetch : Bool ) : UIInventoryItemStatsManager
	{
		var record : weak< UIStatsMap_Record >;
		if( statsManagerFetched && !( refetch ) )
		{
			return statsManager;
		}
		record = UIInventoryItemsManager.GetUIStatsMap( itemType );
		statsManager = UIInventoryItemStatsManager.Make( InventoryItemData.GetGameItemData( inventoryItemData ), record, managerRef );
		statsManagerFetched = true;
		return statsManager;
	}

	public function GetStatsManager( optional refetch : Bool ) : weak< UIInventoryItemStatsManager >
	{
		return GetStatsManagerHandle( refetch );
	}

}

struct InventoryTooltipData_StatData
{
	var statType : gamedataStatType;
	var statName : String;
	var minStatValue : Int32;
	var maxStatValue : Int32;
	var currentValue : Int32;
	var diffValue : Int32;
	var minStatValueF : Float;
	var maxStatValueF : Float;
	var currentValueF : Float;
	var diffValueF : Float;
	var state : EInventoryDataStatDisplayType;
}

enum EInventoryDataStatDisplayType
{
	CompareBar = 0,
	DisplayBar = 1,
	Value = 2,
}

struct InventoryTooltipData_QuickhackData
{
	var memorycost : Int32;
	var baseCost : Int32;
	var uploadTime : Float;
	var duration : Float;
	var cooldown : Float;
	var attackEffects : array< DamageEffectUIEntry >;
	var uploadTimeDiff : Float;
	var durationDiff : Float;
	var cooldownDiff : Float;
}

class InventoryTooltiData_GrenadeData
{
	var type : GrenadeDamageType;
	var range : Float;
	var duration : Float;
	var delay : Float;
	var damagePerTick : Float;
	var damageType : gamedataStatType;
	var detonationTimer : Float;
	var deliveryMethod : gamedataGrenadeDeliveryMethodType;
	var totalDamage : Float;
	var grenadeType : EGrenadeType;
}

class InventoryTooltipData_CyberdeckData
{
	var vehicleHackUnlocked : Bool;
	var viewingTooltipFromCyberwareMenu : Bool;
}

class InventoryTooltiData_GrenadeDamageData
{
	var statType : gamedataStatType;
	var value : Float;
}

class InventoryTooltiData_CyberwareUpgradeData
{
	var upgradeQuality : gamedataQuality;
	var isUpgradable : Bool;
	var isRipperdoc : Bool;
	var isUpgradeScreen : Bool;
	var playerComponents : Int32;
	var upgradeCost : CyberwareUpgradeCostData;

	public function IsValid() : Bool
	{
		if( ( upgradeCost.materialRecordID == T"" ) || ( upgradeCost.materialCount == 0 ) )
		{
			return false;
		}
		return true;
	}

	public static function Make( item : weak< UIInventoryItem >, player : weak< GameObject >, optional isUpgradeScreen : Bool ) : InventoryTooltiData_CyberwareUpgradeData
	{
		var upgradeComponentsItemData : weak< gameItemData >;
		var upgradeQuality : gamedataQuality;
		var upgradeItem : Item_Record;
		var upgradeCostData : CyberwareUpgradeCostData;
		var instance : InventoryTooltiData_CyberwareUpgradeData;
		instance = new InventoryTooltiData_CyberwareUpgradeData;
		instance.isUpgradable = RPGManager.CanUpgradeCyberware( player, item.GetID(), item.IsEquipped(), gamedataQuality.Invalid, upgradeQuality, upgradeItem, upgradeCostData, true );
		instance.isRipperdoc = true;
		instance.isUpgradeScreen = isUpgradeScreen;
		instance.upgradeCost = upgradeCostData;
		instance.upgradeQuality = upgradeQuality;
		upgradeComponentsItemData = RPGManager.GetItemData( player.GetGame(), player, ItemID.FromTDBID( upgradeCostData.materialRecordID ) );
		instance.playerComponents = upgradeComponentsItemData.GetQuantity();
		return instance;
	}

}

class DEBUG_IconErrorInfo
{
	var itemName : String;
	var innerItemName : String;
	var resolvedIconName : String;
	var errorMessage : String;
	var errorType : inkIconResult;
	var isManuallySet : Bool;
}

enum InventoryTooltipDisplayContext
{
	Default = 0,
	Attachment = 1,
	Crafting = 2,
	Upgrading = 3,
	HUD = 4,
	Vendor = 5,
}

enum GrenadeDamageType
{
	Normal = 0,
	DoT = 1,
	None = 2,
}

