-- ------------------------------------------------------------------------------ --
--                                TradeSkillMaster                                --
--          http://www.curse.com/addons/wow/tradeskillmaster_warehousing          --
--                                                                                --
--             A TradeSkillMaster Addon (http://tradeskillmaster.com)             --
--    All Rights Reserved* - Detailed license information included with addon.    --
-- ------------------------------------------------------------------------------ --

TSMAPI_FOUR.Money = {}
local private =  { textMoneyParts = {} }
local GOLD_ICON = "|TInterface\\MoneyFrame\\UI-GoldIcon:0|t"
local SILVER_ICON = "|TInterface\\MoneyFrame\\UI-SilverIcon:0|t"
local COPPER_ICON = "|TInterface\\MoneyFrame\\UI-CopperIcon:0|t"
local GOLD_TEXT = "|cffffd70ag|r"
local SILVER_TEXT = "|cffc7c7cfs|r"
local COPPER_TEXT = "|cffeda55fc|r"
local GOLD_TEXT_DISABLED = "|cff5d5222g|r"
local SILVER_TEXT_DISABLED = "|cff464646s|r"
local COPPER_TEXT_DISABLED = "|cff402d22c|r"



-- ============================================================================
-- TSMAPI Functions
-- ============================================================================

function TSMAPI_FOUR.Money.ToString(money, ...)
	money = tonumber(money)
	if not money then return end
	local color, isIcon, pad, trim, disabled, sep = nil, nil, nil, nil, nil, nil
	for i=1, select('#', ...) do
		local opt = select(i, ...)
		if type(opt) == "string" then
			if opt == "OPT_ICON" then -- use texture icons instead of letters for denominations
				isIcon = true
			elseif opt == "OPT_PAD" then -- left-pad all but the highest denomination with zeros (i.e. "1g 00s 02c" instead of "1g 0s 2c")
				pad = true
			elseif opt == "OPT_TRIM" then -- removes any 0 valued denominations (i.e. "1g" instead of "1g 0s 0c") - 0 will still be represented as "0c"
				trim = true
			elseif opt == "OPT_DISABLE" then -- removes color from denomination text - NOTE: this is not allowed if OPT_ICON is set
				disabled = true
			elseif opt == "OPT_SEP" then
				sep = true
			elseif strmatch(strlower(opt), "^|c[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]$") then -- color the numbers
				color = opt
			else
				assert(false, "Invalid option: "..opt)
			end
		end
	end
	assert(not (isIcon and disabled), "Setting both OPT_ICON and OPT_DISABLE is not allowed")

	local isNegative = money < 0
	money = abs(money)
	local gold = floor(money / COPPER_PER_GOLD)
	local silver = floor((money % COPPER_PER_GOLD) / COPPER_PER_SILVER)
	local copper = floor(money % COPPER_PER_SILVER)
	local goldText, silverText, copperText = nil, nil, nil
	if isIcon then
		goldText, silverText, copperText = GOLD_ICON, SILVER_ICON, COPPER_ICON
	elseif disabled then
		goldText, silverText, copperText = GOLD_TEXT_DISABLED, SILVER_TEXT_DISABLED, COPPER_TEXT_DISABLED
	else
		goldText, silverText, copperText = GOLD_TEXT, SILVER_TEXT, COPPER_TEXT
	end

	if money == 0 then
		return private.FormatNumber(0, false, color)..copperText
	end

	local text = nil
	local shouldPad = false
	if trim then
		wipe(private.textMoneyParts) -- avoid creating a new table every time
		-- add gold
		if gold > 0 then
			tinsert(private.textMoneyParts, private.FormatNumber(gold, false, color, sep)..goldText)
			shouldPad = pad
		end
		-- add silver
		if silver > 0 then
			tinsert(private.textMoneyParts, private.FormatNumber(silver, shouldPad, color)..silverText)
			shouldPad = pad
		end
		-- add copper
		if copper > 0 then
			tinsert(private.textMoneyParts, private.FormatNumber(copper, shouldPad, color)..copperText)
			shouldPad = pad
		end
		text = table.concat(private.textMoneyParts, " ")
	else
		if gold > 0 then
			text = private.FormatNumber(gold, false, color, sep)..goldText.." "..private.FormatNumber(silver, pad, color)..silverText.." "..private.FormatNumber(copper, pad, color)..copperText
		elseif silver > 0 then
			text = private.FormatNumber(silver, false, color)..silverText.." "..private.FormatNumber(copper, pad, color)..copperText
		else
			text = private.FormatNumber(copper, false, color)..copperText
		end
	end

	if isNegative then
		if color then
			return color.."-|r"..text
		else
			return "-"..text
		end
	else
		return text
	end
end

function TSMAPI_FOUR.Money.FromString(value)
	-- remove any colors
	value = gsub(gsub(strtrim(value), "\124c([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])", ""), "\124r", "")

	-- extract gold/silver/copper values
	local gold = tonumber(strmatch(value, "([0-9]+)g"))
	local silver = tonumber(strmatch(value, "([0-9]+)s"))
	local copper = tonumber(strmatch(value, "([0-9]+)c"))
	if not gold and not silver and not copper then return end

	-- test that there are no extra characters (other than spaces)
	value = gsub(value, "[0-9]+g", "", 1)
	value = gsub(value, "[0-9]+s", "", 1)
	value = gsub(value, "[0-9]+c", "", 1)
	if strtrim(value) ~= "" then return end

	return ((gold or 0) * COPPER_PER_GOLD) + ((silver or 0) * COPPER_PER_SILVER) + (copper or 0)
end



-- ============================================================================
-- Helper Functions
-- ============================================================================

function private.FormatNumber(num, pad, color, sep)
	if num < 10 and pad then
		num = "0"..num
	elseif sep and num >= 1000 then
		local result = ""
		while num > 0 do
			local part = num % 1000
			num = floor(num / 1000)
			if result ~= "" then
				result = LARGE_NUMBER_SEPERATOR..result
			end
			result = (num == 0 and part or format("%03d", part))..result
		end
		return result
	end

	if color then
		return color..num.."|r"
	else
		return num
	end
end
