--[[
HoloFriends addon created by Holo, continued by Zappster, followed by Andymon

Get the latest version at wow.curse.com

See HoloFriends_change.log for more informations  
]]

--[[

This file manages the share-friends dialog

]]

local HF_Num_ScrollFrame_Buttons = 10;
local HF_CharList = {};
local HF_FriendsList = {};

local HF_PDframe = "";
local HF_ActualPlayer = "";
local HF_SelectedFriendsListKey = "";
local HF_CharListCheckedCnt = 0;
local HF_FriendsListCheckedCnt = 0;
local HF_Longlist


local function HFF_CopyFriendslist(list)
	local result = {};
	for key, entry in pairs(list) do
		local temp      = {};
		temp.name       = entry.name
		temp.group      = entry.group;
		temp.share      = false;
		temp.sharegroup = false;
		table.insert(result, temp);
	end
	return result;
end


local function HFF_CopyCharList(list, exclude)
	local faction, faction_lc = UnitFactionGroup("player");
	local result = {};
	for key, entry in pairs(list) do
		if ( entry ~= exclude ) then
			local name = entry;
			if ( name == faction ) then name = faction_lc; end
			local temp = {};
			temp.name  = name;
			temp.share = false;
			table.insert(result, temp);
		end
	end
	return result;
end


local function HFF_RealmGetFactionChars(mark)
	local list = HoloFriendsFuncs_RealmGetAllFactionChars();

	for idx = table.getn(list), 1, -1 do
		if ( not (HoloFriendsFuncs_IsDataAvailable(HOLOFRIENDS_LIST, list[idx])) ) then
			if ( mark ) then
				list[idx] = "("..list[idx]..")"
			else
				table.remove(list, idx);
			end
		end
	end

	return list;
end


local function HFF_CharListRemoveUnavailable(list)
	local faction, faction_lc = UnitFactionGroup("player");
	for idx = table.getn(list), 1, -1 do
		local name = list[idx].name;
		if ( not name ) then name = list[idx]; end
		if ( name == faction_lc ) then name = faction; end
		if ( not (HoloFriendsFuncs_IsDataAvailable(HOLOFRIENDS_LIST, name)) ) then
			if ( list[idx].share ) then
				HF_CharListCheckedCnt = HF_CharListCheckedCnt - 1;
			end
			table.remove(list, idx);
		end
	end
	return list;
end


-- Scroll frame handling

local function HFF_ScrollFrame_Update(list, scrollFrame, btnName)
	local visibleCnt;

	-- get visible index table
	local ShownIndexTable = {};
	ShownIndexTable = HoloFriendsFuncs_ShownListTab(list, HF_Num_ScrollFrame_Buttons);

	-- count visible entries
	local numElementsTable = table.getn(ShownIndexTable);
	local visibleCnt = 0;
	if ( numElementsTable > HF_Num_ScrollFrame_Buttons ) then
		visibleCnt = numElementsTable;
	else
		local numElementsList = table.getn(list);
		for ii = 1, numElementsTable do
			if ( ShownIndexTable[ii] <= numElementsList ) then
				visibleCnt = visibleCnt + 1;
			end
		end
	end

	-- ScrollFrame stuff
	FauxScrollFrame_Update(scrollFrame, visibleCnt, HF_Num_ScrollFrame_Buttons, 16);
	-- scrollframe offset
	local offset = FauxScrollFrame_GetOffset(scrollFrame);

	-- button and textures
	local button, buttonText, buttonIcon, buttonCheck;

	local entry = {};
	local line = 1;

	-- set values / textures for all buttons
	while ( line <= HF_Num_ScrollFrame_Buttons ) do
		local index = ShownIndexTable[line + offset];

		entry = list[index];

		button = getglobal(btnName..line);
		button:SetID(index);

		if ( line > visibleCnt ) then
			button:Hide();
		else
			button:Show();
		end

		if ( entry ) then
			-- get textfields and icon
			buttonText  = getglobal(btnName..line.."Name");
			buttonIcon  = getglobal(btnName..line.."ShareIcon");
			buttonCheck = getglobal(btnName..line.."ShareCheck");

			-- group entry ?
			if ( entry.name == "1" or entry.name == "0" ) then
				buttonText:SetText(entry.group);
				buttonText:SetWidth(110);

				buttonIcon:Hide();
				if ( entry.share ) then
					buttonCheck:SetChecked(true);
				else
					buttonCheck:SetChecked(false);
				end
				buttonCheck:SetID(index);
				buttonCheck:Show();

				if ( entry.name == "1" ) then
					button:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up");
				else
					button:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up");
				end
			else -- no, we got a player
				if ( string.sub(entry.name,1,1) == "(" ) then
					buttonText:SetText("|cff999999"..entry.name.."|r");
				else
					buttonText:SetText(entry.name);
				end
				buttonText:SetWidth(130);

				if ( entry.share ) then
					buttonIcon:Show();
				else
					buttonIcon:Hide();
				end
				if ( buttonCheck ) then buttonCheck:Hide(); end

				button:SetNormalTexture("");
			end

			-- Set the button text with
			button:SetWidth(150);
		end

		line = line + 1;
	end
