class ItemTooltipController extends AGenericTooltipControllerWithDebug
{
	protected editable var m_itemNameText : inkTextRef;
	protected editable var m_itemRarityText : inkTextRef;
	protected editable var m_progressBar : inkWidgetRef;
	protected editable var m_recipeStatsTitle : inkTextRef;
	protected editable var m_categoriesWrapper : inkCompoundRef;
	protected editable var m_backgroundContainer : inkCompoundRef;
	protected editable var m_topContainer : inkCompoundRef;
	protected editable var m_headerContainer : inkCompoundRef;
	protected editable var m_headerWeaponContainer : inkCompoundRef;
	protected editable var m_headerItemContainer : inkCompoundRef;
	protected editable var m_headerGrenadeContainer : inkCompoundRef;
	protected editable var m_headerArmorContainer : inkCompoundRef;
	protected editable var m_primmaryStatsContainer : inkCompoundRef;
	protected editable var m_secondaryStatsContainer : inkCompoundRef;
	protected editable var m_recipeStatsContainer : inkCompoundRef;
	protected editable var m_recipeDamageTypesContainer : inkCompoundRef;
	protected editable var m_modsContainer : inkCompoundRef;
	protected editable var m_dedicatedModsContainer : inkCompoundRef;
	protected editable var m_descriptionContainer : inkCompoundRef;
	protected editable var m_craftedItemContainer : inkCompoundRef;
	protected editable var m_bottomContainer : inkCompoundRef;
	protected editable var m_primmaryStatsList : inkCompoundRef;
	protected editable var m_secondaryStatsList : inkCompoundRef;
	protected editable var m_recipeStatsTypesList : inkCompoundRef;
	protected editable var m_recipeDamageTypesList : inkCompoundRef;
	protected editable var m_modsList : inkCompoundRef;
	protected editable var m_dedicatedModsList : inkCompoundRef;
	protected editable var m_requiredLevelContainer : inkCompoundRef;
	protected editable var m_priceContainer : inkCompoundRef;
	protected editable var m_descriptionText : inkTextRef;
	protected editable var m_requireLevelText : inkTextRef;
	protected editable var m_priceText : inkTextRef;
	protected editable var m_dpsWrapper : inkWidgetRef;
	protected editable var m_dpsArrow : inkImageRef;
	protected editable var m_dpsText : inkTextRef;
	protected editable var m_nonLethalText : inkTextRef;
	protected editable var m_damagePerHitValue : inkTextRef;
	protected editable var m_attacksPerSecondValue : inkTextRef;
	protected editable var m_silencerPartWrapper : inkWidgetRef;
	protected editable var m_scopePartWrapper : inkWidgetRef;
	protected editable var m_craftedItemIcon : inkWidgetRef;
	protected editable var m_grenadeDamageTypeWrapper : inkWidgetRef;
	protected editable var m_grenadeDamageTypeIcon : inkImageRef;
	protected editable var m_grenadeRangeValue : inkTextRef;
	protected editable var m_grenadeRangeText : inkTextRef;
	protected editable var m_grenadeDeliveryLabel : inkTextRef;
	protected editable var m_grenadeDeliveryIcon : inkImageRef;
	protected editable var m_grenadeDamageStatWrapper : inkWidgetRef;
	protected editable var m_grenadeDamageStatLabel : inkTextRef;
	protected editable var m_grenadeDamageStatValue : inkTextRef;
	protected editable var m_armorStatArrow : inkImageRef;
	protected editable var m_armorStatLabel : inkTextRef;
	protected editable var m_quickhackStatWrapper : inkWidgetRef;
	protected editable var m_quickhackCostValue : inkTextRef;
	protected editable var m_quickhackDuration : inkTextRef;
	protected editable var m_quickhackCooldown : inkTextRef;
	protected editable var m_quickhackUpload : inkTextRef;
	protected editable var m_damageTypeWrapper : inkWidgetRef;
	protected editable var m_damageTypeIcon : inkImageRef;
	protected editable var m_equipedWrapper : inkWidgetRef;
	protected editable var m_itemTypeText : inkTextRef;
	protected editable var m_itemPreviewWrapper : inkWidgetRef;
	protected editable var m_itemPreviewIcon : inkImageRef;
	protected editable var m_itemPreviewIconicLines : inkWidgetRef;
	protected editable var m_itemWeightWrapper : inkWidgetRef;
	protected editable var m_itemWeightText : inkTextRef;
	protected editable var m_itemAmmoWrapper : inkWidgetRef;
	protected editable var m_itemAmmoText : inkTextRef;
	protected editable var m_itemRequirements : inkWidgetRef;
	protected editable var m_itemLevelRequirements : inkWidgetRef;
	protected editable var m_itemStrenghtRequirements : inkWidgetRef;
	protected editable var m_itemAttributeRequirements : inkWidgetRef;
	protected editable var m_itemSmartGunLinkRequirements : inkWidgetRef;
	protected editable var m_itemLevelRequirementsValue : inkTextRef;
	protected editable var m_itemStrenghtRequirementsValue : inkTextRef;
	protected editable var m_itemAttributeRequirementsText : inkTextRef;
	protected editable var m_weaponEvolutionWrapper : inkWidgetRef;
	protected editable var m_weaponEvolutionIcon : inkImageRef;
	protected editable var m_weaponEvolutionName : inkTextRef;
	protected editable var m_weaponEvolutionDescription : inkTextRef;
	protected editable var DEBUG_iconErrorWrapper : inkWidgetRef;
	protected editable var DEBUG_iconErrorText : inkTextRef;
	protected var m_data : InventoryTooltipData;
	private var m_animProxy : inkAnimProxy;
	private var m_playAnimation : Bool;

	public function SetData( const data : ref< ItemViewData > )
	{
		SetData( InventoryTooltipData.FromItemViewData( data ) );
	}

	public override function SetData( tooltipData : ATooltipData )
	{
		m_data = ( ( InventoryTooltipData )( tooltipData ) );
		UpdateLayout();
	}

	public function ForceNoEquipped()
	{
		m_data.isEquipped = false;
		UpdateLayout();
	}

	public override function Show()
	{
		super.Show();
		if( m_animProxy )
		{
			m_animProxy.Stop();
			m_animProxy = NULL;
		}
		if( m_playAnimation )
		{
			m_animProxy = PlayLibraryAnimationOnAutoSelectedTargets( 'show_item_tooltip', GetRootWidget() );
			m_animProxy.RegisterToCallback( inkanimEventType.OnFinish, this, 'OnShowAnimationFinished' );
		}
	}

	protected function UpdateLayout()
	{
		UpdateName();
		UpdateItemType();
		UpdateDamageType();
		UpdateRarity();
		UpdateHeader();
		UpdateParts();
		UpdateDPS();
		UpdateArmor();
		UpdateEvolutionDescription();
		UpdateSecondaryStats();
		UpdatemRecipeProperties();
		UpdatemRecipeDamageTypes();
		UpdateAttachments();
		UpdateRequirements();
		UpdateDescription();
		UpdateCraftedIcon();
		UpdatePrice();
		UpdateWeight();
		UpdateAmmo();
		UpdateQuickhackState();
		DEBUG_UpdateDebugInfo();
		UpdateIcon();
		UpdateEquipped();
		UpdateGrenadeStats();
		FixLines();
		inkWidgetRef.SetVisible( m_progressBar, false );
		inkCompoundRef.SetVisible( m_backgroundContainer, m_data.displayContext != InventoryTooltipDisplayContext.Crafting );
	}

	protected function UpdateItemType()
	{
		var finalType : String;
		var evolution : gamedataWeaponEvolution;
		evolution = gamedataWeaponEvolution.Invalid;
		if( InventoryItemData.GetEquipmentArea( m_data.inventoryItemData ) == gamedataEquipmentArea.Weapon )
		{
			evolution = RPGManager.GetWeaponEvolution( InventoryItemData.GetID( m_data.inventoryItemData ) );
		}
		finalType += GetLocalizedText( UIItemsHelper.GetItemTypeKey( GetItemType(), evolution ) );
		inkTextRef.SetText( m_itemTypeText, finalType );
	}

	protected function UpdateName()
	{
		var id : TweakDBID;
		var itemData : weak< gameItemData >;
		var finalItemName : String;
		var quantity : Int32;
		if( m_data.displayContext == InventoryTooltipDisplayContext.Crafting || m_data.displayContext == InventoryTooltipDisplayContext.Upgrading )
		{
			inkTextRef.SetVisible( m_itemNameText, false );
			return;
		}
		inkTextRef.SetVisible( m_itemNameText, true );
		id = ItemID.GetTDBID( InventoryItemData.GetID( m_data.inventoryItemData ) );
		if( !( TDBID.IsValid( id ) ) )
		{
			id = ItemID.GetTDBID( m_data.itemID );
		}
		itemData = InventoryItemData.GetGameItemData( m_data.inventoryItemData );
		quantity = InventoryItemData.GetQuantity( m_data.inventoryItemData );
		finalItemName = UIItemsHelper.GetTooltipItemName( id, itemData, m_data.itemName );
		if( quantity > 1 )
		{
			finalItemName += ( ( " [" + IntToString( quantity ) ) + "]" );
		}
		inkTextRef.SetText( m_itemNameText, finalItemName );
	}

