--[[
-------------------
-    Madorin's    -
-Bag Status Meters-
-     v1.3.6      -
-------------------

Author: Kevin "Madorin" Hassett
Modified by Arbi(Hanulari dev)
Last Updated: March 16, 2005

-Patch Notes-
v1.3.6 (4/04/2005):
-TOC updated to 4297
-Added support for myAddOns AddOn arrangement (separate AddOn)

v1.3.5.1-kr (3/16/2005):
-applied to lastest BSM version

v1.3.5.1 (3/03/2005):
-Fixed a bug where any bag after an ammo bag or empty slot would not be checked

v1.3.5 (2/26/2005):
-TOC updated to 4216
-Added an option to hide the background and meter on the Overall Meter

v1.3.4 (2/17/2005):
-Merged all localizations
-TOC updated to 4211
-Added German Description

v1.3.3 (2/04/2005):
-Changed some variables from local to global for dependency possibilities.
-Fixed a quest reward ammo bag, "Bandolier of the Watch", to not show up as inventory.
-Put in bank bag labels.
-Set the Overall and Dropdown frame level to LOW.
-Commented Code.

v1.3.2-kr (2/1/2005):
-Modified functions for Cosmos and Hanulari.(Cosmos Korean ver)
-Translated to Korean.
-Removed Bindings and Options layout.

v1.3.2 (1/24/2005):
-Fixed layering issues with overlay bars/labels.
-Replaced the command system with a GUI for more customizability.
   -To access GUI, just type "/bsm" with anything or nothing following it.
-Added a key binding for BSM Options Pane.
-Added a UI button for the BSM Options Pane.
-Changed binding labels to buttons that toggle corresponding bag.
-Added an option to lock the overall meter.
-Added an option to place the overall meter at a specified location.

v1.3.1 (1/8/2005):
-Added "/bsm color" to toggle colors on/off.
-Added "/bsm totals" to toggle displaying the totals.
-Added "/bsm slots" to toggle using either free or used slots for display.
-Added "/bsm title" to toggle displaying the title on the overall meter.
-Added "/bsm notify" to toggle displaying notifications.
-Fixed "Inventory Full" notification to "Backpack Full".
-Fixed overall frame obstruction.
-Added notification when settings have changed.
-Changed color function to the one contributed by Azam.
-Added a brief readme.

v1.3 (1/5/2005):
-Fixed the small bug with ammo bags counting as inventory.
-Added alternative to use only text for displaying bag status ("/bsm none").
-Added alternative to use a dropdown frame for displaying bag status ("/bsm none").
-Added "/bsm help".
-Added ability to toggle hiding of labels ("/bsm labels").
-Added saved variables.
-Added notification when a bag becomes full.
-Huge XML overhaul.

v1.2 (1/2/2005):
-Fixed a layer problem where the meters showed up over the map frame.
-Added "/bsm hide" and "/bsm show" to hide or show the overall bag meter.
-Minor tweak to the % at which the meters turn yellow.

v1.1 (1/1/2005):
-Optimization help from Vjeux.
-Fixed a bug where a bag dragged into the bag bar from a non-inventory bag would not update.
-Added the missing line of XML to make it draggable.

Special Thanks: Vjeux for v1.1 LUA and XML optimization
                Azam for contributing an improved color function
                kiki for the french localization
                SirPennt for the german localization
                SoNeX for the german description
]]

BSM_Save = { };
BSM_Save.dispX = 0;
BSM_Save.dispY = -65;
BSM_Save.dropdowns = false;
BSM_Save.enable = true;
BSM_Save.individual = true;
BSM_Save.lock = false;
BSM_Save.notify = false;
BSM_Save.overall = true;
BSM_Save.slots = 0;

--BSM_NumSlots: global variable that holds the total number of slots per bag
BSM_NumSlots = {0, 0, 0, 0, 0};
--BSM_UsedSlots: global variable that holds the number of used slots per bag
BSM_UsedSlots = {0, 0, 0, 0, 0};
--BSM_BagFull: global variable used for displaying notifications only once
BSM_BagFull = {false, false, false, false, false};

BSM_LOADED = false;

