--[[
ChatEdit
by Karl Isenberg

Brought to you by the author of ChatScroll:
No more clumsy chat edit interfaces. Just click-it and edit.
]]--

CHAT_EDIT_MAX_LINES = 500;
CHAT_EDIT_HOVER_SCROLL_TIMER = 1/10;

for i=1, 7 do
	getglobal("ChatFrame"..i):SetMaxLines(CHAT_EDIT_MAX_LINES);
end

ChatEdit = {};

function ChatEdit:Hide()
	ChatEditScrollFrameEditBox:ClearFocus();
	self:RestoreNormalChat(ChatEditScrollFrame:GetParent():GetID());
	ChatEditScrollFrame:Hide();
end

function ChatEdit:RefuseUpdate()
	if (type(ChatEditScrollFrame.text) == "string") then
		ChatEditScrollFrameEditBox:SetText(ChatEditScrollFrame.text);
	else
		ChatEdit:Hide();
		ChatEditScrollFrameEditBox:SetText("");
	end
end

function ChatEdit:Show(id)
	if (ChatEditScrollFrame:IsVisible()) then
		if (id == ChatEditScrollFrame:GetParent():GetID()) then
			return
		end
		ChatEdit:Hide();
	end
	
	local name, fontSize, r, g, b, a, shown, locked, docked = GetChatWindowInfo(id);
	local chatFrame = getglobal("ChatFrame"..id);
	ChatEditScrollFrame:SetParent(chatFrame);
	ChatEditScrollFrame:SetAllPoints(chatFrame);
	ChatEditScrollFrame:SetScrollChild(ChatEditScrollFrameEditBox);
	--ChatEditScrollFrameEditBox:SetAllPoints(ChatEditScrollFrame);
	if (docked) then
		ChatEditScrollFrameEditBox:SetWidth(DEFAULT_CHAT_FRAME:GetWidth());
	else
		ChatEditScrollFrameEditBox:SetWidth(chatFrame:GetWidth());
	end
	
	--ChatEditScrollFrameEditBox:SetTextInsets(0,0,0,2)
	
	-- Get Chat Text
	self:UpdateText(id);
	
	if (ChatEditScrollFrame:IsShown()) then
		self:RestoreNormalChat(ChatEditScrollFrame:GetParent():GetID());
	end
	self:HideNormalChat(id);
	
	ChatEditScrollFrame:Show();
	
	-- Update Font and Size
	ChatEditScrollFrameEditBox:SetFontObject(chatFrame:GetFontObject())
	local font, size = ChatEditScrollFrameEditBox:GetFont()
	ChatEditScrollFrameEditBox:SetFont(font, fontSize) 
	
	-- Set Content
	ChatEditScrollFrameEditBox:SetText(ChatEditScrollFrame.text);
	
	-- Set flag to scroll to bottom OnScrollRangeChanged and adjust the hit rect
	self.newText = true;
	ChatEditScrollFrame:UpdateScrollChildRect();
	
	self.hoverUp = getglobal(chatFrame:GetName().."ResizeTop")
	self.hoverDown = getglobal(chatFrame:GetName().."ResizeBottom")

	--/z for i=123456111000, 123456112300 do Sea.io.print(i) end
end

function ChatEdit:UpdateText(id)
	local text = ""
	for line=1, getn(ChatEditScrollFrame.chatData[id]) do
		text = text..ChatEditScrollFrame.chatData[id][line].."\n"
	end
	text = text.."\n "
	ChatEditScrollFrame.text = text
end