	protected virtual function UpdateIcon()
	{
		var iconName : String;
		var emptyIcon : CName;
		var iconsNameResolver : IconsNameResolver;
		var localData : gameItemData;
		iconsNameResolver = IconsNameResolver.GetIconsNameResolver();
		localData = InventoryItemData.GetGameItemData( m_data.inventoryItemData );
		if( localData && localData.HasTag( 'Recipe' ) )
		{
			UpdateRecipeIcon();
			return;
		}
		if( m_data.isCraftable || m_data.displayContext == InventoryTooltipDisplayContext.Upgrading )
		{
			inkWidgetRef.SetVisible( m_itemPreviewWrapper, false );
			return;
		}
		inkWidgetRef.SetVisible( m_itemPreviewWrapper, true );
		if( m_data && IsStringValid( InventoryItemData.GetIconPath( m_data.inventoryItemData ) ) )
		{
			iconName = InventoryItemData.GetIconPath( m_data.inventoryItemData );
		}
		else
		{
			iconName = NameToString( iconsNameResolver.TranslateItemToIconName( ItemID.GetTDBID( InventoryItemData.GetID( m_data.inventoryItemData ) ), InventoryItemData.GetIconGender( m_data.inventoryItemData ) == ItemIconGender.Male ) );
		}
		if( iconName != "None" && iconName != "" )
		{
			inkImageRef.SetScale( m_itemPreviewIcon, ( ( InventoryItemData.GetEquipmentArea( m_data.inventoryItemData ) == gamedataEquipmentArea.Outfit ) ? ( Vector2( 0.5, 0.5 ) ) : ( Vector2( 1.0, 1.0 ) ) ) );
			InkImageUtils.RequestSetImage( this, m_itemPreviewIcon, "UIIcon." + iconName, 'OnIconCallback' );
		}
		else
		{
			emptyIcon = UIItemsHelper.GetSlotShadowIcon( TDBID.None(), GetItemType(), InventoryItemData.GetEquipmentArea( m_data.inventoryItemData ) );
			InkImageUtils.RequestSetImage( this, m_itemPreviewIcon, emptyIcon );
		}
	}

	protected virtual function UpdateRecipeIcon()
	{
		var iconName : String;
		var emptyIcon : CName;
		var iconsNameResolver : IconsNameResolver;
		var recipeRecord : weak< ItemRecipe_Record >;
		var craftingResult : weak< CraftingResult_Record >;
		var itemRecord : weak< Item_Record >;
		var itemScale : Vector2;
		iconsNameResolver = IconsNameResolver.GetIconsNameResolver();
		recipeRecord = TweakDBInterface.GetItemRecipeRecord( ItemID.GetTDBID( m_data.itemID ) );
		craftingResult = recipeRecord.CraftingResult();
		if( craftingResult )
		{
			itemRecord = craftingResult.Item();
		}
		if( itemRecord && IsStringValid( itemRecord.IconPath() ) )
		{
			iconName = itemRecord.IconPath();
		}
		else
		{
			iconName = NameToString( iconsNameResolver.TranslateItemToIconName( itemRecord.GetID(), InventoryItemData.GetIconGender( m_data.inventoryItemData ) == ItemIconGender.Male ) );
		}
		if( iconName != "None" && iconName != "" )
		{
			if( itemRecord.EquipArea().Type() == gamedataEquipmentArea.Outfit )
			{
				itemScale = Vector2( 0.5, 0.5 );
			}
			else if( itemRecord.EquipArea().Type() == gamedataEquipmentArea.Weapon )
			{
				itemScale = Vector2( 0.33000001, 0.33000001 );
			}
			else
			{
				itemScale = Vector2( 1.0, 1.0 );
			}
			inkImageRef.SetScale( m_itemPreviewIcon, itemScale );
			InkImageUtils.RequestSetImage( this, m_itemPreviewIcon, "UIIcon." + iconName, 'OnIconCallback' );
		}
		else
		{
			emptyIcon = UIItemsHelper.GetSlotShadowIcon( TDBID.None(), GetItemType(), InventoryItemData.GetEquipmentArea( m_data.inventoryItemData ) );
			InkImageUtils.RequestSetImage( this, m_itemPreviewIcon, emptyIcon );
		}
	}

	protected event OnIconCallback( e : iconAtlasCallbackData )
	{
		if( e.loadResult != inkIconResult.Success )
		{
			inkWidgetRef.SetVisible( m_itemPreviewWrapper, false );
		}
	}

	protected override function DEBUG_UpdateDebugInfo()
	{
		var craftableItems : array< weak< Item_Record > >;
		var recipeRecord : RecipeItem_Record;
		var resultText : String;
		var errorData : DEBUG_IconErrorInfo;
		var iconsNameResolver : IconsNameResolver;
		var itemRecordID : TweakDBID;
		iconsNameResolver = IconsNameResolver.GetIconsNameResolver();
		if( !( iconsNameResolver.IsInDebugMode() ) )
		{
			inkWidgetRef.SetVisible( DEBUG_iconErrorWrapper, false );
			return;
		}
		errorData = m_data.DEBUG_iconErrorInfo;
		inkWidgetRef.SetVisible( DEBUG_iconErrorWrapper, ( errorData != NULL ) || DEBUG_showDebug );
		if( DEBUG_showDebug )
		{
			resultText += " - itemID:\n";
			itemRecordID = ItemID.GetTDBID( InventoryItemData.GetID( m_data.inventoryItemData ) );
			resultText += TDBID.ToStringDEBUG( itemRecordID );
			OpenTweakDBRecordInVSCodeIfRequested( itemRecordID );
			if( InventoryItemData.GetGameItemData( m_data.inventoryItemData ).HasTag( 'Recipe' ) )
			{
				recipeRecord = TweakDBInterface.GetRecipeItemRecord( ItemID.GetTDBID( InventoryItemData.GetID( m_data.inventoryItemData ) ) );
				if( recipeRecord )
				{
					recipeRecord.CraftableItems( craftableItems );
					if( craftableItems.Size() > 0 )
					{
						resultText += "\n - inner itemID:\n";
						resultText += TDBID.ToStringDEBUG( craftableItems[ 0 ].GetID() );
					}
				}
			}
			inkTextRef.SetText( DEBUG_iconErrorText, resultText );
		}
		else
		{
			if( errorData != NULL )
			{
				resultText += ( ( "   ErrorType: " + EnumValueToString( "inkIconResult", ( ( Int32 )( errorData.errorType ) ) ) ) + "\n\n" );
				resultText += " - itemID:\n";
				resultText += errorData.itemName;
				if( IsStringValid( errorData.innerItemName ) )
				{
					resultText += "\n - inner itemID:\n";
					resultText += errorData.innerItemName;
				}
				if( errorData.isManuallySet )
				{
					resultText += "\n - resolved icon name (manually set):\n";
				}
				else
				{
					resultText += "\n - resolved icon name (auto generated):\n";
				}
				resultText += errorData.resolvedIconName;
				resultText += "\n - error message:\n";
				resultText += errorData.errorMessage;
				inkTextRef.SetText( DEBUG_iconErrorText, resultText );
			}
		}
	}

	protected function UpdateEquipped()
	{
		inkWidgetRef.SetVisible( m_equipedWrapper, m_data.isEquipped || m_data.displayContext == InventoryTooltipDisplayContext.Attachment );
	}

	protected function UpdateProgressBar() {}

	protected function UpdateQuickhackState()
	{
		var costParams : inkTextParams;
		var durationParams : inkTextParams;
		var uploadParams : inkTextParams;
		var cooldownParams : inkTextParams;
		if( GetItemType() == gamedataItemType.Prt_Program )
		{
			inkWidgetRef.SetVisible( m_quickhackStatWrapper, true );
			costParams = new inkTextParams;
			costParams.AddLocalizedString( "SEC", "LocKey#40730" );
			costParams.AddNumber( "VALUE", m_data.quickhackData.baseCost );
			( ( inkText )( inkTextRef.Get( m_quickhackCostValue ) ) ).SetLocalizedTextScript( "LocKey#40804", costParams );
			durationParams = new inkTextParams;
			durationParams.AddLocalizedString( "SEC", "LocKey#40730" );
			durationParams.AddNumber( "VALUE", m_data.quickhackData.duration );
			( ( inkText )( inkTextRef.Get( m_quickhackDuration ) ) ).SetLocalizedTextScript( "LocKey#40736", durationParams );
			cooldownParams = new inkTextParams;
			cooldownParams.AddLocalizedString( "SEC", "LocKey#40730" );
			cooldownParams.AddNumber( "VALUE", m_data.quickhackData.cooldown );
			( ( inkText )( inkTextRef.Get( m_quickhackCooldown ) ) ).SetLocalizedTextScript( "LocKey#40729", cooldownParams );
			uploadParams = new inkTextParams;
			uploadParams.AddLocalizedString( "SEC", "LocKey#40730" );
			uploadParams.AddNumber( "VALUE", m_data.quickhackData.uploadTime );
			( ( inkText )( inkTextRef.Get( m_quickhackUpload ) ) ).SetLocalizedTextScript( "LocKey#40737", uploadParams );
		}
		else
		{
			inkWidgetRef.SetVisible( m_quickhackStatWrapper, false );
		}
	}