--Variables for UI Objects
BSM_FRAME = "BSM_Frame";
BSM_DROPDOWNS = "BSM_Dropdowns";
BSM_DROPDOWNS_BARS = "BSM_DropdownsBars";
BSM_BARS = "BSM_Bars";
BSM_COODLOWNS = "BSM_Cooldowns";
BSM_BARS_LABELS = "BSM_BarLabels";
BSM_DROPDOWNS_LABELS = "BSM_DropdownLabels";
BSM_FRAMEBUTTON_LABEL = "BSM_FrameButtonLabel";
BSM_OPTIONS_BUTTON = "BSM_OptionsButton";
BSM_BANK = "BSM_BankBag";

--Variables for the type of slot used to keep count
BSM_SLOTS_FREE = 1;
BSM_SLOTS_TAKEN = 1;



--BSM_SavePosition:
--    Purpose - Save the position of the Overall Meter frame
--    Parameters - None
--    Returns - Nothing
function BSM_SavePosition()
    BSM_Save.dispX = this:GetLeft();
    BSM_Save.dispY = this:GetBottom();
end

--BSM_DisableAllIndividual:
--    Purpose - Hide all the individual meters components
--    Parameters - None
--    Returns - Nothing
function BSM_DisableAllIndividual()
    getglobal(BSM_BARS_LABELS):Hide();
    getglobal(BSM_BARS):Hide();
end

--BSM_EnableAllIndividual:
--    Purpose - Show all the individual meters components that need to be
--    Parameters - None
--    Returns - Nothing
function BSM_EnableAllIndividual()
    if ( BSM_Save.individual ) then
        getglobal(BSM_BARS):Show();
        getglobal(BSM_BARS_LABELS):Show();
    end
end

function BSM_OnLoad()
	BSM_CosmosRegisterOptions();

	this:RegisterEvent("VARIABLES_LOADED");
	this:RegisterEvent("PLAYER_ENTERING_WORLD")
end

function BSM_CosmosRegisterOptions()
	if (Cosmos_RegisterConfiguration) then
		Cosmos_RegisterConfiguration(
			"COS_BSM",
			"SECTION",
			BSM_SEP,
			BSM_SEP_INFO
		);
		Cosmos_RegisterConfiguration(
			"COS_BSM_SECTION",
			"SEPARATOR",
			BSM_SEP,
			BSM_SEP_INFO
		);
		
		Cosmos_RegisterConfiguration(
			"COS_BSM_ENABLE",
			"CHECKBOX",
			BSM_ENABLE,
			BSM_ENABLE_INFO,
			BSM_Toggle,
			1,
			0
		);
		Cosmos_RegisterConfiguration(
			"COS_BSM_INDIVIDUAL",
			"CHECKBOX",
			BSM_INDIVIDUAL,
			BSM_INDIVIDUAL_INFO,
			BSM_IndividualToggle,
			1,
			0
		);
		Cosmos_RegisterConfiguration(
			"COS_BSM_OVERALL",
			"CHECKBOX",
			BSM_OVERALL,
			BSM_OVERALL_INFO,
			BSM_OverallToggle,
			1,
			0
		);
		Cosmos_RegisterConfiguration(
			"COS_BSM_DROPDOWN",
			"CHECKBOX",
			BSM_DROPDOWN,
			BSM_DROPDOWN_INFO,
			BSM_DropdownToggle
		);
		Cosmos_RegisterConfiguration(
			"COS_BSM_LOCK",
			"CHECKBOX",
			BSM_LOCK,
			BSM_LOCK_INFO,
			BSM_LockToggle
		);
		Cosmos_RegisterConfiguration(
			"COS_BSM_RESET",
			"BUTTON",
			BSM_RESET,
			BSM_RESET_INFO,
			BSM_ResetButton,
			0,
			0,
			0,
			0,
			BSM_RESET_BUTTONTEXT
		);
		Cosmos_RegisterConfiguration(
			"COS_BSM_SLOTS",
			"CHECKBOX",
			BSM_SLOTS,
			BSM_SLOTS_INFO,
			BSM_SlotsToggle
		);
		Cosmos_RegisterConfiguration(
			"COS_BSM_NOTIFY",
			"CHECKBOX",
			BSM_NOTIFY,
			BSM_NOTIFY_INFO,
			BSM_NotifyToggle,
			0,
			0
		);
	end
end

