local DIGITS = "%.2f";
local NO_BONUS_ALPHA = 0.5;

local Narci = Narci;
local L = Narci.L;
local FormatLargeNumbers = NarciAPI.FormatLargeNumbers;
local BreakUpLargeNumbers = BreakUpLargeNumbers;
local GetPrimaryStats = NarciAPI.GetPrimaryStats;
local format = string.format;
local floor = math.floor;
local ceil = math.ceil;
local max = math.max;
local min = math.min;

local DefaultTooltip = NarciGameTooltip;	--Created in NarciAPI.lua

local C_PaperDollInfo = C_PaperDollInfo;
local UnitStat = UnitStat;
local GetCombatRating = GetCombatRating;
local GetCombatRatingBonus = GetCombatRatingBonus;
local BASE_MOVEMENT_SPEED = BASE_MOVEMENT_SPEED;
local GetSpecialization = GetSpecialization;

local function GetPrimaryStatsNum()
	local _, strength = UnitStat("player", 1);
	local _, agility = UnitStat("player", 2);
	local _, intellect = UnitStat("player", 4);
	if strength > agility and strength > intellect then
		return strength;
	elseif	agility > strength and agility > intellect then
		return agility;
	elseif	intellect > agility and	intellect >	strength then
		return intellect;
	end
end

local function GetAppropriateDamage(unit)
	if IsRangedWeapon() then
		local attackTime, minDamage, maxDamage, bonusPos, bonusNeg, percent = UnitRangedDamage(unit);
		return minDamage, maxDamage, nil, nil, 0, 0, percent;
	else
		return UnitDamage(unit);
	end
end