	protected function UpdateGrenadeStats()
	{
		var tweakRecord : Grenade_Record;
		if( GetItemType() == gamedataItemType.Gad_Grenade )
		{
			inkWidgetRef.SetVisible( m_grenadeDamageStatWrapper, true );
			tweakRecord = TweakDBInterface.GetGrenadeRecord( ItemID.GetTDBID( InventoryItemData.GetID( m_data.inventoryItemData ) ) );
			UpdateGrenadeRange( tweakRecord );
			UpdateGrenadeDelivery( tweakRecord );
			UpdateGrenadeDamage( tweakRecord );
		}
		else
		{
			inkWidgetRef.SetVisible( m_grenadeDamageStatWrapper, false );
		}
	}

	protected function GetGranadeDamageFromStats() : InventoryTooltipData_StatData
	{
		var result : InventoryTooltipData_StatData;
		var stats : array< InventoryTooltipData_StatData >;
		stats = GetDamageStatsFromSecondayStats();
		if( stats.Size() > 0 )
		{
			result = stats[ 0 ];
		}
		else
		{
			result.statType = gamedataStatType.Invalid;
		}
		return result;
	}

	protected function GetArmorStatFromSecondaryStats() : InventoryTooltipData_StatData
	{
		var emptyResult : InventoryTooltipData_StatData;
		var i : Int32;
		var stats : array< InventoryTooltipData_StatData >;
		stats = GetSecondaryStatsData( m_data );
		for( i = 0; i < stats.Size(); i += 1 )
		{
			if( stats[ i ].statType == gamedataStatType.Armor )
			{
				return stats[ i ];
			}
		}
		return emptyResult;
	}

	protected function GetDamageStatsFromSecondayStats() : array< InventoryTooltipData_StatData >
	{
		var i : Int32;
		var stats : array< InventoryTooltipData_StatData >;
		var result : array< InventoryTooltipData_StatData >;
		stats = GetSecondaryStatsData( m_data );
		stats = FilterStatsWithValue( stats );
		for( i = 0; i < stats.Size(); i += 1 )
		{
			if( IsDamageStat( stats[ i ].statType ) )
			{
				stats[ i ].minStatValueF = stats[ i ].currentValueF * 0.89999998;
				stats[ i ].maxStatValueF = stats[ i ].currentValueF * 1.10000002;
				result.PushBack( stats[ i ] );
			}
		}
		return result;
	}

	public function ProcessDoTEffects( effects : weak< StatusEffect_Record > ) : array< DamageEffectUIEntry >
	{
		var i, j, k, l : Int32;
		var statusPackages : array< weak< GameplayLogicPackage_Record > >;
		var package : weak< GameplayLogicPackage_Record >;
		var effectors : array< weak< Effector_Record > >;
		var effector : weak< Effector_Record >;
		var effectorAsTriggerAttack : weak< TriggerAttackEffector_Record >;
		var effectorAsContinousAttack : weak< ContinuousAttackEffector_Record >;
		var attackRecord : weak< Attack_Record >;
		var attackRecordStatModifiers : array< weak< StatModifier_Record > >;
		var attackRecordStatModifier : weak< StatModifier_Record >;
		var durationRecord : weak< StatModifierGroup_Record >;
		var durationRecordStatModifiers : array< weak< StatModifier_Record > >;
		var durationStatModifier : weak< StatModifier_Record >;
		var durationConstantStat : weak< ConstantStatModifier_Record >;
		var constantMod : weak< ConstantStatModifier_Record >;
		var combinedMod : weak< CombinedStatModifier_Record >;
		var result : array< DamageEffectUIEntry >;
		var resultEntry : DamageEffectUIEntry;
		var durationStatToSkip : StatModifierGroup_Record;
		var continousDelayTime : Float;
		var isContinuous : Bool;
		durationStatToSkip = TweakDBInterface.GetStatModifierGroupRecord( T"BaseStatusEffect.BaseQuickHackDuration" );
		effects.Packages( statusPackages );
		durationRecord = effects.Duration();
		if( durationRecord != durationStatToSkip )
		{
			durationRecord.StatModifiers( durationRecordStatModifiers );
		}
		for( i = 0; i < statusPackages.Size(); i += 1 )
		{
			package = statusPackages[ i ];
			package.Effectors( effectors );
			for( j = 0; j < effectors.Size(); j += 1 )
			{
				effector = effectors[ j ];
				effectorAsTriggerAttack = ( ( weak< weak< TriggerAttackEffector_Record > > )( effector ) );
				attackRecord = NULL;
				if( effectorAsTriggerAttack )
				{
					attackRecord = effectorAsTriggerAttack.AttackRecord();
				}
				effectorAsContinousAttack = ( ( weak< weak< ContinuousAttackEffector_Record > > )( effector ) );
				if( effectorAsContinousAttack )
				{
					attackRecord = effectorAsContinousAttack.AttackRecord();
					continousDelayTime = effectorAsContinousAttack.DelayTime();
					isContinuous = true;
				}
				if( attackRecord )
				{
					for( l = 0; l < durationRecordStatModifiers.Size(); l += 1 )
					{
						durationStatModifier = durationRecordStatModifiers[ l ];
						if( durationStatModifier != durationStatToSkip )
						{
							if( durationStatModifier.StatType().StatType() == gamedataStatType.MaxDuration )
							{
								if( ( ( weak< weak< ConstantStatModifier_Record > > )( durationStatModifier ) ) )
								{
									durationConstantStat = ( ( weak< weak< ConstantStatModifier_Record > > )( durationStatModifier ) );
								}
							}
						}
					}
					attackRecord.StatModifiers( attackRecordStatModifiers );
					for( k = 0; k < attackRecordStatModifiers.Size(); k += 1 )
					{
						attackRecordStatModifier = attackRecordStatModifiers[ k ];
						constantMod = ( ( weak< weak< ConstantStatModifier_Record > > )( attackRecordStatModifier ) );
						combinedMod = ( ( weak< weak< CombinedStatModifier_Record > > )( attackRecordStatModifier ) );
						if( constantMod )
						{
							resultEntry = new DamageEffectUIEntry;
							resultEntry.valueStat = constantMod.StatType().StatType();
							resultEntry.targetStat = gamedataStatType.Invalid;
							resultEntry.displayType = DamageEffectDisplayType.Flat;
							resultEntry.valueToDisplay = constantMod.Value();
							resultEntry.effectorDuration = durationConstantStat.Value();
							resultEntry.effectorDelay = continousDelayTime;
							resultEntry.isContinuous = isContinuous;
							result.PushBack( resultEntry );
						}
						if( combinedMod )
						{
							resultEntry = new DamageEffectUIEntry;
							resultEntry.valueStat = combinedMod.StatType().StatType();
							resultEntry.targetStat = combinedMod.RefStat().StatType();
							resultEntry.displayType = DamageEffectDisplayType.Invalid;
							resultEntry.valueToDisplay = combinedMod.Value();
							resultEntry.effectorDuration = durationConstantStat.Value();
							resultEntry.effectorDelay = continousDelayTime;
							resultEntry.isContinuous = isContinuous;
							if( combinedMod.OpSymbol() == '*' && resultEntry.targetStat == gamedataStatType.Health )
							{
								resultEntry.displayType = DamageEffectDisplayType.TargetHealth;
								resultEntry.valueToDisplay = resultEntry.valueToDisplay * 100.0;
							}
							result.PushBack( resultEntry );
						}
					}
				}
			}
		}
		return result;
	}

	protected function GetDoTEffects( attackRecord : weak< Attack_Record > ) : array< DamageEffectUIEntry >
	{
		var i, j : Int32;
		var statusEffects : array< weak< StatusEffectAttackData_Record > >;
		var processedDoTEffects : array< DamageEffectUIEntry >;
		var result : array< DamageEffectUIEntry >;
		attackRecord.StatusEffects( statusEffects );
		for( i = 0; i < statusEffects.Size(); i += 1 )
		{
			processedDoTEffects = ProcessDoTEffects( statusEffects[ i ].StatusEffect() );
			for( j = 0; j < processedDoTEffects.Size(); j += 1 )
			{
				result.PushBack( processedDoTEffects[ j ] );
			}
		}
		return result;
	}