function BSM_OnEvent(event)
    if event == "VARIABLES_LOADED" then
        BSM_loadVariables();
    elseif ( event == "BAG_UPDATE") then
	BSM_updateFreeSlots();
    elseif ( event == "UNIT_INVENTORY_CHANGED" ) then
	BSM_updateFreeSlots();
    elseif event == "PLAYER_ENTERING_WORLD" then
	this:RegisterEvent("BAG_UPDATE");
	this:RegisterEvent("UNIT_INVENTORY_CHANGED");
	this:RegisterEvent("PLAYER_LEAVING_WORLD")
    elseif event == "PLAYER_LEAVING_WORLD" then
	this:UnregisterEvent("BAG_UPDATE");
	this:UnregisterEvent("UNIT_INVENTORY_CHANGED");
    end
end

--BSM_loadVariables:
--    Purpose - Initialize the save vairiables if they don't exist and hide/show appropriate things
--    Parameters - None
--    Returns - Nothing
function BSM_loadVariables()
    --Set the position of the Overall Meter frame relative to the bottom left of the screen
    getglobal(BSM_FRAME):ClearAllPoints();
    getglobal(BSM_FRAME):SetPoint("BOTTOMLEFT", "UIParent", "BOTTOMLEFT", BSM_Save.dispX, BSM_Save.dispY);

    BSM_LOADED = true;
    BSM_updateFreeSlots();
end