function ChatEdit:GetChatOffset(id, chatFrame, font, fontSize)
	-- Impossible to calculate line wraps by measuring line
	-- Scroll Conversion by Emulation
	--[[
	ChatEditScrollFrameMessageFrame:ClearAllPoints();
	ChatEditScrollFrameMessageFrame = nil
	local smf = CreateFrame("MessageFrame", "ChatEditScrollFrameMessageFrame", ChatEditScrollFrame);
	smf:Hide()
	smf:SetPoint("TOPLEFT", ChatEditScrollFrame, "TOPLEFT")
	ChatEditScrollFrame:SetScrollChild(smf);
	smf:SetWidth(ChatEditScrollFrameEditBox:GetWidth());
	smf:SetFont(font, fontSize)
	for line=1, getn(ChatEditScrollFrame.chatData[id]) - chatFrame:GetCurrentScroll() do
		smf:AddMessage(ChatEditScrollFrame.chatData[id][line])
	end
	local height = smf:GetHeight()
	ChatEditScrollFrame:SetScrollChild(ChatEditScrollFrameEditBox);
	return height
	]]--
	return ChatEditScrollFrame:GetVerticalScrollRange()
end

function ChatEdit:HideNormalChat(id)
	local chatFrame = getglobal("ChatFrame"..id);
	if (not self.CurrentScroll) then
		self.CurrentScroll = {}
	end
	local temp = chatFrame:GetCurrentScroll()
	if (temp > 0 or not self.CurrentScroll[id]) then
		self.CurrentScroll[id] = temp
	end
	chatFrame:SetScrollFromBottom(0)
	
	if (not self.FadeTimes) then
		self.FadeTimes = {}
	end
	temp = chatFrame:GetFadeDuration()
	if (temp > 0.1 or not self.FadeTimes[id]) then
		self.FadeTimes[id] = temp
	end
	chatFrame:SetFadeDuration(0.1)
	
	if (not self.TimesVisible) then
		self.TimesVisible = {}
	end
	temp = chatFrame:GetTimeVisible()
	if (temp > 0 or not self.TimesVisible[id]) then
		self.TimesVisible[id] = temp
	end
	chatFrame:SetTimeVisible(0)
	
	--Hook Chat Frame scrolling
	Sea.util.hook("ChatFrame"..id..".ScrollUp", "ChatEdit.ChatFrameScrollUp", "replace");
	Sea.util.hook("ChatFrame"..id..".ScrollDown", "ChatEdit.ChatFrameScrollDown", "replace");
	Sea.util.hook("ChatFrame"..id..".PageUp", "ChatEdit.ChatFramePageUp", "replace");
	Sea.util.hook("ChatFrame"..id..".PageDown", "ChatEdit.ChatFramePageDown", "replace");
	Sea.util.hook("ChatFrame"..id..".ScrollToTop", "ChatEdit.ScrollToTop", "replace");
	Sea.util.hook("ChatFrame"..id..".ScrollToBottom", "ChatEdit.ScrollToBottom", "replace");
end

function ChatEdit:RestoreNormalChat(id)
	local chatFrame = getglobal("ChatFrame"..id);
	if (self.CurrentScroll and self.CurrentScroll[id]) then
		chatFrame:SetScrollFromBottom(self.CurrentScroll[id])
	end
	
	if (self.FadeTimes and self.FadeTimes[id]) then
		chatFrame:SetFadeDuration(self.FadeTimes[id])
	end
	
	if (self.TimesVisible and self.TimesVisible[id]) then
		chatFrame:SetTimeVisible(self.TimesVisible[id])
	end
	
	chatFrame:SetScrollFromBottom(chatFrame:GetCurrentScroll())
	
	-- Unhook Chat Frame scrolling
	Sea.util.unhook("ChatFrame"..id..".ScrollUp", "ChatEdit.ChatFrameScrollUp", "replace");
	Sea.util.unhook("ChatFrame"..id..".ScrollDown", "ChatEdit.ChatFrameScrollDown", "replace");
	Sea.util.unhook("ChatFrame"..id..".PageUp", "ChatEdit.ChatFramePageUp", "replace");
	Sea.util.unhook("ChatFrame"..id..".PageDown", "ChatEdit.ChatFramePageDown", "replace");
	Sea.util.unhook("ChatFrame"..id..".ScrollToTop", "ChatEdit.ScrollToTop", "replace");
	Sea.util.unhook("ChatFrame"..id..".ScrollToBottom", "ChatEdit.ScrollToBottom", "replace");