local function CharacterDamageFrame_OnEnter(object)
	-- Main hand weapon
	DefaultTooltip:SetOwner(object, "ANCHOR_NONE");
	if ( object.unit == "pet" ) then
		DefaultTooltip:SetText(INVTYPE_WEAPONMAINHAND_PET, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
	else
		DefaultTooltip:SetText(INVTYPE_WEAPONMAINHAND, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
	end
	DefaultTooltip:AddDoubleLine(format(STAT_FORMAT, ATTACK_SPEED_SECONDS), format("%.2F", object.attackSpeed), 1.00, 0.82, 0.00, 1.00, 0.82, 0.00);
	DefaultTooltip:AddDoubleLine(format(STAT_FORMAT, DAMAGE), object.damage, 1.00, 0.82, 0.00, 1.00, 0.82, 0.00);
	-- Check for offhand weapon
	if ( object.offhandAttackSpeed ) then
		DefaultTooltip:AddLine("\n");
		DefaultTooltip:AddLine(INVTYPE_WEAPONOFFHAND, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
		DefaultTooltip:AddDoubleLine(format(STAT_FORMAT, ATTACK_SPEED_SECONDS), format("%.2F", object.offhandAttackSpeed), 1.00, 0.82, 0.00, 1.00, 0.82, 0.00);
		DefaultTooltip:AddDoubleLine(format(STAT_FORMAT, DAMAGE), object.offhandDamage, 1.00, 0.82, 0.00, 1.00, 0.82, 0.00);
	end

	DefaultTooltip:SetPoint("TOPRIGHT",object,"TOPLEFT", -4, 0);
	DefaultTooltip:Show();
end

local function MovementSpeed_OnUpdate(object, elapsed)
	object.t = object.t + elapsed;
	if object.t > 0.1 then
		object.t = 0;
	else
		return
	end

	local unit = object.unit;
	local _, runSpeed, flightSpeed, swimSpeed = GetUnitSpeed(unit);
	runSpeed = runSpeed/BASE_MOVEMENT_SPEED*100;
	flightSpeed = flightSpeed/BASE_MOVEMENT_SPEED*100;
	swimSpeed = swimSpeed/BASE_MOVEMENT_SPEED*100;

	-- Determine whether to display running, flying, or swimming speed
	local speed = runSpeed;
	local swimming = IsSwimming(unit);
	if (swimming) then
		speed = swimSpeed;
	elseif (IsFlying(unit)) then
		speed = flightSpeed;
	end

	-- Hack so that your speed doesn't appear to change when jumping out of the water
	if (IsFalling(unit)) then
		if (object.wasSwimming) then
			speed = swimSpeed;
		end
	else
		object.wasSwimming = swimming;
	end

	local valueText = format("%d%%", speed+0.5);

	object.Label:SetText(L["Movement Speed"]);		--STAT_MOVEMENT_SPEED
	object.Value:SetText(valueText);

	object.speed = speed;
	object.runSpeed = runSpeed;
	object.flightSpeed = flightSpeed;
	object.swimSpeed = swimSpeed;
end

local function MovementSpeed_OnEnter(object)
	DefaultTooltip:SetOwner(object, "ANCHOR_NONE");
	DefaultTooltip:SetText("|cffffffff".. STAT_MOVEMENT_SPEED .." "..format("%d%%", object.speed+0.5).."|r");

	DefaultTooltip:AddLine(format(STAT_MOVEMENT_GROUND_TOOLTIP, object.runSpeed+0.5));
	if (object.unit ~= "pet") then
		DefaultTooltip:AddLine(format(STAT_MOVEMENT_FLIGHT_TOOLTIP, object.flightSpeed+0.5));
	end
	DefaultTooltip:AddLine(format(STAT_MOVEMENT_SWIM_TOOLTIP, object.swimSpeed+0.5));
	DefaultTooltip:AddLine(" ");
	DefaultTooltip:AddLine(format(CR_SPEED_TOOLTIP, BreakUpLargeNumbers(GetCombatRating(CR_SPEED)), GetCombatRatingBonus(CR_SPEED)));

	DefaultTooltip:SetPoint("TOPRIGHT",object,"TOPLEFT", -4, 0)
	DefaultTooltip:Show();

	object.UpdateTooltip = MovementSpeed_OnEnter;
end

local function MasteryFrame_OnEnter(object)
    local RadarChart = object:GetParent();
    if RadarChart.SetVerticeSize then
        RadarChart.SetVerticeSize(RadarChart, object, 15);
    end

	DefaultTooltip:SetOwner(object, "ANCHOR_NONE");

	local mastery, bonusCoeff = GetMasteryEffect();
	local masteryBonus = GetCombatRatingBonus(CR_MASTERY) * bonusCoeff;

	local title = "|cffffffff"..STAT_MASTERY.." "..format("%.2F%%", mastery).."|r";
	if (masteryBonus > 0) then
		title = title.."|cffffffff".." ("..format("%.2F%%", mastery-masteryBonus).."|r"..GREEN_FONT_COLOR_CODE.."+"..format("%.2F%%", masteryBonus).."|r".."|cffffffff"..")".."|r";
	end
	DefaultTooltip:SetText(title);

	local masteryRating = GetCombatRating(CR_MASTERY);
	local primaryTalentTree = GetSpecialization();
	if (primaryTalentTree) then
		local masterySpell, masterySpell2 = GetSpecializationMasterySpells(primaryTalentTree);
		if (masterySpell) then
			DefaultTooltip:AddSpellByID(masterySpell);
		end
		if (masterySpell2) then
			DefaultTooltip:AddLine(" ");
			DefaultTooltip:AddSpellByID(masterySpell2);
		end
		DefaultTooltip:AddLine(" ");
		local tooltip = format(STAT_MASTERY_TOOLTIP, BreakUpLargeNumbers(masteryRating), masteryBonus);
		if masteryBonus ~= 0 then
			DefaultTooltip:AddDoubleLine(tooltip ,floor( (masteryRating / masteryBonus) * 100 + 0.5) / 100 .. " [+1%]", 1.00, 0.82, 0.00, 1.00, 0.82, 0.00);
		else
			DefaultTooltip:AddLine(tooltip, 1.00, 0.82, 0.00, true);
		end
	else
		DefaultTooltip:AddLine(format(STAT_MASTERY_TOOLTIP, BreakUpLargeNumbers(masteryRating), masteryBonus), 1.00, 0.82, 0.00, true);
		DefaultTooltip:AddLine(" ");
		DefaultTooltip:AddLine(STAT_MASTERY_TOOLTIP_NO_TALENT_SPEC, GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b, true);
	end
	DefaultTooltip:SetPoint("TOPRIGHT",object,"TOPLEFT", -4, 0)
	DefaultTooltip:Show();
end

local function GetEffectiveCrit()
	local rating;
	local spellCrit, rangedCrit, meleeCrit;
	local critChance;
	
	-- Start at 2 to skip physical damage
	local holySchool = 2;
	local minCrit = GetSpellCritChance(holySchool);
	local spellCritTable = {};
	spellCritTable[holySchool] = minCrit;
	local spellCrit;
	for i = (holySchool+1), MAX_SPELL_SCHOOLS do
		spellCrit = GetSpellCritChance(i);
		minCrit = min(minCrit, spellCrit);
		spellCritTable[i] = spellCrit;
	end
	spellCrit = minCrit
	rangedCrit = GetRangedCritChance();
	meleeCrit = GetCritChance();

	if (spellCrit >= rangedCrit and spellCrit >= meleeCrit) then
		critChance = spellCrit;
		rating = CR_CRIT_SPELL;
	elseif (rangedCrit >= meleeCrit) then
		critChance = rangedCrit;
		rating = CR_CRIT_RANGED;
	else
		critChance = meleeCrit;
		rating = CR_CRIT_MELEE;
	end

	return critChance, rating
end

Narci.GetEffectiveCrit = GetEffectiveCrit;

------------------------------------------------------------------
----The following codes are derivated from PapaerDollFrame.lua----
------------------------------------------------------------------
local UpdateFunc = {};

function UpdateFunc:Primary(object)
	local unit = "player";
	local PrimaryStatsName, PrimaryStatsNum = GetPrimaryStats();
	object.Label:SetText(PrimaryStatsName)
	object.Value:SetText(PrimaryStatsNum)
	local spec = GetSpecialization();
	if not spec then return; end
	local role = GetSpecializationRole(spec);
	local _, _, _, _, _, primaryStat = GetSpecializationInfo(spec);
	if type(tonumber(primaryStat)) ~= "number" then return; end		--sometimes changing zones cause Lua error
	local stat, effectiveStat, posBuff, negBuff = UnitStat(unit, primaryStat);
	local effectiveStatDisplay = FormatLargeNumbers(effectiveStat);

	-- Set the tooltip text
	local statName = _G["SPELL_STAT"..primaryStat.."_NAME"];
	local tooltipText = "|cffffffff".. statName .." ";

	if ( ( posBuff == 0 ) and ( negBuff == 0 ) ) then
		object.tooltip = tooltipText..effectiveStatDisplay.."|r";
	else
		tooltipText = tooltipText..effectiveStatDisplay;
		if ( posBuff > 0 or negBuff < 0 ) then
			tooltipText = tooltipText.." ("..BreakUpLargeNumbers(stat - posBuff - negBuff).."|r";
		end
		if ( posBuff > 0 ) then
			tooltipText = tooltipText.."|r"..GREEN_FONT_COLOR_CODE.."+"..BreakUpLargeNumbers(posBuff).."|r";
		end
		if ( negBuff < 0 ) then
			tooltipText = tooltipText..RED_FONT_COLOR_CODE.." "..BreakUpLargeNumbers(negBuff).."|r";
		end
		if ( posBuff > 0 or negBuff < 0 ) then
			tooltipText = tooltipText.."|cffffffff"..")".."|r";
		end
		object.tooltip = tooltipText;

		-- If there are any negative buffs then show the main number in red even if there are
		-- positive buffs. Otherwise show in green.
		if ( negBuff < 0 and not GetPVPGearStatRules() ) then
			effectiveStatDisplay = RED_FONT_COLOR_CODE..effectiveStatDisplay.."|r";
		end
	end

	object.tooltip2 = _G["DEFAULT_STAT"..primaryStat.."_TOOLTIP"];

	if ( primaryStat == LE_UNIT_STAT_AGILITY ) then
		local attackPower = GetAttackPowerForStat(primaryStat, effectiveStat);
		local tooltip = STAT_TOOLTIP_BONUS_AP;
		if (HasAPEffectsSpellPower()) then
			tooltip = STAT_TOOLTIP_BONUS_AP_SP;
		end
		if (not primaryStat or primaryStat == LE_UNIT_STAT_AGILITY) then
			object.tooltip2 = format(tooltip, BreakUpLargeNumbers(attackPower));
			if ( role == "TANK" ) then
				local increasedDodgeChance = GetDodgeChanceFromAttribute();
				if ( increasedDodgeChance > 0 ) then
					object.tooltip2 = object.tooltip2.."|n|n"..format(CR_DODGE_BASE_STAT_TOOLTIP, increasedDodgeChance);
				end
			end
		else
			object.tooltip2 = STAT_NO_BENEFIT_TOOLTIP;
		end

	elseif ( primaryStat == LE_UNIT_STAT_STRENGTH ) then
		local attackPower = GetAttackPowerForStat(primaryStat,effectiveStat);
		if (HasAPEffectsSpellPower()) then
			object.tooltip2 = STAT_TOOLTIP_BONUS_AP_SP;
		end
		if (not primaryStat or primaryStat == LE_UNIT_STAT_STRENGTH) then
			object.tooltip2 = format(object.tooltip2, BreakUpLargeNumbers(attackPower));
			if ( role == "TANK" ) then
				local increasedParryChance = GetParryChanceFromAttribute();
				if ( increasedParryChance > 0 ) then
					object.tooltip2 = object.tooltip2.."|n|n"..format(CR_PARRY_BASE_STAT_TOOLTIP, increasedParryChance);
				end
			end
		else
			object.tooltip2 = STAT_NO_BENEFIT_TOOLTIP;
		end

	elseif ( primaryStat == LE_UNIT_STAT_INTELLECT ) then
		if ( UnitHasMana("player") ) then
			if (HasAPEffectsSpellPower()) then
				object.tooltip2 = STAT_NO_BENEFIT_TOOLTIP;
			else
				local result, druid = HasSPEffectsAttackPower();
				if (result and druid) then
					object.tooltip2 = format(STAT_TOOLTIP_SP_AP_DRUID, max(0, effectiveStat), max(0, effectiveStat));
				elseif (result) then
					object.tooltip2 = format(STAT_TOOLTIP_BONUS_AP_SP, max(0, effectiveStat));
				elseif (not primaryStat or primaryStat == LE_UNIT_STAT_INTELLECT) then
					object.tooltip2 = format(object.tooltip2, max(0, effectiveStat));
				else
					object.tooltip2 = STAT_NO_BENEFIT_TOOLTIP;
				end
			end
		else
			object.tooltip2 = STAT_NO_BENEFIT_TOOLTIP;
		end
	end
end

function UpdateFunc:Stamina(object)
	local statIndex = LE_UNIT_STAT_STAMINA;
	local stat, effectiveStat, posBuff, negBuff = UnitStat("player", statIndex);

	local effectiveStatDisplay = FormatLargeNumbers(effectiveStat);
	-- Set the tooltip text
	local statName = _G["SPELL_STAT"..statIndex.."_NAME"];
	local tooltipText = "|cffffffff".. statName .." ";

	if ( ( posBuff == 0 ) and ( negBuff == 0 ) ) then
		object.tooltip = tooltipText..effectiveStatDisplay.."|r";
	else
		tooltipText = tooltipText..effectiveStatDisplay;
		if ( posBuff > 0 or negBuff < 0 ) then
			tooltipText = tooltipText.." ("..BreakUpLargeNumbers(stat - posBuff - negBuff).."|r";
		end
		if ( posBuff > 0 ) then
			tooltipText = tooltipText.."|r"..GREEN_FONT_COLOR_CODE.."+"..BreakUpLargeNumbers(posBuff).."|r";
		end
		if ( negBuff < 0 ) then
			tooltipText = tooltipText..RED_FONT_COLOR_CODE.." "..BreakUpLargeNumbers(negBuff).."|r";
		end
		if ( posBuff > 0 or negBuff < 0 ) then
			tooltipText = tooltipText.."|cffffffff"..")".."|r";
		end
		object.tooltip = tooltipText;

		-- If there are any negative buffs then show the main number in red even if there are
		-- positive buffs. Otherwise show in green.
		if ( negBuff < 0 and not GetPVPGearStatRules() ) then
			effectiveStatDisplay = RED_FONT_COLOR_CODE..effectiveStatDisplay.."|r";
		end
	end

	object.Label:SetText(statName)
	object.Value:SetText(effectiveStat)
	object.tooltip2 = _G["DEFAULT_STAT"..statIndex.."_TOOLTIP"];
	object.tooltip2 = format(object.tooltip2, BreakUpLargeNumbers(((effectiveStat*UnitHPPerStamina("player")))*GetUnitMaxHealthModifier("player")));

	--object:Show();
end

function UpdateFunc:Damage(object)
	local unit = "player";

	local speed, offhandSpeed = UnitAttackSpeed(unit);
	local minDamage, maxDamage, minOffHandDamage, maxOffHandDamage, physicalBonusPos, physicalBonusNeg, percent = GetAppropriateDamage(unit);

	-- remove decimal points for display values
	local displayMin = max(floor(minDamage),1);
	local displayMinLarge = displayMin	--BreakUpLargeNumbers(displayMin);
	local displayMax = max(ceil(maxDamage),1);
	local displayMaxLarge = displayMax	--BreakUpLargeNumbers(displayMax);

	-- calculate base damage
	if percent == 0 then return; end;
	minDamage = (minDamage / percent) - physicalBonusPos - physicalBonusNeg;
	maxDamage = (maxDamage / percent) - physicalBonusPos - physicalBonusNeg;

	local baseDamage = (minDamage + maxDamage) * 0.5;
	local fullDamage = (baseDamage + physicalBonusPos + physicalBonusNeg) * percent;
	local totalBonus = (fullDamage - baseDamage);
	-- set tooltip text with base damage
	local damageTooltip = BreakUpLargeNumbers(max(floor(minDamage),1)).." - "..BreakUpLargeNumbers(max(ceil(maxDamage),1));

	local colorPos = "|cffffffff";
	local colorNeg = "|cffffffff";

	-- epsilon check
	if ( totalBonus < 0.1 and totalBonus > -0.1 ) then
		totalBonus = 0.0;
	end

	local value;
	if ( totalBonus == 0 ) then
		if ( ( displayMin < 100 ) and ( displayMax < 100 ) ) then
			value = displayMinLarge.." - "..displayMaxLarge;
		else
			value = displayMinLarge.." - "..displayMaxLarge;
		end
	else
		-- set bonus color and display
		local color;
		if ( totalBonus > 0 ) then
			color = colorPos;
		else
			color = colorNeg;
		end
		if ( ( displayMin < 100 ) and ( displayMax < 100 ) ) then
			value = color..displayMinLarge.." - "..displayMaxLarge.."|r";
		else
			value = color..displayMinLarge.." - "..displayMaxLarge.."|r";
		end
		if ( physicalBonusPos > 0 ) then
			damageTooltip = damageTooltip..colorPos.." +"..physicalBonusPos.."|r";
		end
		if ( physicalBonusNeg < 0 ) then
			damageTooltip = damageTooltip..colorNeg.." "..physicalBonusNeg.."|r";
		end
		if ( percent > 1 ) then
			damageTooltip = damageTooltip..colorPos.." x"..floor(percent*100+0.5).."%|r";
		elseif ( percent < 1 ) then
			damageTooltip = damageTooltip..colorNeg.." x"..floor(percent*100+0.5).."%|r";
		end

	end

	object.Label:SetText(DAMAGE)
	object.Value:SetText(value)
	object.damage = damageTooltip;
	object.attackSpeed = speed;
	object.unit = unit;

	-- If there's an offhand speed then add the offhand info to the tooltip
	if ( offhandSpeed and minOffHandDamage and maxOffHandDamage ) then
		minOffHandDamage = (minOffHandDamage / percent) - physicalBonusPos - physicalBonusNeg;
		maxOffHandDamage = (maxOffHandDamage / percent) - physicalBonusPos - physicalBonusNeg;

		local offhandBaseDamage = (minOffHandDamage + maxOffHandDamage) * 0.5;
		local offhandFullDamage = (offhandBaseDamage + physicalBonusPos + physicalBonusNeg) * percent;
		local offhandDamageTooltip = BreakUpLargeNumbers(max(floor(minOffHandDamage),1)).." - "..BreakUpLargeNumbers(max(ceil(maxOffHandDamage),1));
		if ( physicalBonusPos > 0 ) then
			offhandDamageTooltip = offhandDamageTooltip..colorPos.." +"..physicalBonusPos.."|r";
		end
		if ( physicalBonusNeg < 0 ) then
			offhandDamageTooltip = offhandDamageTooltip..colorNeg.." "..physicalBonusNeg.."|r";
		end
		if ( percent > 1 ) then
			offhandDamageTooltip = offhandDamageTooltip..colorPos.." x"..floor(percent*100+0.5).."%|r";
		elseif ( percent < 1 ) then
			offhandDamageTooltip = offhandDamageTooltip..colorNeg.." x"..floor(percent*100+0.5).."%|r";
		end
		object.offhandDamage = offhandDamageTooltip;
		object.offhandAttackSpeed = offhandSpeed;
	else
		object.offhandAttackSpeed = nil;
	end

	object:SetScript("OnEnter", CharacterDamageFrame_OnEnter);
	--object:Show();
end

function UpdateFunc:AttackSpeed(object, unit)
	local unit = "player"

	local meleeHaste = GetMeleeHaste();
	local speed, offhandSpeed = UnitAttackSpeed(unit);

	local displaySpeed = floor(100*speed + 0.5)/100;
	if ( offhandSpeed ) then
		offhandSpeed = floor(100*offhandSpeed + 0.5)/100;
	end
	if ( offhandSpeed ) then
		if displaySpeed ~= offhandSpeed then
			displaySpeed =  displaySpeed.." / ".. offhandSpeed;
		else
			displaySpeed =  displaySpeed;
		end
	else
		displaySpeed =  displaySpeed;
	end

	local speedText = format(DIGITS, meleeHaste).."%"
	object.Label:SetText(ATTACK_SPEED)
	object.Value:SetText(displaySpeed)

	object.tooltip = "|cffffffff".. ATTACK_SPEED .." "..displaySpeed.."|r";
	object.tooltip2 = format(STAT_ATTACK_SPEED_BASE_TOOLTIP, format(DIGITS, meleeHaste));

	--object:Show();
end

function UpdateFunc:Armor(object, unit)
	local unit = "player"

	local baselineArmor, effectiveArmor, armor, bonusArmor = UnitArmor(unit);
	object.Label:SetText(STAT_ARMOR);
	object.Value:SetText(effectiveArmor);

    local armorReduction = C_PaperDollInfo.GetArmorEffectiveness(effectiveArmor, UnitEffectiveLevel(unit));
	local armorReductionAgainstTarget = C_PaperDollInfo.GetArmorEffectivenessAgainstTarget(effectiveArmor);

	object.tooltip = "|cffffffff".. ARMOR .." "..BreakUpLargeNumbers(effectiveArmor).."|r";
	object.tooltip2 = format(STAT_ARMOR_TOOLTIP, 100*armorReduction);
	if (armorReductionAgainstTarget) then
		object.tooltip3 = format(STAT_ARMOR_TARGET_TOOLTIP, 100*armorReductionAgainstTarget);
	else
		object.tooltip3 = nil;
	end
	--object:Show();
end

function UpdateFunc:Reduction(object)
	local unit = "player"
	local baselineArmor, effectiveArmor, armor, bonusArmor = UnitArmor(unit);

	local armorReduction = C_PaperDollInfo.GetArmorEffectiveness(effectiveArmor, UnitEffectiveLevel(unit)) or 0;
	armorReduction = 100 * armorReduction;
	local armorReductionAgainstTarget = C_PaperDollInfo.GetArmorEffectivenessAgainstTarget(effectiveArmor);
	local armorReductionText = format(DIGITS, armorReduction).."%"
	
	object.Label:SetText(L["Damage Reduction Percentage"]);

	object.tooltip = "|cffffffff"..COMBAT_TEXT_SHOW_RESISTANCES_TEXT.." "..armorReductionText.."|r";
	object.tooltip2 = format(STAT_ARMOR_TOOLTIP, armorReduction);
	if (armorReductionAgainstTarget) then
		object.tooltip3 = format(STAT_ARMOR_TARGET_TOOLTIP, 100*armorReductionAgainstTarget);
		armorReduction = 100 * armorReductionAgainstTarget
	else
		object.tooltip3 = nil;
	end

	object.Value:SetText(armorReductionText);
	--object:Show();
end

function UpdateFunc:Dodge(object)
	local chance = GetDodgeChance();
	local chanceText = format("%.2F", chance).."%"
	object.Label:SetText(STAT_DODGE);
	object.Value:SetText(chanceText);

	object.tooltip = "|cffffffff".. DODGE_CHANCE .." "..format("%.2F", chance).."%".."|r";
	object.tooltip2 = format(CR_DODGE_TOOLTIP, GetCombatRating(CR_DODGE), GetCombatRatingBonus(CR_DODGE));
	--object:Show();
end

function UpdateFunc:Parry(object)
	local chance = GetParryChance();
	local chanceText = format("%.2F", chance).."%"
	object.Label:SetText(STAT_PARRY);
	object.Value:SetText(chanceText);		

	object.tooltip = "|cffffffff".. PARRY_CHANCE .." "..format("%.2F", chance).."%".."|r";
	object.tooltip2 = format(CR_PARRY_TOOLTIP, GetCombatRating(CR_PARRY), GetCombatRatingBonus(CR_PARRY));
	--object:Show();
end

function UpdateFunc:Block(object)
	local unit = "player";

	local chance = GetBlockChance();
	local chanceText = format("%.2F", chance).."%";

	local spec = GetSpecialization();
	if not spec then return; end

	--local role = GetSpecializationRole(spec);
	if chance ~= 0 and C_PaperDollInfo.OffhandHasShield() then		--role == "TANK"
		object:SetLabelAndValue(STAT_BLOCK, chanceText);
	else
		object:SetLabelAndValue(STAT_BLOCK, "N/A", true);
	end

	object.tooltip = "|cffffffff".. BLOCK_CHANCE .." "..format("%.2F", chance).."%".."|r";

	local shieldBlockArmor = GetShieldBlock();
	local blockArmorReduction = C_PaperDollInfo.GetArmorEffectiveness(shieldBlockArmor, UnitEffectiveLevel(unit));
	local blockArmorReductionAgainstTarget = C_PaperDollInfo.GetArmorEffectivenessAgainstTarget(shieldBlockArmor);

	object.tooltip2 = format(CR_BLOCK_TOOLTIP, blockArmorReduction * 100);
	if (blockArmorReductionAgainstTarget) then
		object.tooltip3 = format(STAT_BLOCK_TARGET_TOOLTIP, blockArmorReductionAgainstTarget * 100);
	else
		object.tooltip3 = nil;
	end
end

function UpdateFunc:Health(object, unit)
	if (not unit) then
		unit = "player";
	end
	local health = UnitHealthMax(unit);
	local healthText = FormatLargeNumbers(health);
	object.Label:SetText(HEALTH)
	object.Value:SetText(healthText)
	object.tooltip = "|cffffffff".. HEALTH .." "..healthText.."|r";
	if (unit == "player") then
		object.tooltip2 = STAT_HEALTH_TOOLTIP;
	elseif (unit == "pet") then
		object.tooltip2 = STAT_HEALTH_PET_TOOLTIP;
	end
	object:Show();
end

function UpdateFunc:Power(object)
	local unit = "player";
	local powerType, powerToken = UnitPowerType(unit);
	local power = UnitPowerMax(unit) or 0;
	local powerText = FormatLargeNumbers(power);
	local powerName = _G[powerToken];
	if (powerToken and powerName) then
		object.Label:SetText(powerName)
		object.Value:SetText(powerText)
		object.tooltip = "|cffffffff".. powerName .." "..powerText.."|r";
		object.tooltip2 = _G["STAT_"..powerToken.."_TOOLTIP"];
		object:Show();
	else
		object:SetLabelAndValue("Resource", "N/A", true);
	end
end

function UpdateFunc:Regen(object)
	local powerType, powerToken = UnitPowerType("player");
	local regenRate = GetPowerRegen();
	local regenRateText = BreakUpLargeNumbers(regenRate);
	local regenRatePerSec = format("%.2f", regenRate).."/s";
	local labelText;
	if powerToken == "ENERGY" then
		labelText = STAT_ENERGY_REGEN;
		object.tooltip2 = STAT_ENERGY_REGEN_TOOLTIP;
	elseif powerToken == "RUNES" then
		labelText = STAT_RUNE_REGEN;
		object.tooltip2 = STAT_RUNE_REGEN_TOOLTIP;
	elseif powerToken == "FOCUS" then
		labelText = STAT_FOCUS_REGEN;
		object.tooltip2 = STAT_FOCUS_REGEN_TOOLTIP;
	elseif UnitHasMana("player") then
		labelText = MANA_REGEN;
		regenRate = GetManaRegen();
		regenRatePerSec = tostring(floor(regenRate)).."/s";
	else
		local _, class = UnitClass("player");
		if (class ~= "DEATHKNIGHT") then
			object:SetLabelAndValue(MANA_REGEN_COMBAT, "N/A", true);		--MANA_REGEN_ABBR
			return;
		end
		local _, regenRate = GetRuneCooldown(1);
		local regenRateText = (format(STAT_RUNE_REGEN_FORMAT, regenRate));
		object:SetLabelAndValue(STAT_RUNE_REGEN, regenRateText);
		return;
	end
	if labelText then
		object.tooltip = "|cffffffff".. labelText .." "..regenRateText.."|r";
	end
	object:SetLabelAndValue(labelText, regenRatePerSec);
end

function UpdateFunc:Crit(object)
	if not Narci.refreshCombatRatings then return end;
	local critChance, rating = GetEffectiveCrit();

	object.tooltip = "|cffffffff".. STAT_CRITICAL_STRIKE .." "..format("%.2F%%", critChance).."|r";
	local extraCritChance = GetCombatRatingBonus(rating);
	local extraCritRating = GetCombatRating(rating);
	object.tooltip4 = nil;
	if (GetCritChanceProvidesParryEffect()) then
		object.tooltip2 = format(CR_CRIT_PARRY_RATING_TOOLTIP, BreakUpLargeNumbers(extraCritRating), extraCritChance, GetCombatRatingBonusForCombatRatingValue(CR_PARRY, extraCritRating));
	else
		if extraCritChance == 0 then
			object.tooltip2 = format(CR_CRIT_TOOLTIP, BreakUpLargeNumbers(extraCritRating), extraCritChance);
		else
			object.tooltip2 = NARCI_CRIT_TOOLTIP;
			object.tooltip4 = {format(NARCI_CRIT_TOOLTIP_FORMAT, BreakUpLargeNumbers(extraCritRating), extraCritChance), floor( (extraCritRating / extraCritChance) * 100 + 0.5) / 100 .. " [+1%]"}
		end
	end

	local PercentageText = format(DIGITS, critChance).."%"
	object.Label:SetText(NARCI_CRITICAL_STRIKE);		--COMBAT_RATING_NAME10
	object.Value:SetText(PercentageText);
	object.ValueRating:SetText(extraCritRating);
end

function UpdateFunc:Haste(object)
	if not Narci.refreshCombatRatings then return end;
	local unit = "player";
	local haste = GetHaste();
	local rating = CR_HASTE_MELEE;
	local hasteFormatString;

	if (haste < 0 and not GetPVPGearStatRules()) then
		hasteFormatString = RED_FONT_COLOR_CODE.."%s".."|r";
	else
		hasteFormatString = "%s";
	end

	object.tooltip = "|cffffffff" .. STAT_HASTE .. " " .. format(hasteFormatString, format("%.2F%%", haste)) .. "|r";

	local _, class = UnitClass(unit);
	object.tooltip2 = _G["STAT_HASTE_"..class.."_TOOLTIP"];
	if (not object.tooltip2) then
		object.tooltip2 = STAT_HASTE_TOOLTIP;
	end

	local Rating = GetCombatRating(rating);
	local RatingBonus = GetCombatRatingBonus(rating);
	if RatingBonus == 0 then
		object.tooltip2 = object.tooltip2 .. format(STAT_HASTE_BASE_TOOLTIP, BreakUpLargeNumbers(Rating), RatingBonus);
		object.tooltip4 = nil;
	else
		object.tooltip4 = {format(NARCI_HASTE_TOOLTIP_FORMAT, BreakUpLargeNumbers(Rating), RatingBonus), floor( (Rating / RatingBonus) * 100 + 0.5) / 100 .. " [+1%]"};
	end

	local PercentageText = format(DIGITS, haste).."%"
	object.Label:SetText(STAT_HASTE);
	object.Value:SetText(PercentageText);
	object.ValueRating:SetText(GetCombatRating(rating));
end

function UpdateFunc:Mastery(object)
	if not Narci.refreshCombatRatings then return end;
	object:SetScript("OnEnter", MasteryFrame_OnEnter);

	local mastery = GetMasteryEffect();
	local PercentageText = format(DIGITS, mastery).."%"
	object.Label:SetText(STAT_MASTERY);

	--[[
	if (UnitLevel("player") < SHOW_MASTERY_LEVEL) then
		object.numericValue = 0;
		object.Value:SetText("N/A");
		object.ValueRating:SetText("0");
		object.Label:SetAlpha(NO_BONUS_ALPHA)
		object.Value:SetAlpha(NO_BONUS_ALPHA)
		object.ValueRating:SetAlpha(NO_BONUS_ALPHA)
		return;
	end
	--]]

	object.Value:SetText(PercentageText);
	object.ValueRating:SetText(GetCombatRating(CR_MASTERY));

	object.Label:SetAlpha(1)
	object.Value:SetAlpha(1)
	object.ValueRating:SetAlpha(1)
end

function UpdateFunc:Versatility(object)
	if not Narci.refreshCombatRatings then return end;
	local versatility = GetCombatRating(CR_VERSATILITY_DAMAGE_DONE);
	local versatilityDamageBonus = GetCombatRatingBonus(CR_VERSATILITY_DAMAGE_DONE) + GetVersatilityBonus(CR_VERSATILITY_DAMAGE_DONE);
	local versatilityDamageTakenReduction = GetCombatRatingBonus(CR_VERSATILITY_DAMAGE_TAKEN) + GetVersatilityBonus(CR_VERSATILITY_DAMAGE_TAKEN);
	object.tooltip = "|cffffffff" .. format(VERSATILITY_TOOLTIP_FORMAT, STAT_VERSATILITY, versatilityDamageBonus, versatilityDamageTakenReduction) .. "|r";

	if versatilityDamageBonus == 0 then
		object.tooltip2 = format(CR_VERSATILITY_TOOLTIP, versatilityDamageBonus, versatilityDamageTakenReduction, BreakUpLargeNumbers(versatility), versatilityDamageBonus, versatilityDamageTakenReduction);
		object.tooltip4 = nil;
	else
		object.tooltip2 = format(NARCI_VERSATILITY_TOOLTIP_FORMAT_1, versatilityDamageBonus, versatilityDamageTakenReduction);
		object.tooltip4 = {format(NARCI_VERSATILITY_TOOLTIP_FORMAT_2, BreakUpLargeNumbers(versatility), versatilityDamageBonus, versatilityDamageTakenReduction) , floor( (versatility / versatilityDamageBonus) * 100 + 0.5) / 100 .. " [+1%/0.5%]"};
	end
	
	local PercentageText = format(DIGITS, versatilityDamageBonus).."%";
	object.Label:SetText(STAT_VERSATILITY);
	object.Value:SetText(PercentageText);
	object.ValueRating:SetText(GetCombatRating(CR_VERSATILITY_DAMAGE_DONE));
end

function UpdateFunc:Leech(object)
	local lifesteal = GetLifesteal();

	object.tooltip = "|cffffffff" .. STAT_LIFESTEAL .. " " .. format("%.2F%%", lifesteal) .. "|r";
	object.tooltip2 = format(CR_LIFESTEAL_TOOLTIP, BreakUpLargeNumbers(GetCombatRating(CR_LIFESTEAL)), GetCombatRatingBonus(CR_LIFESTEAL));

	local PercentageText = format(DIGITS, lifesteal).."%";
	object:SetLabelAndValue(STAT_LIFESTEAL, PercentageText, lifesteal == 0);
end

function UpdateFunc:Avoidance(object)
	local avoidance = GetAvoidance();

	object.tooltip = "|cffffffff" .. STAT_AVOIDANCE .. " " .. format("%.2F%%", avoidance) .. "|r";
	object.tooltip2 = format(CR_AVOIDANCE_TOOLTIP, BreakUpLargeNumbers(GetCombatRating(CR_AVOIDANCE)), GetCombatRatingBonus(CR_AVOIDANCE));
	
	local PercentageText = format(DIGITS, avoidance).."%";
	object:SetLabelAndValue(STAT_AVOIDANCE, PercentageText, avoidance == 0);
end

function UpdateFunc:Speed(object)
	local speed = GetSpeed();

	object.tooltip = "|cffffffff" .. STAT_SPEED .. " " .. format("%.2F%%", speed) .. "|r";
	object.tooltip2 = format(CR_SPEED_TOOLTIP, BreakUpLargeNumbers(GetCombatRating(CR_SPEED)), GetCombatRatingBonus(CR_SPEED));

	local PercentageText = format(DIGITS, speed).."%";
	object:SetLabelAndValue(STAT_SPEED, PercentageText, speed == 0);
end

function UpdateFunc:MovementSpeed(object)
	local unit = "player";

	object.wasSwimming = nil;
	object.unit = unit;
	object.t = 0;
	MovementSpeed_OnUpdate(object, 1);
	object:SetScript("OnEnter", MovementSpeed_OnEnter);
	object:SetScript("OnUpdate", MovementSpeed_OnUpdate);
end

---------------------------------------------------------------------------
NarciAttributeMixin = {};

function NarciAttributeMixin:Update()
    if UpdateFunc[self.token] then
        UpdateFunc[self.token](nil, self);
    end
end

function NarciAttributeMixin:SetLabelAndValue(label, value, grey)
	self.Label:SetText(label);
	self.Value:SetText(value);
	if grey then
		self.Label:SetTextColor(0.5, 0.5, 0.5);
		self.Value:SetTextColor(0.5, 0.5, 0.5);
	else
		self.Label:SetTextColor(0.92, 0.92, 0.92);
		self.Value:SetTextColor(0.92, 0.92, 0.92);
	end
end