end


function HoloFriendsShare_SourceScrollFrame_Update()
	HFF_ScrollFrame_Update(HF_FriendsList, HoloFriends_ShareFrame_SourceScrollFrame, "HoloFriends_ShareFrame_Source");
end


function HoloFriendsShare_TargetScrollFrame_Update()
	HFF_ScrollFrame_Update(HF_CharList, HoloFriends_ShareFrame_TargetScrollFrame, "HoloFriends_ShareFrame_Target");
end


-- Overall window functions

local function HFF_ListUpdate()
	local faction = UnitFactionGroup("player");
	HF_Longlist = false;
	if ( HF_SelectedFriendsListKey == faction ) then HF_Longlist = true; end
	HF_CharList = HFF_CopyCharList(HFF_RealmGetFactionChars(HF_Longlist), HF_SelectedFriendsListKey);

	-- be certain, the name exists in HOLOFRIENDS_LIST, otherwise
	-- HoloFriendsFuncs_LoadList() would create a new entry
	if ( HoloFriendsFuncs_IsDataAvailable(HOLOFRIENDS_LIST, HF_SelectedFriendsListKey) ) then
		-- use a copy, not the original data
		local list = HoloFriendsFuncs_LoadList(HOLOFRIENDS_LIST, HF_SelectedFriendsListKey);
		HF_FriendsList = HFF_CopyFriendslist(list);
	else
		HF_FriendsList = {};
	end

	HF_CharListCheckedCnt = 0;
	HF_FriendsListCheckedCnt = 0;

	HoloFriends_ShareFrame_ButtonShareAdd:Disable();
	HoloFriends_ShareFrame_ButtonShareSub:Disable();

	HoloFriendsShare_SourceScrollFrame_Update();
	HoloFriendsShare_TargetScrollFrame_Update();

	if ( HF_SelectedFriendsListKey == faction ) then
		HoloFriends_ShareFrame_FactionButtons_Character1_text:SetText("-");
		HoloFriends_ShareFrame_FactionButtons_ButtonFactionAdd:Disable();
	else
		HoloFriends_ShareFrame_FactionButtons_Character1_text:SetText(HF_SelectedFriendsListKey);
		HoloFriends_ShareFrame_FactionButtons_ButtonFactionAdd:Enable();
	end

	HoloFriends_ShareFrame_FactionButtons_Character2_text:SetText("-");
	HoloFriends_ShareFrame_FactionButtons_ButtonFactionExtract:Disable();
end


function HoloFriendsShare_OnLoad(self)
	self.name = HOLOFRIENDS_SHAREWINDOWTITLE;
	self.parent = HOLOFRIENDS_OPTIONS0LISTENTRY;
	InterfaceOptions_AddCategory(self);

	HoloFriends_DropDownBG_Init();
end