	protected function UpdateGrenadeDamage( tweakRecord : Grenade_Record )
	{
		var damageStat : InventoryTooltipData_StatData;
		var dotResultText : String;
		damageStat = GetGranadeDamageFromStats();
		inkWidgetRef.SetState( m_grenadeDamageTypeWrapper, UIItemsHelper.GetStateNameForStat( damageStat.statType ) );
		inkImageRef.SetTexturePart( m_grenadeDamageTypeIcon, UIItemsHelper.GetIconNameForStat( damageStat.statType ) );
		if( m_data.grenadeData.type == GrenadeDamageType.DoT )
		{
			dotResultText += IntToString( RoundF( m_data.grenadeData.totalDamage ) );
			dotResultText += " / ";
			dotResultText += IntToString( RoundF( m_data.grenadeData.duration ) );
			dotResultText += " ";
			dotResultText += GetLocalizedText( "UI-Quickhacks-Seconds" );
			inkTextRef.SetText( m_grenadeDamageStatValue, dotResultText );
			inkTextRef.SetText( m_grenadeDamageStatLabel, "Gameplay-RPG-Damage-DoT" );
			inkWidgetRef.SetVisible( m_grenadeDamageStatWrapper, true );
		}
		else if( damageStat.statType != gamedataStatType.Invalid )
		{
			inkTextRef.SetText( m_grenadeDamageStatValue, ( FloatToStringPrec( damageStat.minStatValueF, 0 ) + "-" ) + FloatToStringPrec( damageStat.maxStatValueF, 0 ) );
			inkTextRef.SetText( m_grenadeDamageStatLabel, "Gameplay-Scanning-Devices-GameplayActions-Damage" );
			inkWidgetRef.SetVisible( m_grenadeDamageStatWrapper, true );
		}
		else
		{
			inkWidgetRef.SetVisible( m_grenadeDamageStatWrapper, false );
		}
	}

	protected function UpdateGrenadeRange( tweakRecord : Grenade_Record )
	{
		var i, finalRangeDecimalPart : Int32;
		var finalRange : Float;
		var statModifier : array< weak< StatModifier_Record > >;
		var unitName : CName;
		var rangeTextParams : inkTextParams;
		var measurementUnit : EMeasurementUnit;
		rangeTextParams = new inkTextParams;
		measurementUnit = UILocalizationHelper.GetSystemBaseUnit();
		unitName = MeasurementUtils.GetUnitLocalizationKey( measurementUnit );
		finalRange = tweakRecord.AttackRadius();
		tweakRecord.StatModifiers( statModifier );
		for( i = statModifier.Size() - 1; i > 0; i -= 1 )
		{
			if( statModifier[ i ].StatType().StatType() == gamedataStatType.Range )
			{
				if( ( ( CombinedStatModifier_Record )( statModifier[ i ] ) ) )
				{
					finalRange = ( ( CombinedStatModifier_Record )( statModifier[ i ] ) ).Value();
				}
				if( ( ( ConstantStatModifier_Record )( statModifier[ i ] ) ) )
				{
					finalRange = ( ( ConstantStatModifier_Record )( statModifier[ i ] ) ).Value();
				}
			}
		}
		finalRange = MeasurementUtils.ValueUnitToUnit( finalRange, EMeasurementUnit.Meter, measurementUnit );
		finalRangeDecimalPart = RoundF( ( finalRange - ( ( Float )( RoundF( finalRange ) ) ) ) * 10.0 ) % 10;
		rangeTextParams.AddNumber( "value", FloorF( finalRange ) );
		rangeTextParams.AddNumber( "valueDecimalPart", finalRangeDecimalPart );
		rangeTextParams.AddString( "unit", GetLocalizedText( NameToString( unitName ) ) );
		inkTextRef.SetText( m_grenadeRangeText, ( ( finalRangeDecimalPart != 0 ) ? ( "UI-Tooltips-GrenadeRangeWithDecimalTemplate" ) : ( "UI-Tooltips-GrenadeRangeTemplate" ) ) );
		inkTextRef.SetTextParameters( m_grenadeRangeText, rangeTextParams );
	}

	protected function UpdateGrenadeDelivery( tweakRecord : Grenade_Record )
	{
		var deliveryMethod : gamedataGrenadeDeliveryMethodType;
		deliveryMethod = tweakRecord.DeliveryMethod().Type().Type();
		switch( deliveryMethod )
		{
			case gamedataGrenadeDeliveryMethodType.Regular:
				InkImageUtils.RequestSetImage( this, m_grenadeDeliveryIcon, "UIIcon." );
			inkTextRef.SetText( m_grenadeDeliveryLabel, GetLocalizedText( "Gameplay-Items-Stats-Delivery-Regular" ) );
			break;
			case gamedataGrenadeDeliveryMethodType.Sticky:
				InkImageUtils.RequestSetImage( this, m_grenadeDeliveryIcon, "UIIcon." );
			inkTextRef.SetText( m_grenadeDeliveryLabel, GetLocalizedText( "Gameplay-Items-Stats-Delivery-Sticky" ) );
			break;
			case gamedataGrenadeDeliveryMethodType.Homing:
				InkImageUtils.RequestSetImage( this, m_grenadeDeliveryIcon, "UIIcon." );
			inkTextRef.SetText( m_grenadeDeliveryLabel, GetLocalizedText( "Gameplay-Items-Stats-Delivery-Homing" ) );
			break;
		}
	}

	protected function UpdateAmmo()
	{
		if( m_data.equipArea == gamedataEquipmentArea.Weapon || m_data.equipArea == gamedataEquipmentArea.WeaponHeavy )
		{
			if( InventoryItemData.GetGameItemData( m_data.inventoryItemData ).HasTag( WeaponObject.GetMeleeWeaponTag() ) )
			{
				inkWidgetRef.SetVisible( m_itemAmmoWrapper, false );
			}
			else
			{
				inkWidgetRef.SetVisible( m_itemAmmoWrapper, true );
				inkTextRef.SetText( m_itemAmmoText, IntToString( InventoryItemData.GetAmmo( m_data.inventoryItemData ) ) );
			}
			if( GetItemType() == gamedataItemType.Gad_Grenade )
			{
				inkWidgetRef.SetVisible( m_itemAmmoWrapper, false );
			}
		}
		else
		{
			inkWidgetRef.SetVisible( m_itemAmmoWrapper, false );
		}
	}

	protected function UpdateDamageType()
	{
		inkWidgetRef.SetState( m_damageTypeWrapper, UIItemsHelper.GetStateNameForType( m_data.damageType ) );
		inkImageRef.SetTexturePart( m_damageTypeIcon, WeaponsUtils.GetDamageTypeIcon( m_data.damageType ) );
	}

	protected function UpdateRarity()
	{
		var quality : gamedataQuality;
		var rarityLabel, iconicLabel : String;
		var isIconic : Bool;
		if( m_data.displayContext == InventoryTooltipDisplayContext.Crafting || m_data.displayContext == InventoryTooltipDisplayContext.Upgrading )
		{
			inkTextRef.SetVisible( m_itemRarityText, false );
			return;
		}
		inkTextRef.SetVisible( m_itemRarityText, true );
		if( m_data.overrideRarity )
		{
			quality = UIItemsHelper.QualityNameToEnum( StringToName( m_data.quality ) );
		}
		else
		{
			quality = RPGManager.GetItemDataQuality( InventoryItemData.GetGameItemData( m_data.inventoryItemData ) );
		}
		isIconic = RPGManager.IsItemIconic( InventoryItemData.GetGameItemData( m_data.inventoryItemData ) );
		rarityLabel = GetLocalizedText( UIItemsHelper.QualityToDefaultString( quality ) );
		iconicLabel = GetLocalizedText( UIItemsHelper.QualityToDefaultString( gamedataQuality.Iconic ) );
		if( isIconic )
		{
			inkTextRef.SetState( m_itemNameText, 'Iconic' );
		}
		else
		{
			inkTextRef.SetState( m_itemNameText, UIItemsHelper.QualityEnumToName( quality ) );
		}
		inkTextRef.SetState( m_itemRarityText, UIItemsHelper.QualityEnumToName( quality ) );
		inkTextRef.SetText( m_itemRarityText, ( ( isIconic ) ? ( ( rarityLabel + " UpdateRarity2 " ) + iconicLabel ) : ( rarityLabel ) ) );
		inkCompoundRef.SetState( m_craftedItemContainer, UIItemsHelper.QualityEnumToName( quality ) );
		inkWidgetRef.SetVisible( m_itemPreviewIconicLines, isIconic );
	}