--BSM_updateFreeSlots:
--    Purpose - Update the BSM_NumSlots and BSM_UsedSlots to accurately reflect the inventory
--              Also updates all meters that need to be updated
--    Parameters - None
--    Returns - Nothing
function BSM_updateFreeSlots()
    --totalSlots: the number of slots in all bags
	local totalSlots = 0;
	--totalUsedSlots: the number of used slots in all bags
	local totalusedSlots = 0;
	--slotsText: the text that is to be displayed on the meter labels
	local slotsText = 0;
	--isAmmo:  true if the current bag is one of the recognized ammo bags
	local isAmmo = false;

    --Loop through for every bag
	for bag = 0, 4, 1 do
        --Save the number of total slots in the current bag to the global variable
		BSM_NumSlots[bag+1] = GetContainerNumSlots(bag);

		isAmmo = false;

		--Check if the current bag is an ammo bag or can't get the bag name
		if ( not GetBagName(bag) ) then
			isAmmo = true;
		else
			for i = 1, #( BSM_AMMO ), 1 do
				if ( string.find( GetBagName(bag), BSM_AMMO[i] ) ) then
				    isAmmo = true;
				    break;
				end
	    		end
		end

		--If there is no bag in the current bag slot or it is an ammo bag, hide all of its meters and don't count it in the total
		--if (numSlots[bag+1] == 0 or numSlots[bag+1] == nil or string.find(GetBagName(bag), BSM_QUIVER) or string.find(GetBagName(bag), BSM_AMMO) or string.find(GetBagName(bag), BSM_BANDOLIER) or BSM_Save.enable ~= true) then
		if ( ( isAmmo or BSM_NumSlots[bag+1] == 0 ) or BSM_Save.enable ~= true ) then
			getglobal(BSM_BARS..bag):Hide();
			getglobal(BSM_BARS_LABELS..bag):Hide();
			getglobal(BSM_DROPDOWNS..bag):Hide();
			getglobal(BSM_DROPDOWNS_LABELS..bag):Hide();
			getglobal(BSM_DROPDOWNS_BARS..bag):Hide();
			getglobal(BSM_OPTIONS_BUTTON):Hide();
			BSM_BagFull[bag+1] = false;
		else
			totalSlots = totalSlots + BSM_NumSlots[bag+1];
			
			--Reset the used slots global variable and
            --loop through every slot in the current bag and 
            --increment the variable if an item exists
			BSM_UsedSlots[bag+1] = 0;
			for slot = 1, BSM_NumSlots[bag+1], 1 do
				if (GetContainerItemInfo(bag, slot)) then
					BSM_UsedSlots[bag+1] = BSM_UsedSlots[bag+1] + 1;
					totalusedSlots = totalusedSlots + 1;
				end
			end
			
            --If free slots are used in the individual labels, subtract the used slots from the free slots and
            --use that number in the slots text instead of used slots
			if (BSM_Save.slots == BSM_SLOTS_FREE) then
		                slotsText = BSM_NumSlots[bag+1] - BSM_UsedSlots[bag+1];
				labelText = BSM_FREEBAGSLOTS;
			else
		                slotsText = BSM_UsedSlots[bag+1];
		                slotsText = slotsText.."/"..BSM_NumSlots[bag+1];
				labelText = BSM_USEDBAGSLOTS;
			end
			
            --Show the current bag text and reset the text color
	                getglobal(BSM_BARS_LABELS..bag):Show();
  			getglobal(BSM_BARS_LABELS..bag):SetText(slotsText);
		        getglobal(BSM_BARS_LABELS..bag):SetTextColor(1.0, 1.0, 1.0, 1.0);
		        getglobal(BSM_DROPDOWNS_LABELS..bag):Show();
			getglobal(BSM_DROPDOWNS_LABELS..bag):SetText(slotsText);
			getglobal(BSM_FRAMEBUTTON_LABEL):SetText(labelText);

            --status: a temporary variable to hold the current meter being updated
			local status;
			--If the bars are shown and the overlay is enabled, update the meter/label over the current bag
			if ( BSM_Save.individual and BSM_Save.enable ) then
                --Set status to the meter that is over the current bag
		                status = getglobal(BSM_BARS..bag);
                --Set the meter's min, max, and current values accordingly
				status:SetMinMaxValues(0, BSM_NumSlots[bag+1]);
				status:SetValue(BSM_UsedSlots[bag+1]);
        			status:SetStatusBarColor(BSM_GetColor(BSM_NumSlots[bag+1] - BSM_UsedSlots[bag+1], BSM_NumSlots[bag+1], 0.6));
				status:Show();
		                getglobal(BSM_BARS_LABELS..bag):SetTextColor(1.0, 1.0, 1.0, 1.0);
		        end

            --If the dropdown meters are enabled, update them
			if ( BSM_Save.dropdowns and BSM_Save.enable ) then
                --Set status to the dropdown meter that is for the current bag
		                status = getglobal(BSM_DROPDOWNS_BARS..bag);
                --Set the meter's min, max, and current values accordingly
				status:SetMinMaxValues(0, BSM_NumSlots[bag+1]);
				status:SetValue(BSM_UsedSlots[bag+1]);
				status:SetStatusBarColor(BSM_GetColor(BSM_NumSlots[bag+1] - BSM_UsedSlots[bag+1], BSM_NumSlots[bag+1], 1.0));
	   	        	status:Show();
				getglobal(BSM_DROPDOWNS..bag):Show()
	                end

		        --If the current bag is full and notifications are enabled, check if a notification should be given
			if BSM_UsedSlots[bag+1] == BSM_NumSlots[bag+1] and BSM_Save.notify then
			--If the bag was not full last check, give a notification and
			--set the full bag variable to true
			--Otherwise keep the full bag variable false
				if not BSM_BagFull[bag+1] then
					if bag == 0 then
						UIErrorsFrame:AddMessage(BSM_BACKPACK..BSM_FULL, 1.0, 0.1, 1.0, 1.0, UIERRORS_HOLD_TIME);
						DEFAULT_CHAT_FRAME:AddMessage(BSM_MSG.."|cffff0fff"..BSM_BACKPACK..BSM_FULL.."|r");
					else
						UIErrorsFrame:AddMessage(BSM_BAG..bag..BSM_FULL, 1.0, 0.1, 1.0, 1.0, UIERRORS_HOLD_TIME);
						DEFAULT_CHAT_FRAME:AddMessage(BSM_MSG.."|cffff0fff"..BSM_BAG..bag..BSM_FULL.."|r");
					end
					BSM_BagFull[bag+1] = true;
				end
			else
				BSM_BagFull[bag+1] = false;
			end
		end
	end

    --Update the bindings for all of the dropdown meter buttons
    getglobal(BSM_DROPDOWNS.."0Key"):SetText(GetBindingText(GetBindingKey("TOGGLEBACKPACK"), "KEY_"));
    getglobal(BSM_DROPDOWNS.."4Key"):SetText(GetBindingText(GetBindingKey("TOGGLEBAG1"), "KEY_"));
    getglobal(BSM_DROPDOWNS.."3Key"):SetText(GetBindingText(GetBindingKey("TOGGLEBAG2"), "KEY_"));
    getglobal(BSM_DROPDOWNS.."2Key"):SetText(GetBindingText(GetBindingKey("TOGGLEBAG3"), "KEY_"));
    getglobal(BSM_DROPDOWNS.."1Key"):SetText(GetBindingText(GetBindingKey("TOGGLEBAG4"), "KEY_"));

    --totalFreeSlots: free slots in all of the bags
	local totalFreeSlots = totalSlots - totalusedSlots;

    --If free slots are used in the overall label, use that number in the slots text instead of used slots
	if ( BSM_Save.slots == BSM_SLOTS_FREE ) then
	        slotsText = totalFreeSlots;
		labelText = BSM_FREEBAGSLOTS;
	else
		slotsText = totalusedSlots;
		slotsText = slotsText.."/"..totalSlots;
		labelText = BSM_USEDBAGSLOTS;
	end

    --Update the text and
    --min, max, and current values of the overall bar
	BSM_FrameText:SetText(slotsText);
	BSM_FrameButtonLabel:SetText(labelText);
	BSM_FrameStatus:SetMinMaxValues(0, totalSlots);
	BSM_FrameStatus:SetValue(totalusedSlots);
		
    --If the overall meter is disabled, then everything else can be ignored
	if ( BSM_Save.overall and BSM_Save.enable ) then
		getglobal(BSM_FRAME):Show();
		getglobal(BSM_OPTIONS_BUTTON):Show();
	else
		getglobal(BSM_FRAME):Hide();
	end

    	BSM_FrameStatus:SetStatusBarColor(BSM_GetColor(totalFreeSlots, totalSlots, 1.0));

    --Update the bank bars if the Bank frame is open
	--[[if getglobal("BSM_Bank_Bars"):IsVisible() then
    	BSM_updateBankBags();
	end]]