function HoloFriendsShare_OnShow()
	HF_ActualPlayer = UnitName("player");
	if ( not (HoloFriendsFuncs_IsDataAvailable(HOLOFRIENDS_LIST, HF_ActualPlayer)) ) then
		HF_ActualPlayer = UnitFactionGroup("player");
	end

	HF_SelectedFriendsListKey = HF_ActualPlayer;

	for i = 1, HF_Num_ScrollFrame_Buttons do
		getglobal("HoloFriends_ShareFrame_Source"..i.."ShareIcon"):Hide();
		getglobal("HoloFriends_ShareFrame_Target"..i.."ShareIcon"):Hide();
	end

	HFF_ListUpdate();

	-- update actual name to the pull down menu
	if ( HF_PDframe and (HF_PDframe ~= "") ) then
		local name = HF_ActualPlayer;
		if ( name == faction ) then name = faction_lc; end
		UIDropDownMenu_SetText(getglobal(HF_PDframe), name);
	end
end


function HoloFriendsShare_OnHide()
	HF_CharList = {};
	HF_FriendsList = {};
	HF_SelectedFriendsListKey = "";
	HF_CharListCheckedCnt = 0;
	HF_FriendsListCheckedCnt = 0;

	HoloFriendsShareButton:Enable();

	HoloFriends_ShareFrame_FactionButtons_Character1_text:SetText("-");
	HoloFriends_ShareFrame_FactionButtons_ButtonFactionAdd:Disable();

	HoloFriends_ShareFrame_FactionButtons_Character2_text:SetText("-");
	HoloFriends_ShareFrame_FactionButtons_ButtonFactionExtract:Disable();
end


-- Actions on click to one of the two lists

local function HFF_ChangeOnClick(name)
	local faction = UnitFactionGroup("player");

	if ( (HF_FriendsListCheckedCnt > 0) and (HF_CharListCheckedCnt > 0) ) then
		HoloFriends_ShareFrame_ButtonShareAdd:Enable();
		HoloFriends_ShareFrame_ButtonShareSub:Enable();
	else
		HoloFriends_ShareFrame_ButtonShareAdd:Disable();
		HoloFriends_ShareFrame_ButtonShareSub:Disable();
	end

	if ( HF_SelectedFriendsListKey == faction ) then
		if ( (HF_FriendsListCheckedCnt == 0) and (HF_CharListCheckedCnt == 0) and not HF_Longlist ) then
			HF_Longlist = true;
			HF_CharList = HFF_CopyCharList(HFF_RealmGetFactionChars(HF_Longlist), HF_SelectedFriendsListKey);
			HF_CharListCheckedCnt = 0;
			HoloFriendsShare_TargetScrollFrame_Update();
		end

		local change = false;
		if ( (HF_FriendsListCheckedCnt > 0) and HF_Longlist ) then change = true; end
		if ( (HF_CharListCheckedCnt > 0) and HF_Longlist ) then
			if ( HF_CharListCheckedCnt > 1 ) then change = true; end
			if ( name ) then
				if ( string.sub(name,1,1) ~= "(" ) then change = true; end
			else change = true; end
		end
		if ( change ) then
			HF_Longlist = false;
			HF_CharList = HFF_CharListRemoveUnavailable(HF_CharList);
			HoloFriendsShare_TargetScrollFrame_Update();
		end
	end

	if ( (HF_CharListCheckedCnt > 0) or (HF_FriendsListCheckedCnt > 0)
	    or (HF_SelectedFriendsListKey == faction) ) then
		HoloFriends_ShareFrame_FactionButtons_Character1_text:SetText("-");
		HoloFriends_ShareFrame_FactionButtons_ButtonFactionAdd:Disable();
	else
		HoloFriends_ShareFrame_FactionButtons_Character1_text:SetText(HF_SelectedFriendsListKey);
		HoloFriends_ShareFrame_FactionButtons_ButtonFactionAdd:Enable();
	end

	if ( (HF_CharListCheckedCnt == 1) and (HF_FriendsListCheckedCnt == 0)
	    and (HF_SelectedFriendsListKey == faction) and (string.sub(name,1,1) == "(") ) then
		local namelength = string.len(name);
		local sepname = string.sub(name,2,namelength - 1);
		HoloFriends_ShareFrame_FactionButtons_Character2_text:SetText(sepname);
		HoloFriends_ShareFrame_FactionButtons_ButtonFactionExtract:Enable();
	else
		HoloFriends_ShareFrame_FactionButtons_Character2_text:SetText("-");
		HoloFriends_ShareFrame_FactionButtons_ButtonFactionExtract:Disable();
	end