	protected function FixLines()
	{
		var i : Int32;
		var container : weak< inkCompoundWidget >;
		var lineWidget : weak< inkWidget >;
		var firstHidden : Bool;
		firstHidden = false;
		for( i = 0; i < inkCompoundRef.GetNumChildren( m_categoriesWrapper ); i += 1 )
		{
			container = ( ( inkCompoundWidget )( inkCompoundRef.GetWidgetByIndex( m_categoriesWrapper, i ) ) );
			if( container )
			{
				if( container.IsVisible() )
				{
					lineWidget = container.GetWidgetByPath( inkWidgetPath.Build( 'line' ) );
					if( lineWidget )
					{
						lineWidget.SetVisible( firstHidden );
						firstHidden = true;
					}
				}
			}
		}
	}

	protected function UpdateHeader()
	{
		var itemRecord : Item_Record;
		var armorStat : InventoryTooltipData_StatData;
		itemRecord = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( m_data.itemID ) );
		inkCompoundRef.SetVisible( m_headerContainer, true );
		inkCompoundRef.SetVisible( m_headerItemContainer, true );
		inkCompoundRef.SetVisible( m_headerWeaponContainer, false );
		inkCompoundRef.SetVisible( m_headerGrenadeContainer, false );
		inkCompoundRef.SetVisible( m_headerArmorContainer, false );
		if( m_data.equipArea == gamedataEquipmentArea.Weapon || m_data.equipArea == gamedataEquipmentArea.WeaponHeavy )
		{
			inkCompoundRef.SetVisible( m_headerWeaponContainer, true );
		}
		else if( itemRecord.ItemType().Type() == gamedataItemType.Gad_Grenade )
		{
			inkCompoundRef.SetVisible( m_headerGrenadeContainer, true );
		}
		else if( itemRecord.ItemCategory().Type() == gamedataItemCategory.Clothing )
		{
			armorStat = GetArmorStatFromSecondaryStats();
			if( armorStat.statType == gamedataStatType.Armor )
			{
				inkCompoundRef.SetVisible( m_headerArmorContainer, true );
			}
		}
	}

	protected function GetArrowWrapperState( diffValue : Float ) : CName
	{
		if( diffValue < 0.0 )
		{
			return 'Worse';
		}
		else if( diffValue > 0.0 )
		{
			return 'Better';
		}
		return 'Default';
	}

	protected function UpdateParts()
	{
		var i : Int32;
		var silencerAttachmentSlot, scopeAttachmentSlot : InventoryItemAttachments;
		var attachmentsSize : Int32;
		var attachments : InventoryItemAttachments;
		attachmentsSize = InventoryItemData.GetAttachmentsSize( m_data.inventoryItemData );
		for( i = 0; i < attachmentsSize; i += 1 )
		{
			attachments = InventoryItemData.GetAttachment( m_data.inventoryItemData, i );
			if( attachments.SlotID == T"AttachmentSlots.PowerModule" )
			{
				silencerAttachmentSlot = attachments;
			}
			else if( attachments.SlotID == T"AttachmentSlots.Scope" )
			{
				scopeAttachmentSlot = attachments;
			}
		}
		if( TDBID.IsValid( silencerAttachmentSlot.SlotID ) )
		{
			inkWidgetRef.SetVisible( m_silencerPartWrapper, true );
			inkWidgetRef.SetState( m_silencerPartWrapper, ( ( InventoryItemData.IsEmpty( silencerAttachmentSlot.ItemData ) ) ? ( 'Empty' ) : ( 'Default' ) ) );
		}
		else
		{
			inkWidgetRef.SetVisible( m_silencerPartWrapper, false );
		}
		if( TDBID.IsValid( scopeAttachmentSlot.SlotID ) )
		{
			inkWidgetRef.SetVisible( m_scopePartWrapper, true );
			inkWidgetRef.SetState( m_scopePartWrapper, ( ( InventoryItemData.IsEmpty( scopeAttachmentSlot.ItemData ) ) ? ( 'Empty' ) : ( 'Default' ) ) );
		}
		else
		{
			inkWidgetRef.SetVisible( m_scopePartWrapper, false );
		}
	}

	protected function UpdateArmor()
	{
		var i : Int32;
		var armor, armorDiffValue : Float;
		var armorParams : inkTextParams;
		for( i = 0; i < m_data.primaryStats.Size(); i += 1 )
		{
			if( m_data.primaryStats[ i ].statType == gamedataStatType.Armor )
			{
				armor = m_data.primaryStats[ i ].currentValueF;
				armorDiffValue = m_data.primaryStats[ i ].diffValueF;
			}
		}
		if( armorDiffValue > 0.0 )
		{
			inkImageRef.SetBrushMirrorType( m_armorStatArrow, inkBrushMirrorType.NoMirror );
		}
		else if( armorDiffValue < 0.0 )
		{
			inkImageRef.SetBrushMirrorType( m_armorStatArrow, inkBrushMirrorType.Vertical );
		}
		inkImageRef.SetState( m_armorStatArrow, GetArrowWrapperState( armorDiffValue ) );
		inkImageRef.SetVisible( m_armorStatArrow, armorDiffValue != 0.0 );
		armorParams = new inkTextParams;
		armorParams.AddNumber( "value", FloorF( armor ) );
		armorParams.AddNumber( "valueDecimalPart", RoundF( ( armor - ( ( Float )( RoundF( armor ) ) ) ) * 10.0 ) % 10 );
		inkTextRef.SetTextParameters( m_armorStatLabel, armorParams );
	}

	protected function UpdateEvolutionDescription()
	{
		var evolution : gamedataWeaponEvolution;
		evolution = gamedataWeaponEvolution.Invalid;
		if( InventoryItemData.GetEquipmentArea( m_data.inventoryItemData ) == gamedataEquipmentArea.Weapon )
		{
			evolution = RPGManager.GetWeaponEvolution( InventoryItemData.GetID( m_data.inventoryItemData ) );
		}
		inkTextRef.SetVisible( m_nonLethalText, evolution == gamedataWeaponEvolution.Blunt );
		inkWidgetRef.SetVisible( m_weaponEvolutionWrapper, evolution != gamedataWeaponEvolution.Invalid );
		switch( evolution )
		{
			case gamedataWeaponEvolution.Power:
				inkImageRef.SetTexturePart( m_weaponEvolutionIcon, 'ico_power' );
			inkTextRef.SetText( m_weaponEvolutionName, "LocKey#54118" );
			inkTextRef.SetText( m_weaponEvolutionDescription, "LocKey#54117" );
			break;
			case gamedataWeaponEvolution.Smart:
				inkImageRef.SetTexturePart( m_weaponEvolutionIcon, 'ico_smart' );
			inkTextRef.SetText( m_weaponEvolutionName, "LocKey#54119" );
			inkTextRef.SetText( m_weaponEvolutionDescription, "LocKey#54120" );
			break;
			case gamedataWeaponEvolution.Tech:
				inkImageRef.SetTexturePart( m_weaponEvolutionIcon, 'ico_tech' );
			inkTextRef.SetText( m_weaponEvolutionName, "LocKey#54121" );
			inkTextRef.SetText( m_weaponEvolutionDescription, "LocKey#54122" );
			break;
			case gamedataWeaponEvolution.Blunt:
				inkImageRef.SetTexturePart( m_weaponEvolutionIcon, 'ico_blunt' );
			inkTextRef.SetText( m_weaponEvolutionName, "LocKey#77968" );
			inkTextRef.SetText( m_weaponEvolutionDescription, "LocKey#77969 " );
			break;
			case gamedataWeaponEvolution.Blade:
				inkImageRef.SetTexturePart( m_weaponEvolutionIcon, 'ico_blades' );
			inkTextRef.SetText( m_weaponEvolutionName, "LocKey#77957" );
			inkTextRef.SetText( m_weaponEvolutionDescription, "LocKey#77960" );
			break;
			case gamedataWeaponEvolution.Throwable:
				inkImageRef.SetTexturePart( m_weaponEvolutionIcon, 'ico_blades' );
			inkTextRef.SetText( m_weaponEvolutionName, "LocKey#91802" );
			inkTextRef.SetText( m_weaponEvolutionDescription, "LocKey#91803" );
			break;
		}
	}

	protected function UpdateDPS()
	{
		var i : Int32;
		var dps : Float;
		var itemRecord : Item_Record;
		var projectilesPerShot, damagePerHit, damagePerHitMin, damagePerHitMax, attacksPerSecond, dpsDiffValue : Float;
		var dpsParams, damageParams, attackPerSecondParams : inkTextParams;
		var isShotgun, divideAttacksByPellets : Bool;
		dps = -1.0;
		itemRecord = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( m_data.itemID ) );
		dpsParams = new inkTextParams;
		damageParams = new inkTextParams;
		attackPerSecondParams = new inkTextParams;
		for( i = 0; i < m_data.primaryStats.Size(); i += 1 )
		{
			if( m_data.primaryStats[ i ].statType == gamedataStatType.EffectiveDPS )
			{
				dps = m_data.primaryStats[ i ].currentValueF;
				dpsDiffValue = m_data.primaryStats[ i ].diffValueF;
			}
		}
		inkWidgetRef.SetState( m_dpsWrapper, GetArrowWrapperState( dpsDiffValue ) );
		inkWidgetRef.SetVisible( m_dpsWrapper, dps >= 0.0 );
		inkImageRef.SetVisible( m_dpsArrow, dpsDiffValue != 0.0 );
		if( dpsDiffValue > 0.0 )
		{
			inkImageRef.SetBrushMirrorType( m_dpsArrow, inkBrushMirrorType.NoMirror );
		}
		else if( dpsDiffValue < 0.0 )
		{
			inkImageRef.SetBrushMirrorType( m_dpsArrow, inkBrushMirrorType.Vertical );
		}
		dpsParams.AddNumber( "value", FloorF( dps ) );
		dpsParams.AddNumber( "valueDecimalPart", RoundF( ( dps - ( ( Float )( RoundF( dps ) ) ) ) * 10.0 ) % 10 );
		inkTextRef.SetTextParameters( m_dpsText, dpsParams );
		projectilesPerShot = InventoryItemData.GetGameItemData( m_data.inventoryItemData ).GetStatValueByType( gamedataStatType.ProjectilesPerShot );
		attacksPerSecond = InventoryItemData.GetGameItemData( m_data.inventoryItemData ).GetStatValueByType( gamedataStatType.AttacksPerSecond );
		divideAttacksByPellets = TweakDBInterface.GetBool( ItemID.GetTDBID( m_data.itemID ) + T".divideAttacksByPelletsOnUI", false ) && ( projectilesPerShot > 0.0 );
		attackPerSecondParams.AddString( "value", FloatToStringPrec( ( ( divideAttacksByPellets ) ? ( attacksPerSecond / projectilesPerShot ) : ( attacksPerSecond ) ), 2 ) );
		inkTextRef.SetLocalizedTextScript( m_attacksPerSecondValue, "UI-Tooltips-AttacksPerSecond", attackPerSecondParams );
		damagePerHit = InventoryItemData.GetGameItemData( m_data.inventoryItemData ).GetStatValueByType( gamedataStatType.EffectiveDamagePerHit );
		if( InventoryItemData.GetGameItemData( m_data.inventoryItemData ).HasTag( 'Melee' ) )
		{
			inkTextRef.SetText( m_damagePerHitValue, "UI-Tooltips-DamagePerHitMeleeTemplate" );
			damageParams.AddString( "value", IntToString( RoundF( damagePerHit ) ) );
			inkTextRef.SetTextParameters( m_damagePerHitValue, damageParams );
			return;
		}
		damagePerHitMin = InventoryItemData.GetGameItemData( m_data.inventoryItemData ).GetStatValueByType( gamedataStatType.EffectiveDamagePerHitMin );
		damagePerHitMax = InventoryItemData.GetGameItemData( m_data.inventoryItemData ).GetStatValueByType( gamedataStatType.EffectiveDamagePerHitMax );
		damageParams.AddString( "value", IntToString( RoundF( damagePerHitMin ) ) );
		damageParams.AddString( "valueMax", IntToString( RoundF( damagePerHitMax ) ) );
		isShotgun = itemRecord.ItemType().Type() == gamedataItemType.Wea_Shotgun || itemRecord.ItemType().Type() == gamedataItemType.Wea_ShotgunDual;
		if( isShotgun && ( projectilesPerShot > 0.0 ) )
		{
			inkTextRef.SetText( m_damagePerHitValue, "UI-Tooltips-DamagePerHitWithMultiplierTemplate" );
			damageParams.AddString( "multiplier", IntToString( RoundF( projectilesPerShot ) ) );
		}
		else
		{
			inkTextRef.SetText( m_damagePerHitValue, "UI-Tooltips-DamagePerHitTemplate" );
		}
		inkTextRef.SetTextParameters( m_damagePerHitValue, damageParams );
	}

	protected function UpdatePrimmaryStats()
	{
		var i : Int32;
		var stat : InventoryTooltipData_StatData;
		var controller : ItemTooltipStatController;
		if( m_data.primaryStats.Size() > 0 )
		{
			while( inkCompoundRef.GetNumChildren( m_primmaryStatsList ) > m_data.primaryStats.Size() )
			{
				inkCompoundRef.RemoveChildByIndex( m_primmaryStatsList, 0 );
			}
			while( inkCompoundRef.GetNumChildren( m_primmaryStatsList ) < m_data.primaryStats.Size() )
			{
				SpawnFromLocal( inkCompoundRef.Get( m_primmaryStatsList ), 'itemTooltipPrimmaryStatTest' );
			}
			for( i = 0; i < m_data.primaryStats.Size(); i += 1 )
			{
				stat = m_data.primaryStats[ i ];
				controller = ( ( ItemTooltipStatController )( inkCompoundRef.GetWidgetByIndex( m_primmaryStatsList, i ).GetController() ) );
				controller.SetData( stat );
			}
			inkCompoundRef.SetVisible( m_primmaryStatsContainer, true );
		}
		else
		{
			inkCompoundRef.SetVisible( m_primmaryStatsContainer, false );
		}
	}

	protected function UpdatemRecipeDamageTypes()
	{
		var i : Int32;
		var stat : InventoryTooltipData_StatData;
		var controller : ItemTooltipStatController;
		if( m_data.randomDamageTypes.Size() > 0 )
		{
			while( inkCompoundRef.GetNumChildren( m_recipeDamageTypesList ) > m_data.randomDamageTypes.Size() )
			{
				inkCompoundRef.RemoveChildByIndex( m_recipeDamageTypesList, 0 );
			}
			while( inkCompoundRef.GetNumChildren( m_recipeDamageTypesList ) < m_data.randomDamageTypes.Size() )
			{
				SpawnFromLocal( inkCompoundRef.Get( m_recipeDamageTypesList ), 'itemTooltipSecondaryStatTest' );
			}
			for( i = 0; i < m_data.randomDamageTypes.Size(); i += 1 )
			{
				stat = m_data.randomDamageTypes[ i ];
				controller = ( ( ItemTooltipStatController )( inkCompoundRef.GetWidgetByIndex( m_recipeDamageTypesList, i ).GetController() ) );
				controller.SetData( stat );
			}
			inkCompoundRef.SetVisible( m_recipeDamageTypesContainer, true );
		}
		else
		{
			inkCompoundRef.SetVisible( m_recipeDamageTypesContainer, false );
		}
	}

	protected function UpdatemRecipeProperties()
	{
		var controller : ItemRandomizedStatsController;
		var widget : weak< inkWidget >;
		var statsQuantityParams : inkTextParams;
		if( m_data.recipeAdditionalStats.Size() > 0 )
		{
			statsQuantityParams = new inkTextParams;
			statsQuantityParams.AddString( "value", IntToString( m_data.randomizedStatQuantity ) );
			inkTextRef.SetLocalizedText( m_recipeStatsTitle, 'UI-Tooltips-RandomStatsNumber', statsQuantityParams );
			if( inkCompoundRef.GetNumChildren( m_recipeStatsTypesList ) == 0 )
			{
				widget = SpawnFromLocal( inkCompoundRef.Get( m_recipeStatsTypesList ), 'itemTooltipRecipeStat' );
			}
			else
			{
				widget = inkCompoundRef.GetWidgetByIndex( m_recipeStatsTypesList, 0 );
			}
			controller = ( ( ItemRandomizedStatsController )( widget.GetController() ) );
			controller.SetData( m_data.recipeAdditionalStats );
			inkCompoundRef.SetVisible( m_recipeStatsContainer, true );
		}
		else
		{
			inkCompoundRef.SetVisible( m_recipeStatsContainer, false );
		}
	}

	protected function GetSecondaryStatsData( data : InventoryTooltipData ) : array< InventoryTooltipData_StatData >
	{
		var i, j : Int32;
		var alreadyAdded : Bool;
		var stats : array< InventoryTooltipData_StatData >;
		for( i = 0; i < data.additionalStats.Size(); i += 1 )
		{
			alreadyAdded = false;
			for( j = 0; j < stats.Size(); j += 1 )
			{
				if( stats[ j ].statType == data.additionalStats[ i ].statType )
				{
					alreadyAdded = true;
					break;
				}
			}
			if( !( alreadyAdded ) )
			{
				stats.PushBack( data.additionalStats[ i ] );
			}
		}
		for( i = 0; i < data.comparedStats.Size(); i += 1 )
		{
			alreadyAdded = false;
			for( j = 0; j < stats.Size(); j += 1 )
			{
				if( stats[ j ].statType == data.comparedStats[ i ].statType )
				{
					alreadyAdded = true;
					break;
				}
			}
			if( !( alreadyAdded ) )
			{
				stats.PushBack( data.comparedStats[ i ] );
			}
		}
		return stats;
	}

	private function FilterStatsWithValue( const stats : ref< array< InventoryTooltipData_StatData > > ) : array< InventoryTooltipData_StatData >
	{
		var i : Int32;
		var statTweakID : TweakDBID;
		var result : array< InventoryTooltipData_StatData >;
		for( i = 0; i < stats.Size(); i += 1 )
		{
			statTweakID = TDBID.Create( "BaseStats." + EnumValueToString( "gamedataStatType", ( ( Int32 )( stats[ i ].statType ) ) ) );
			if( TweakDBInterface.GetBool( statTweakID + T".roundValue", false ) )
			{
				if( stats[ i ].currentValue != 0 )
				{
					result.PushBack( stats[ i ] );
				}
				continue;
			}
			if( AbsF( stats[ i ].currentValueF ) > 0.001 )
			{
				result.PushBack( stats[ i ] );
			}
		}
		return result;
	}

	private function IsDamageStat( stat : gamedataStatType ) : Bool
	{
		switch( stat )
		{
			case gamedataStatType.BaseDamage:
			case gamedataStatType.PhysicalDamage:
			case gamedataStatType.ChemicalDamage:
			case gamedataStatType.ElectricDamage:
			case gamedataStatType.ThermalDamage:
				return true;
			default:
				return false;
		}
		return false;
	}

	private function ShouldDisplayGrenadeStat( const stat : ref< InventoryTooltipData_StatData > ) : Bool
	{
		return stat.statType != gamedataStatType.Range && !( IsDamageStat( stat.statType ) );
	}

	private function FilterGrenadeStats( const stats : ref< array< InventoryTooltipData_StatData > > ) : array< InventoryTooltipData_StatData >
	{
		var i : Int32;
		var result : array< InventoryTooltipData_StatData >;
		if( GetItemType() != gamedataItemType.Gad_Grenade )
		{
			return stats;
		}
		for( i = 0; i < stats.Size(); i += 1 )
		{
			if( ShouldDisplayGrenadeStat( stats[ i ] ) )
			{
				result.PushBack( stats[ i ] );
			}
		}
		return result;
	}

	private function FilterArmorStat( const stats : ref< array< InventoryTooltipData_StatData > > ) : array< InventoryTooltipData_StatData >
	{
		var i : Int32;
		var result : array< InventoryTooltipData_StatData >;
		for( i = 0; i < stats.Size(); i += 1 )
		{
			if( stats[ i ].statType != gamedataStatType.Armor )
			{
				result.PushBack( stats[ i ] );
			}
		}
		return result;
	}

	protected function UpdateSecondaryStats()
	{
		var i : Int32;
		var stats : array< InventoryTooltipData_StatData >;
		var controller : ItemTooltipStatController;
		var tempWidget : weak< inkWidget >;
		var shouldDisplayStats : Bool;
		var itemRecord : weak< Item_Record >;
		if( m_data.displayContext == InventoryTooltipDisplayContext.HUD && m_data.equipArea == gamedataEquipmentArea.Weapon )
		{
			inkCompoundRef.SetVisible( m_secondaryStatsContainer, false );
			return;
		}
		itemRecord = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( m_data.itemID ) );
		stats = GetSecondaryStatsData( m_data );
		stats = FilterStatsWithValue( stats );
		shouldDisplayStats = stats.Size() > 0;
		stats = FilterGrenadeStats( stats );
		if( itemRecord.ItemCategory().Type() != gamedataItemCategory.Part && itemRecord.ItemCategory().Type() != gamedataItemCategory.WeaponMod )
		{
			stats = FilterArmorStat( stats );
		}
		inkCompoundRef.RemoveAllChildren( m_secondaryStatsList );
		if( m_data.displayContext == InventoryTooltipDisplayContext.Crafting && itemRecord.EquipArea().Type() == gamedataEquipmentArea.Weapon )
		{
			return;
		}
		if( stats.Size() > 0 )
		{
			for( i = 0; i < stats.Size(); i += 1 )
			{
				tempWidget = SpawnFromLocal( inkCompoundRef.Get( m_secondaryStatsList ), 'itemTooltipSecondaryStatTest' );
				controller = ( ( ItemTooltipStatController )( tempWidget.GetController() ) );
				controller.SetData( stats[ i ] );
			}
			inkCompoundRef.SetVisible( m_secondaryStatsContainer, true );
		}
		else
		{
			inkCompoundRef.SetVisible( m_secondaryStatsContainer, shouldDisplayStats );
		}
	}

	protected function UpdateAttachments()
	{
		var i : Int32;
		var genericMods, dedicatedMods : array< InventoryItemAttachments >;
		for( i = 0; i < m_data.itemAttachments.Size(); i += 1 )
		{
			switch( m_data.itemAttachments[ i ].SlotType )
			{
				case InventoryItemAttachmentType.Generic:
					genericMods.PushBack( m_data.itemAttachments[ i ] );
				break;
				case InventoryItemAttachmentType.Dedicated:
					dedicatedMods.PushBack( m_data.itemAttachments[ i ] );
				break;
			}
		}
		if( !( m_data.displayContext == InventoryTooltipDisplayContext.HUD && m_data.equipArea == gamedataEquipmentArea.Weapon ) )
		{
			UpdateMods( genericMods );
		}
		else
		{
			inkCompoundRef.SetVisible( m_modsContainer, false );
		}
		UpdateDedicatedMods( dedicatedMods );
	}

	protected function UpdateMods( const mods : ref< array< InventoryItemAttachments > > )
	{
		var dataPackagesSize, attachmentsSize, totalModsSize, i : Int32;
		var controller : ItemTooltipModController;
		var itemRecord : Item_Record;
		var dataPackages : array< weak< GameplayLogicPackage_Record > >;
		var uiDataPackage : weak< GameplayLogicPackageUIData_Record >;
		var dataPackagesToDisplay : array< weak< GameplayLogicPackageUIData_Record > >;
		var innerItemData : InnerItemData;
		itemRecord = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( m_data.itemID ) );
		itemRecord.OnEquip( dataPackages );
		for( i = 0; i < dataPackages.Size(); i += 1 )
		{
			uiDataPackage = dataPackages[ i ].UIData();
			if( uiDataPackage && IsStringValid( uiDataPackage.LocalizedDescription() ) )
			{
				dataPackagesToDisplay.PushBack( uiDataPackage );
			}
		}
		dataPackages.Clear();
		itemRecord.OnAttach( dataPackages );
		for( i = 0; i < dataPackages.Size(); i += 1 )
		{
			uiDataPackage = dataPackages[ i ].UIData();
			if( uiDataPackage && IsStringValid( uiDataPackage.LocalizedDescription() ) )
			{
				dataPackagesToDisplay.PushBack( uiDataPackage );
			}
		}
		dataPackagesSize = dataPackagesToDisplay.Size();
		attachmentsSize = mods.Size();
		totalModsSize = dataPackagesSize + attachmentsSize;
		if( totalModsSize > 0 )
		{
			while( inkCompoundRef.GetNumChildren( m_modsList ) > totalModsSize )
			{
				inkCompoundRef.RemoveChildByIndex( m_modsList, 0 );
			}
			while( inkCompoundRef.GetNumChildren( m_modsList ) < totalModsSize )
			{
				SpawnFromLocal( inkCompoundRef.Get( m_modsList ), 'itemTooltipMod' );
			}
			for( i = 0; i < dataPackagesSize; i += 1 )
			{
				controller = ( ( ItemTooltipModController )( inkCompoundRef.GetWidgetByIndex( m_modsList, i ).GetController() ) );
				if( m_data.displayContext == InventoryTooltipDisplayContext.Attachment )
				{
					innerItemData = InnerItemData();
					m_data.parentItemData.GetItemPart( innerItemData, m_data.slotID );
					controller.SetData( dataPackagesToDisplay[ i ], innerItemData );
				}
				else
				{
					controller.SetData( dataPackagesToDisplay[ i ], InventoryItemData.GetGameItemData( m_data.inventoryItemData ) );
					controller.HideDotIndicator();
				}
			}
			if( ( attachmentsSize > 0 ) || ( dataPackagesSize > 0 ) )
			{
				for( i = 0; i < attachmentsSize; i += 1 )
				{
					controller = ( ( ItemTooltipModController )( inkCompoundRef.GetWidgetByIndex( m_modsList, i + dataPackagesSize ).GetController() ) );
					controller.SetData( mods[ i ] );
				}
			}
			inkCompoundRef.SetVisible( m_modsContainer, true );
		}
		else
		{
			inkCompoundRef.SetVisible( m_modsContainer, false );
		}
	}

	protected function UpdateDedicatedMods( const mods : ref< array< InventoryItemAttachments > > )
	{
		var i : Int32;
		var controller : ItemTooltipModController;
		var modsToShow : array< InventoryItemAttachments >;
		for( i = 0; i < mods.Size(); i += 1 )
		{
			if( !( InventoryItemData.IsEmpty( mods[ i ].ItemData ) ) )
			{
				modsToShow.PushBack( mods[ i ] );
			}
		}
		inkCompoundRef.SetVisible( m_dedicatedModsContainer, modsToShow.Size() > 0 );
		while( inkCompoundRef.GetNumChildren( m_dedicatedModsList ) > modsToShow.Size() )
		{
			inkCompoundRef.RemoveChildByIndex( m_dedicatedModsList, 0 );
		}
		while( inkCompoundRef.GetNumChildren( m_dedicatedModsList ) < modsToShow.Size() )
		{
			SpawnFromLocal( inkCompoundRef.Get( m_dedicatedModsList ), 'itemTooltipMod' );
		}
		for( i = 0; i < modsToShow.Size(); i += 1 )
		{
			controller = ( ( ItemTooltipModController )( inkCompoundRef.GetWidgetByIndex( m_dedicatedModsList, i ).GetController() ) );
			controller.SetData( modsToShow[ i ] );
			controller.HideDotIndicator();
		}
	}

	protected function UpdateRequirements()
	{
		var textParams : inkTextParams;
		var statRecord : Stat_Record;
		var strenghtValue : Int32;
		var requirement : SItemStackRequirementData;
		var statsValue : Float;
		inkWidgetRef.SetVisible( m_itemRequirements, false );
		inkWidgetRef.SetVisible( m_itemLevelRequirements, false );
		inkWidgetRef.SetVisible( m_itemStrenghtRequirements, false );
		inkWidgetRef.SetVisible( m_itemSmartGunLinkRequirements, false );
		inkWidgetRef.SetVisible( m_itemAttributeRequirements, false );
		if( RPGManager.HasSmartLinkRequirement( InventoryItemData.GetGameItemData( m_data.inventoryItemData ) ) && !( m_data.m_HasPlayerSmartGunLink ) )
		{
			inkWidgetRef.SetVisible( m_itemRequirements, true );
			inkWidgetRef.SetVisible( m_itemSmartGunLinkRequirements, true );
		}
		statsValue = InventoryItemData.GetGameItemData( m_data.inventoryItemData ).GetStatValueByType( gamedataStatType.Strength );
		if( ( statsValue > 0.0 ) && ( m_data.m_PlayerStrenght < RoundF( statsValue ) ) )
		{
			inkWidgetRef.SetVisible( m_itemRequirements, true );
			inkWidgetRef.SetVisible( m_itemStrenghtRequirements, true );
			textParams = new inkTextParams;
			statRecord = RPGManager.GetStatRecord( gamedataStatType.Strength );
			textParams.AddString( "statName", GetLocalizedText( UILocalizationHelper.GetStatNameLockey( statRecord ) ) );
			strenghtValue = RoundF( statsValue );
			textParams.AddNumber( "statValue", strenghtValue );
			inkTextRef.SetLocalizedText( m_itemStrenghtRequirementsValue, StringToName( GetLocalizedText( "LocKey#78420" ) ), textParams );
		}
		statsValue = InventoryItemData.GetGameItemData( m_data.inventoryItemData ).GetStatValueByType( gamedataStatType.Reflexes );
		if( ( statsValue > 0.0 ) && ( m_data.m_PlayerReflexes < RoundF( statsValue ) ) )
		{
			inkWidgetRef.SetVisible( m_itemRequirements, true );
			inkWidgetRef.SetVisible( m_itemStrenghtRequirements, true );
			textParams = new inkTextParams;
			statRecord = RPGManager.GetStatRecord( gamedataStatType.Reflexes );
			textParams.AddString( "statName", GetLocalizedText( UILocalizationHelper.GetStatNameLockey( statRecord ) ) );
			strenghtValue = RoundF( statsValue );
			textParams.AddNumber( "statValue", strenghtValue );
			inkTextRef.SetLocalizedText( m_itemStrenghtRequirementsValue, StringToName( GetLocalizedText( "LocKey#78420" ) ), textParams );
		}
		if( ( m_data.levelRequired > 0 ) && ( m_data.m_PlayerLevel < m_data.levelRequired ) )
		{
			inkWidgetRef.SetVisible( m_itemRequirements, true );
			inkWidgetRef.SetVisible( m_itemLevelRequirements, true );
			inkTextRef.SetText( m_itemLevelRequirementsValue, IntToString( m_data.levelRequired ) );
		}
		if( !( InventoryItemData.IsEmpty( m_data.inventoryItemData ) ) )
		{
			requirement = InventoryItemData.GetRequirement( m_data.inventoryItemData );
			if( requirement.statType != gamedataStatType.Invalid && !( InventoryItemData.IsRequirementMet( m_data.inventoryItemData ) ) )
			{
				inkWidgetRef.SetVisible( m_itemRequirements, true );
				inkWidgetRef.SetVisible( m_itemAttributeRequirements, true );
				textParams = new inkTextParams;
				textParams.AddNumber( "value", RoundF( requirement.requiredValue ) );
				statRecord = RPGManager.GetStatRecord( requirement.statType );
				textParams.AddString( "statName", GetLocalizedText( UILocalizationHelper.GetStatNameLockey( statRecord ) ) );
				textParams.AddString( "statColor", "StatTypeColor." + EnumValueToString( "gamedataStatType", ( ( Int32 )( requirement.statType ) ) ) );
				inkTextRef.SetLocalizedTextScript( m_itemAttributeRequirementsText, "LocKey#49215", textParams );
			}
		}
		if( !( InventoryItemData.IsEquippable( m_data.inventoryItemData ) ) )
		{
			inkWidgetRef.SetVisible( m_itemRequirements, true );
			inkWidgetRef.SetVisible( m_itemAttributeRequirements, true );
			requirement = InventoryItemData.GetEquipRequirement( m_data.inventoryItemData );
			textParams = new inkTextParams;
			textParams.AddNumber( "value", RoundF( requirement.requiredValue ) );
			statRecord = RPGManager.GetStatRecord( requirement.statType );
			textParams.AddString( "statName", GetLocalizedText( UILocalizationHelper.GetStatNameLockey( statRecord ) ) );
			textParams.AddString( "statColor", "StatTypeColor." + EnumValueToString( "gamedataStatType", ( ( Int32 )( requirement.statType ) ) ) );
			inkTextRef.SetLocalizedTextScript( m_itemAttributeRequirementsText, "LocKey#77652", textParams );
		}
		if( m_data.isPerkRequired )
		{
			inkWidgetRef.SetVisible( m_itemRequirements, true );
			textParams = new inkTextParams;
			textParams.AddLocalizedString( "perkName", m_data.perkRequiredName );
			inkTextRef.SetLocalizedTextScript( m_itemAttributeRequirementsText, "LocKey#42796", textParams );
		}
		if( InventoryItemData.IsPart( m_data.inventoryItemData ) && !( InventoryItemData.IsRequirementMet( m_data.inventoryItemData ) ) )
		{
			inkWidgetRef.SetVisible( m_itemRequirements, true );
			inkTextRef.SetLocalizedTextScript( m_itemAttributeRequirementsText, "LocKey#79881", textParams );
		}
	}

	protected function UpdateDescription()
	{
		if( m_data && IsStringValid( m_data.description ) )
		{
			inkTextRef.SetLocalizedTextScript( m_descriptionText, m_data.description );
			inkCompoundRef.SetVisible( m_descriptionContainer, true );
		}
		else
		{
			inkCompoundRef.SetVisible( m_descriptionContainer, false );
		}
	}

	protected function UpdateWeight()
	{
		var weight : Float;
		weight = InventoryItemData.GetGameItemData( m_data.inventoryItemData ).GetStatValueByType( gamedataStatType.Weight );
		inkTextRef.SetText( m_requireLevelText, FloatToStringPrec( weight, 2 ) );
	}

	protected function UpdateRequiredLevel() {}

	protected function UpdatePrice()
	{
		if( m_data.itemType == gamedataItemType.Wea_Fists )
		{
			inkTextRef.SetText( m_priceText, "N/A" );
		}
		else if( m_data.isVendorItem )
		{
			inkTextRef.SetText( m_priceText, FloatToStringPrec( m_data.buyPrice, 0 ) );
		}
		else
		{
			inkTextRef.SetText( m_priceText, FloatToStringPrec( m_data.price, 0 ) );
		}
		inkCompoundRef.SetVisible( m_priceContainer, true );
	}

	protected function UpdateCraftedIcon()
	{
		var isCrafted : Bool;
		var showIcon : Bool;
		showIcon = isCrafted && m_data.displayContext != InventoryTooltipDisplayContext.Crafting;
		inkWidgetRef.SetVisible( m_craftedItemIcon, showIcon );
		inkCompoundRef.SetVisible( m_craftedItemContainer, showIcon );
	}

	protected function GetItemType() : gamedataItemType
	{
		if( m_data.itemType != gamedataItemType.Invalid )
		{
			return m_data.itemType;
		}
		return InventoryItemData.GetItemType( m_data.inventoryItemData );
	}

}