end

--BSM_GetColor:
--    Purpose - Get the appropriate color for the bar being updated
--    Parameters - freeSlots: free slots in the bag
--                 totalSlots: number of slots in the bag
--                 alpha: desired opacity of the color
--    Returns - Color for the bar (red, green, blue, alpha)
function BSM_GetColor(freeSlots, totalSlots, alpha)
    local pct = freeSlots / totalSlots;
    local r, g;
    r = 1.0;
    g = 1.0;
	if  pct < 0.5 then
        --r = 1.0;
		g = pct * 2;
	elseif pct > 0.5 then
        r = 1.0 - (pct-0.5) * 2;
        --g = 1.0;
	--elseif pct == 0.5 then
		--Do nothing, both already 1.0
	end
	
	return r, g, 0.0, alpha;
end



--BSM_updateBankBags:
--    Purpose - Update the bank bars when the bank frame is open
--    Parameters - None
--    Returns - Nothing
function BSM_updateBankBags()
    --num: number of slots in the current bank bag
    local num = 0;
    --used: number of used slots in the current bank bag
    local used = 0;
    --slotsText: the text that is to be displayed on the meter labels
	local slotsText = 0;
	--status: the current bar being updated
	local status;
	
    --Loop through for every bank bag
	for bag = 5, 10, 1 do
        --set status to the current bar and get the number of slots in the current bank bag
        status = getglobal(BSM_BANK..(bag-4));
		num = GetContainerNumSlots(bag);
		--if there is no bag in the current bank bag slot, then hide the bar
		if num == 0 then
            status:Hide();
		else
            --Reset the used slots and
            --loop through every slot in the current bank bag and
            --increment the variable if an item exists
			used = 0;
			for slot = 1, num, 1 do
				if GetContainerItemInfo(bag, slot) then
					used = used + 1;
				end
			end
			
            --[[--bar: the bar to the current bank bag
            local bar = getglobal(status:GetName().."Bar");
            --Set the meter's min, max, and current values accordingly
    		bar:SetMinMaxValues(0, num);
    		bar:SetValue(used);
    		--If color is enabled, color the bar according to the ratio of used slots to total slots
    		--Otherwise make it a gray color
    		if BSM_Save.I.color then
        		bar:SetStatusBarColor(BSM_GetColor(num - used, num, 0.6));
        	else
        		bar:SetStatusBarColor(0.5, 0.5, 0.5, 0.6);
        	end]]

			if BSM_Save.slots == BSM_SLOTS_FREE then
		                slotsText = num - used;
			else
		                slotsText = used;
			        slotsText = slotsText.."/"..num;
			end

            status:Show();
            getglobal(status:GetName().."Label"):SetText(slotsText);
		end
	end