end


-- Actions on click to the source list

function HoloFriendsShare_Source_OnClick(self)
	local icon = getglobal(self:GetName().."ShareIcon");
	local index = self:GetID();

	if ( HoloFriendsFuncs_IsGroup(HF_FriendsList, index) ) then
		if ( HF_FriendsList[index].name == "0" and not HF_FriendsList[index].share ) then
			HF_FriendsList[index].name = "1" --show
		else
			HF_FriendsList[index].name = "0" --collapse
		end
		HoloFriendsShare_SourceScrollFrame_Update();
	else
		-- show/hide checkbox-symbol
		if ( HF_FriendsList[index].share ) then
			HF_FriendsList[index].share = false;
			HF_FriendsListCheckedCnt = HF_FriendsListCheckedCnt - 1;
			icon:Hide();
		else
			HF_FriendsList[index].share = true;
			HF_FriendsListCheckedCnt = HF_FriendsListCheckedCnt + 1;
			icon:Show();
		end

		HFF_ChangeOnClick();
	end
end


-- Actions on click to group check box

local function HFF_ChangeShareGroup(group, set)
	local list = HF_FriendsList;

	for index = 1, table.getn(list) do
		if ( list[index].group == group ) then
			if ( set ) then
				HF_FriendsList[index].share = true;
				HF_FriendsList[index].sharegroup = true;
				HF_FriendsListCheckedCnt = HF_FriendsListCheckedCnt + 1;
			else
				HF_FriendsList[index].share = false;
				HF_FriendsList[index].sharegroup = false;
				HF_FriendsListCheckedCnt = HF_FriendsListCheckedCnt - 1;
			end
		end
	end
end


function HoloFriendsShare_Group_OnClick(self)
	local index = self:GetID();

	if ( HoloFriendsFuncs_IsGroup(HF_FriendsList, index) ) then
		if ( HF_FriendsList[index].share ) then
			-- unset share and sharegroup for all group members
			HFF_ChangeShareGroup(HF_FriendsList[index].group, false)
		else
			-- collapse group list display
			HF_FriendsList[index].name = "0"
			-- set share and sharegroup for all group members
			HFF_ChangeShareGroup(HF_FriendsList[index].group, true)
		end
	end

	HoloFriendsShare_SourceScrollFrame_Update();

	HFF_ChangeOnClick();
end


-- Actions on click to the target list

function HoloFriendsShare_Target_OnClick(self)
	local icon = getglobal(self:GetName().."ShareIcon");
	local index = self:GetID();

	-- show/hide checkbox-symbol
	if ( HF_CharList[index].share ) then
		HF_CharList[index].share = false;
		HF_CharListCheckedCnt = HF_CharListCheckedCnt - 1;
		icon:Hide();
	else
		HF_CharList[index].share = true;
		HF_CharListCheckedCnt = HF_CharListCheckedCnt + 1;
		icon:Show();
	end

	HFF_ChangeOnClick(HF_CharList[index].name);
end


-- Char pulldown menu

function HoloFriendsShare_CharDropDown_OnShow(self)
	HF_PDframe = self:GetName();

	local player = UnitName("player");
	if ( not (HoloFriendsFuncs_IsDataAvailable(HOLOFRIENDS_LIST, player)) ) then
		_, player = UnitFactionGroup("player");
	end

	HoloFriends_DropDownBG_Show();
	UIDropDownMenu_Initialize(self, HoloFriendsShare_CharDropDown_Init);
	UIDropDownMenu_SetText(self, player);
	UIDropDownMenu_SetWidth(self, 160);
end


function HoloFriendsShare_CharDropDown_Init(self)
	local faction, faction_lc = UnitFactionGroup("player");
	for k,value in pairs(HFF_RealmGetFactionChars()) do
		local name = value;
		if ( name == faction ) then name = faction_lc; end
		local info = { };
		info.text = name;
		info.value = value;
		info.func = HoloFriendsShare_CharDropDown_OnClick;
		UIDropDownMenu_AddButton(info);
	end
end