end

function ChatEdit.ChatFrameScrollUp(chatFrame)
	local currScroll = ChatEditScrollFrame:GetVerticalScroll()
	if (currScroll <= 0 ) then
		return
	end
	local name, fontSize, r, g, b, a, shown, locked, docked = GetChatWindowInfo(chatFrame:GetID());
	ChatEditScrollFrame:SetVerticalScroll(currScroll - fontSize)
end

function ChatEdit.ChatFrameScrollDown(chatFrame)
	local currScroll = ChatEditScrollFrame:GetVerticalScroll()
	local maxScroll = ChatEditScrollFrameEditBox:GetHeight() - chatFrame:GetHeight();
	if (currScroll >= maxScroll ) then
		return
	end
	local name, fontSize, r, g, b, a, shown, locked, docked = GetChatWindowInfo(chatFrame:GetID());
	ChatEditScrollFrame:SetVerticalScroll(currScroll + fontSize)
end

function ChatEdit.ChatFramePageUp(chatFrame)
	local currScroll = ChatEditScrollFrame:GetVerticalScroll()
	if (currScroll <= 0 ) then
		return
	end
	local name, fontSize, r, g, b, a, shown, locked, docked = GetChatWindowInfo(chatFrame:GetID())
	local newScroll = currScroll - chatFrame:GetHeight() + fontSize
	if (newScroll <= 0 ) then
		ChatEditScrollFrame:SetVerticalScroll(0)
	else
		ChatEditScrollFrame:SetVerticalScroll(newScroll)
	end
end

function ChatEdit.ChatFramePageDown(chatFrame)
	local currScroll = ChatEditScrollFrame:GetVerticalScroll()
	local maxScroll = ChatEditScrollFrame:GetVerticalScrollRange()
	if (currScroll >= maxScroll ) then
		return
	end
	local name, fontSize, r, g, b, a, shown, locked, docked = GetChatWindowInfo(chatFrame:GetID())
	local newScroll = currScroll + chatFrame:GetHeight() - fontSize
	if (newScroll >= maxScroll ) then
		ChatEditScrollFrame:SetVerticalScroll(maxScroll)
	else
		ChatEditScrollFrame:SetVerticalScroll(newScroll)
	end
end

function ChatEdit:ScrollToTop()
	ChatEditScrollFrame:SetVerticalScroll(0)
end

function ChatEdit:ScrollToBottom()
	ChatEditScrollFrame:SetVerticalScroll(ChatEditScrollFrame:GetVerticalScrollRange())
end

--[[
function ChatEdit.OnMouseWheel()
	if ( IsShiftKeyDown() ) then
		if ( arg1 > 0 ) then
			ChatEditScrollFrame:ScrollToTop()
		elseif ( arg1 < 0 ) then
			ChatEditScrollFrame:ScrollToBottom();
		end
	else
		if ( arg1 > 0 ) then
			ChatEditScrollFrame:ScrollUp();
		elseif ( arg1 < 0 ) then
			ChatEditScrollFrame:ScrollDown();
		end
	end
end
]]--

function ChatEdit:OnLoad()
	this:RegisterEvent("PLAYER_ENTERING_WORLD");
	local chatData = {}
	for id=1, NUM_CHAT_WINDOWS do
		-- init curr text storage
		chatData[id] = {}
	end
	this.chatData = chatData;
	
	ScrollFrame_OnLoad();
end

function ChatEdit.ColorText(text, r, g, b)
	local color = "|c"..format("FF%.2X%.2X%.2X", (r or 1) * 255, (g or 1) * 255, (b or 1) * 255);
	text = gsub(text, "|r", color)
	text = color..text.."|r"
	return text
end