end

function BSM_Toggle(toggle)
    if ( toggle == 1 ) then
	BSM_Save.enable = true;
    else
	BSM_Save.enable = false;
    end
    BSM_updateFreeSlots();
end

function BSM_IndividualToggle(toggle)
    if ( toggle == 1 ) then
	BSM_Save.individual = true;
        BSM_EnableAllIndividual();
    else
	BSM_Save.individual = false;
	BSM_DisableAllIndividual();
    end
end

function BSM_OverallToggle(toggle)
    if ( toggle == 1 ) then
	BSM_Save.overall = true;
	if ( BSM_Save.enable ) then
		getglobal(BSM_FRAME):Show();
		getglobal(BSM_OPTIONS_BUTTON):Show();
	end
    else
	BSM_Save.overall = false;
        getglobal(BSM_FRAME):Hide();
	getglobal(BSM_OPTIONS_BUTTON):Hide();
    end
    BSM_updateFreeSlots();
end

function BSM_DropdownToggle(toggle)
    if ( toggle == 1 ) then
	BSM_Save.dropdowns = true;
        getglobal(BSM_DROPDOWNS):Show();
        getglobal(BSM_DROPDOWNS_LABELS):Show();
    else
	BSM_Save.dropdowns = false;
        getglobal(BSM_DROPDOWNS):Hide();
        getglobal(BSM_DROPDOWNS_LABELS):Hide();
    end
end

function BSM_LockToggle(toggle)
    if ( toggle == 1 ) then
	BSM_Save.lock = true;
    else
	BSM_Save.lock = false;
    end
end

function BSM_SlotsToggle(toggle)
    if ( toggle == 1 ) then
	BSM_Save.slots = 1;
    else
	BSM_Save.slots = 0;
    end
    BSM_updateFreeSlots();
end

function BSM_NotifyToggle(toggle)
    if ( toggle == 1 ) then
	BSM_Save.notify = true;
    else
	BSM_Save.notify = false;
    end
    BSM_updateFreeSlots();
end

function BSM_ResetButton()
	BSM_Save.dispX = 0;
	BSM_Save.dispY = -65;
	getglobal(BSM_FRAME):ClearAllPoints();
	getglobal(BSM_FRAME):SetPoint("TOPLEFT", "ChatFrame1", "TOPRIGHT", BSM_Save.dispX, BSM_Save.dispY);
	getglobal(BSM_OPTIONS_BUTTON):Show();
end

--BSM_SetPosition:
--    Purpose - Sets the position of the Overall Meter frame according to what is in the X/Y text boxes in the Options frame
--    Parameters - None
--    Returns - Nothing
function BSM_SetPosition()
    local x, y;
    
    --convert the text in the text boxes to numbers
    x = tonumber(getglobal("BSM_Options_PositionX"):GetText());
    y = tonumber(getglobal("BSM_Options_PositionY"):GetText());
    --if the text converted correctly to a number, set the position of the Overall Meter
    if x then
        BSM_Save.dispX = x;
    end
    if y then
        BSM_Save.dispY = y;
    end
    getglobal(BSM_FRAME):ClearAllPoints();
    getglobal(BSM_FRAME):SetPoint("BOTTOMLEFT", "UIParent", "BOTTOMLEFT", BSM_Save.dispX, BSM_Save.dispY);
end

--BSM_openBag:
--    Purpose - Opens the appropriate bag when hitting a key binding button
--    Parameters - b: the button that was pressed
--    Returns - Nothing
function BSM_openBag(b)
    --name: the name of the button that was pressed
    local name = b:GetName();
    
    --Find the number in the button's name
    name = string.sub( name, string.len(BSM_DROPDOWNS)+1, string.len(BSM_DROPDOWNS)+1 );

    --Convert the number string to an actual number and toggle that bag
    ToggleBag( tonumber(name) );
end