function HoloFriendsShare_CharDropDown_OnClick(self)
	local faction, faction_lc = UnitFactionGroup("player");
	local name = self.value;
	if ( name == faction ) then name = faction_lc; end
	UIDropDownMenu_SetText(HoloFriends_ShareFrame_CharDropDown, name);

	HF_SelectedFriendsListKey = self.value;

	HFF_ListUpdate();
end


-- Functions to perform the sharing

local function HFF_ShareEntry(cname,fkey,sharegroup,addentry)
	local realm = GetCVar("realmName");

	local srclist = HOLOFRIENDS_LIST[realm][HF_SelectedFriendsListKey];
	local tarlist = HOLOFRIENDS_LIST[realm][cname];

	local tarEntry = {};
	local srcEntry = srclist[fkey];

	local name  = srcEntry.name;
	local group = srcEntry.group;

	-- check if destination (target) exist and get the list index
	local cfKey;
	if ( (name ~= "0") and (name ~= "1") ) then
		cfKey = HoloFriendsFuncs_ContainsPlayer(tarlist, name);
	else
		cfKey = HoloFriendsFuncs_ContainsGroup(tarlist, group);
	end

	-- check if target is older than source
	local oldtar = false;
	if ( not addentry and (cfKey ~= nil) ) then
		tarEntry = tarlist[cfKey];
		local lastSeen1 = HoloFriendsLists_GetLastSeen(tarlist, cfKey);
		local lastSeen2 = HoloFriendsLists_GetLastSeen(srclist, fkey);
		if ( lastSeen1 and lastSeen2 ) then
			oldtar = HoloFriendsFuncs_Date1ltDate2(lastSeen1, lastSeen2);
		end
	end

	-- copy values
	tarEntry.name = srcEntry.name;

	-- handle the group entrie according the flags and options
	if ( sharegroup ) then
		-- the group entry is always the first entry in the sorted friends list
		if ( ((name == "0") or (name == "1")) and cfKey and HOLOFRIENDS_OPTIONS.MarkRemove ) then
			-- set the flag .remove for all group members at target list
			-- for not copied entries, the flag is not removed
			for rkey, rval in pairs(tarlist) do
				if ( tarlist[rkey].group == group ) then
					tarlist[rkey].remove = true;
				end
			end
		end
		-- set for actual entry only
		tarEntry.remove = nil;
		tarEntry.group = srcEntry.group;
	elseif ( not cfKey ) then
		if ( (name ~= "0") and (name ~= "1") ) then
			tarEntry.group = FRIENDS;
		else
			tarEntry.group = srcEntry.group;
		end
	end

	-- merge comments according to the options
	local merge = HOLOFRIENDS_OPTIONS.MergeComments;
	local comment = srcEntry.comment;
	local setNote = HoloFriendsFuncs_MergeComment(tarEntry, comment, srcEntry.mergecnt, merge, true);
	if ( comment and (comment ~= "") and not merge and cfKey ) then setNote = true; end

	if ( (name ~= "0") and (name ~= "1") ) then
		if ( not cfKey ) then
			if ( srcEntry.notify ) then
				tarEntry.imported  = true;
				tarEntry.connected = 0;
				tarEntry.notify    = nil;
			end
		elseif ( setNote ) then
			tarEntry.setnote   = true;
		end
		if ( not cfKey or oldtar ) then
			tarEntry.class     = srcEntry.class;
			tarEntry.lc_class  = srcEntry.lc_class;
			tarEntry.level     = srcEntry.level;
			tarEntry.area      = srcEntry.area;
			tarEntry.lastSeen  = srcEntry.lastSeen;
		end
	end

	-- add only, if entry not already exists
	if ( not cfKey ) then
		table.insert(tarlist, tarEntry);
	end
end


function HoloFriendsShare_ShareAdd(add)
	-- data source should be available ...
	if ( not (HoloFriendsFuncs_IsDataAvailable(HOLOFRIENDS_LIST, HF_SelectedFriendsListKey)) ) then
		return;
	end

	local faction, faction_lc = UnitFactionGroup("player");
	for cKey, cVal in pairs(HF_CharList) do
		if ( cVal.share ) then
			local name = cVal.name;
			if ( name == faction_lc ) then name = faction; end
			for fKey, fVal in pairs(HF_FriendsList) do
				if ( fVal.share and not (name == fVal.name) ) then
					HFF_ShareEntry(name, fKey, fVal.sharegroup, add)
				end
			end

			-- update current player's friendslist, if he was a target
			if ( name == HF_ActualPlayer ) then
				HoloFriends_List_Update();
			end
		end
	end

	-- reset selections
	HFF_ListUpdate();