-- after hook
-- Insert at the end, remove from the front
-- only store as many as are normally visible
function ChatEdit.ChatFrameAddMessage(self, text, r, g, b, lineID)
	local id = self:GetID()
	if (type(text) ~= "string") then
		return;
	end
	table.insert(ChatEditScrollFrame.chatData[id], ChatEdit.ColorText(text, r, g, b))
	if (getn(ChatEditScrollFrame.chatData[id]) > self:GetMaxLines()) then
		table.remove(ChatEditScrollFrame.chatData[id], 1)
	end
end

function ChatEdit.WorldFrameOnMouseDown()
	if (arg1 == "LeftButton" and IsShiftKeyDown()) then
		local chatFrame;
		for id=1, NUM_CHAT_WINDOWS do
			chatFrame = getglobal("ChatFrame"..id);
			if (chatFrame:IsVisible() and MouseIsOver(chatFrame)) then
				ChatEdit:Show(id);
				return;
			end
		end
	elseif (ChatEditScrollFrame:IsVisible()) then
		if (MouseIsOver(ChatEditScrollFrame)) then
			ChatEditScrollFrameEditBox:SetFocus(1);
		else
			ChatEdit:Hide()
		end
	end
end

function ChatEdit:SetUpHooks()
	if (not self.hooksInPlace) then
		for id=1, NUM_CHAT_WINDOWS do
			-- hook AddMessage
			Sea.util.hook("ChatFrame"..id..".AddMessage", "ChatEdit.ChatFrameAddMessage", "after");
		end
		Sea.util.hook("WorldFrame", "ChatEdit.WorldFrameOnMouseDown", "after", "OnMouseDown");
		--WorldFrame:SetScript("OnMouseDown", ChatEdit.WorldFrameOnMouseDown);
		self.hooksInPlace = true;
	end
end

function ChatEdit:OnEvent()
	if (event == "PLAYER_ENTERING_WORLD") then
		self:SetUpHooks()
	end
end

function ChatEdit:OnSizeChanged()
	local name, fontSize, r, g, b, a, shown, locked, docked = GetChatWindowInfo(this:GetParent():GetID());
	if (docked) then
		ChatEditScrollFrameEditBox:SetWidth(DEFAULT_CHAT_FRAME:GetWidth());
	else
		ChatEditScrollFrameEditBox:SetWidth(this:GetWidth());
	end
end

function ChatEdit:OnScrollRangeChanged()
	ScrollFrame_OnScrollRangeChanged(arg2);
	if (self.newText) then
		ChatEdit:ScrollToBottom();
		self.newText = nil;
	end
end

function ChatEdit:OnUpdate()
	if (MouseIsOver(self.hoverUp)) then
		if (not self.scrollTimer) then
			self.scrollTimer = GetTime();
		elseif (GetTime() > (self.scrollTimer + CHAT_EDIT_HOVER_SCROLL_TIMER)) then
			-- scroll up
			ChatEdit.ChatFrameScrollUp(ChatEditScrollFrame:GetParent())
			self.scrollTimer = GetTime();
		end
		
	elseif (MouseIsOver(self.hoverDown)) then
		if (not self.scrollTimer) then
			self.scrollTimer = GetTime();
		elseif (GetTime() > (self.scrollTimer + CHAT_EDIT_HOVER_SCROLL_TIMER)) then
			-- scroll down
			ChatEdit.ChatFrameScrollDown(ChatEditScrollFrame:GetParent())
			self.scrollTimer = GetTime();
		end
		
	elseif (self.ScrollTimer) then
		self.scrollTimer = nil;
		
	end
end

function ChatEdit:OnMouseDown()
	this:SetScript("OnUpdate", function() ChatEdit:OnUpdate() end)
end

function ChatEdit:OnMouseUp()
	this:SetScript("OnUpdate", nil)
end

function ChatEdit:OnHide()
	this:SetScript("OnUpdate", nil)
end