end


function HoloFriendsShare_MergeCharDialog()
	StaticPopup_Show("HOLOSHARE_MERGEFACTION", HF_SelectedFriendsListKey);
end


function HoloFriendsShare_MergeGroupsDialog()
	local faction = UnitFactionGroup("player");
	local realm = GetCVar("realmName");

	local exist = HOLOFRIENDS_LIST[realm][faction];
	if ( not exist ) then
		StaticPopup_Show("HOLOSHARE_MERGEFACTIONPRIORITY");
	else
		StaticPopup_Show("HOLOSHARE_MERGEFACTIONGROUPS", HF_SelectedFriendsListKey);
	end
end


function HoloFriendsShare_MergeChar(sharegroup)
	-- source char data should be available ...
	if ( not (HoloFriendsFuncs_IsDataAvailable(HOLOFRIENDS_LIST, HF_SelectedFriendsListKey)) ) then
		local debug = 1;
		HoloFriends_chat("No data available for "..HF_SelectedFriendsListKey, debug);
		return;
	end

	local faction, faction_lc = UnitFactionGroup("player");
	local realm = GetCVar("realmName");

	local exist = HOLOFRIENDS_LIST[realm][faction];
	if ( not exist ) then
		nlist = HOLOFRIENDS_FACTIONS[realm][faction];
		table.insert(nlist, faction);
		table.sort(nlist, function (a,b) return a < b; end);

		HOLOFRIENDS_LIST[realm][faction] = {};
	end

	for fKey, fVal in pairs(HF_FriendsList) do
		HFF_ShareEntry(faction,fKey,sharegroup,false);
	end

	HOLOFRIENDS_LIST[realm][HF_SelectedFriendsListKey] = nil;

	if ( HF_SelectedFriendsListKey == UnitName("player") ) then
		HoloFriends_LoadList();
		HoloFriends_List_Update();
	end
	if ( HF_ActualPlayer == faction ) then
		HoloFriends_List_Update();
	end

	local msg = format(TEXT(HOLOFRIENDS_MSGFACTIONMERGEDONE), HF_SelectedFriendsListKey);
	HoloFriendsFuncs_SystemMessage(msg);

	HoloFriendsShare_OnShow();
end


function HoloFriendsShare_SeparateChar()
	local debug = 1;
	local faction = UnitFactionGroup("player");

	-- the faction list should be selected
	if ( HF_SelectedFriendsListKey ~= faction ) then
		HoloFriends_chat("No faction list selected: "..HF_SelectedFriendsListKey, debug);
		return;
	end

	local charname = HoloFriends_ShareFrame_FactionButtons_Character2_text:GetText();

	-- charname should be set
	if ( not charname or charname == "-" ) then
		HoloFriends_chat("No char name given", debug);
		return;
	end

	-- destination char data should not exist ...
	if ( HoloFriendsFuncs_IsDataAvailable(HOLOFRIENDS_LIST, charname) ) then
		HoloFriends_chat("Data already existing for "..charname, debug);
		return;
	end

	-- create chars friends list and copy the faction friends list over
	local realm = GetCVar("realmName");
	HOLOFRIENDS_LIST[realm][charname] = {};
	for fKey, fVal in pairs(HF_FriendsList) do
		HFF_ShareEntry(charname,fKey,true,false);
	end

	-- remove the faction friends list, if all chars are separated
	local listall = HoloFriendsFuncs_RealmGetAllFactionChars();
	local list = HFF_RealmGetFactionChars();
	if ( table.getn(listall) == table.getn(list) ) then
		-- includes HoloFriendsShare_OnShow()
		HoloFriendsFuncs_DeleteChar(faction);
	else
		HoloFriendsShare_OnShow();
	end

	-- reload the friends list, if actual player was separated
	if ( charname == UnitName("player") ) then
		HoloFriends_LoadList();
		HoloFriends_List_Update();
	end
end
