--[[------------------------------------------------
	-- Love Frames - A GUI library for LOVE --
	-- Copyright (c) 2013 Kenny Shields --
--]]------------------------------------------------

--[[------------------------------------------------
	-- note: the text wrapping of this object is
			 experimental and not final
--]]------------------------------------------------

-- text class
local newobject = loveframes.NewObject("text", "loveframes_object_text", true)

--[[---------------------------------------------------------
	- func: initialize()
	- desc: initializes the object
--]]---------------------------------------------------------
function newobject:initialize()

	self.type = "text"
	self.text = ""
	self.font = loveframes.basicfont
	self.width = 5
	self.height = 5
	self.maxw = 0
	self.shadowxoffset = 1
	self.shadowyoffset = 1
	self.formattedtext = {}
	self.original = {}
	self.defaultcolor = {0, 0, 0, 255}
	self.shadowcolor = {0, 0, 0, 255}
	self.ignorenewlines = false
	self.shadow = false
	self.internal = false
	
end

--[[---------------------------------------------------------
	- func: update(deltatime)
	- desc: updates the object
--]]---------------------------------------------------------
function newobject:update(dt)

	local state = loveframes.state
	local selfstate = self.state
	
	if state ~= selfstate then
		return
	end
	
	local visible = self.visible
	local alwaysupdate = self.alwaysupdate
	
	if not visible then
		if not alwaysupdate then
			return
		end
	end
	
	local parent = self.parent
	local base = loveframes.base
	local update = self.Update
	
	self:CheckHover()
	
	-- move to parent if there is a parent
	if parent ~= base then
		self.x = self.parent.x + self.staticx
		self.y = self.parent.y + self.staticy
	end
	
	if update then
		update(self, dt)
	end
	
end

--[[---------------------------------------------------------
	- func: draw()
	- desc: draws the object
--]]---------------------------------------------------------
function newobject:draw()

	local state = loveframes.state
	local selfstate = self.state
	
	if state ~= selfstate then
		return
	end
	
	if not self.visible then
		return
	end
	
	local skins = loveframes.skins.available
	local skinindex = loveframes.config["ACTIVESKIN"]
	local defaultskin = loveframes.config["DEFAULTSKIN"]
	local selfskin = self.skin
	local skin = skins[selfskin] or skins[skinindex]
	local drawfunc = skin.DrawText or skins[defaultskin].DrawText
	local draw = self.Draw
	local drawcount = loveframes.drawcount
	
	-- set the object's draw order
	self:SetDrawOrder()
		
	if draw then
		draw(self)
	else
		drawfunc(self)
	end

	self:DrawText()
	
end

--[[---------------------------------------------------------
	- func: mousepressed(x, y, button)
	- desc: called when the player presses a mouse button
--]]---------------------------------------------------------
function newobject:mousepressed(x, y, button)

	local state = loveframes.state
	local selfstate = self.state
	
	if state ~= selfstate then
		return
	end
	
	local visible = self.visible
	
	if not visible then
		return
	end
	
	local hover = self.hover
	
	if hover and button == "l" then
		local baseparent = self:GetBaseParent()
		if baseparent and baseparent.type == "frame" then
			baseparent:MakeTop()
		end
	end
	
end

--[[---------------------------------------------------------
	- func: SetText(text)
	- desc: sets the object's text
--]]---------------------------------------------------------
function newobject:SetText(t)
	
	local dtype = type(t)
	local maxw = self.maxw
	local font = self.font
	local defaultcolor = self.defaultcolor
	local inserts = {}
	local prevfont = font
	local tdata, prevcolor
	
	self.text = ""
	self.formattedtext = {}
	
	if dtype == "string" then
		tdata = {t}
		self.original = {t}
	elseif dtype == "number" then
		tdata = {tostring(t)}
		self.original = {tostring(t)}
	elseif dtype == "table" then
		tdata = t
		self.original = t
	else
		return
	end
	
	for k, v in ipairs(tdata) do
		dtype = type(v)
		if k == 1 and dtype ~= "table" then
			prevcolor = defaultcolor
		end
		if dtype == "table" then
			prevcolor = v
		elseif dtype == "userdata" then
			prevfont = v
		elseif dtype == "number" then
			table.insert(self.formattedtext, {font = prevfont, color = prevcolor, text = tostring(v)})
		elseif dtype == "string" then
			if self.ignorenewlines then
				v = v:gsub(" \n ", " ")
				v = v:gsub("\n", "")
			end
			v = v:gsub(string.char(9), "    ")
			local parts = loveframes.util.SplitString(v, " ")
			for i, j in ipairs(parts) do
				table.insert(self.formattedtext, {font = prevfont, color = prevcolor, text = j})
			end
		end
	end
	
	if maxw > 0 then
		for k, v in ipairs(self.formattedtext) do
			local data = v.text
			local width = v.font:getWidth(data)
			local curw = 0
			local new = ""
			local key = k
			if width > maxw then
				table.remove(self.formattedtext, k)
				for n=1, #data do	
					local item = data:sub(n, n)
					local itemw = v.font:getWidth(item)
					if n ~= #data then
						if (curw + itemw) > maxw then
							table.insert(inserts, {key = key, font = v.font, color = v.color, text = new})
							new = item
							curw = 0 + itemw
							key = key + 1
						else
							new = new .. item
							curw = curw + itemw
						end
					else
						new = new .. item
						table.insert(inserts, {key = key, font = v.font, color = v.color, text = new})
					end
				end
			end
		end
	end
	
	for k, v in ipairs(inserts) do
		table.insert(self.formattedtext, v.key, {font = v.font, color = v.color, text = v.text})
	end
	
	local textdata = self.formattedtext
	local maxw = self.maxw
	local font = self.font
	local twidth = 0
	local drawx = 0
	local drawy = 0
	local lines = 0
	local textwidth = 0
	local lastwidth = 0
	local totalwidth = 0
	local x = self.x
	local y = self.y
	local prevtextwidth = 0
	local prevtextheight = 0
	local prevlargestheight = 0
	local largestwidth = 0
	local largestheight = 0
	local initialwidth = 0
	
	for k, v in ipairs(textdata) do
		local text = v.text
		local color = v.color
		if type(text) == "string" then
			self.text = self.text .. text
			local width = v.font:getWidth(text)
			local height = v.font:getHeight("a")
			if height > largestheight then
				largestheight = height
				prevlargestheight = height
			end
			totalwidth = totalwidth + width
			if maxw > 0 then
				if k ~= 1 then
					if string.byte(text) == 10 then
						twidth = 0
						drawx = 0
						width = 0
						drawy = drawy + largestheight
						largestheight = 0
						text = ""
					elseif (twidth + width) > maxw then
						twidth = 0 + width
						drawx = 0
						drawy = drawy + largestheight
						largestheight = 0
					else
						twidth = twidth + width
						drawx = drawx + prevtextwidth
					end
				else
					twidth = twidth + width
				end
				prevtextwidth = width
				prevtextheight = height
				v.x = drawx
				v.y = drawy
			else
				if k ~= 1 then
					if string.byte(text) == 10 then
						twidth = 0
						drawx = 0
						width = 0
						drawy = drawy + largestheight
						largestheight = 0
						text = ""
						if lastwidth < textwidth then
							lastwidth = textwidth
						end
						if largestwidth < textwidth then
							largestwidth = textwidth
						end
						textwidth = 0
					else
						drawx = drawx + prevtextwidth
						textwidth = textwidth + width
					end
				else
					initialwidth = width
				end
				prevtextwidth = width
				prevtextheight = height
				v.x = drawx
				v.y = drawy
			end
		end
	end
	
	if lastwidth == 0 then
		textwidth = totalwidth
	end
	
	if textwidth < largestwidth then
		textwidth = largestwidth + initialwidth
	end
	
	if maxw > 0 then
		self.width = maxw
	else
		self.width = textwidth
	end
	
	self.height = drawy + prevlargestheight
	
end

--[[---------------------------------------------------------
	- func: GetText()
	- desc: gets the object's text
--]]---------------------------------------------------------
function newobject:GetText()

	return self.text
	
end

--[[---------------------------------------------------------
	- func: GetFormattedText()
	- desc: gets the object's formatted text
--]]---------------------------------------------------------
function newobject:GetFormattedText()

	return self.formattedtext
	
end

--[[---------------------------------------------------------
	- func: DrawText()
	- desc: draws the object's text
--]]---------------------------------------------------------
function newobject:DrawText()

	local textdata = self.formattedtext
	local x = self.x
	local y = self.y
	local shadow = self.shadow
	local shadowxoffset = self.shadowxoffset
	local shadowyoffset = self.shadowyoffset
	local shadowcolor = self.shadowcolor
	local inlist, list = self:IsInList()
	
	for k, v in ipairs(textdata) do
		local text = v.text
		local color = v.color
		local font = v.font
		local theight = font:getHeight("a")
		if inlist then
			if (y + v.y) <= (list.y + list.height) and self.y + ((v.y + theight)) >= list.y then
				love.graphics.setFont(font)
				if shadow then
					love.graphics.setColor(unpack(shadowcolor))
					love.graphics.print(text, x + v.x + shadowxoffset, y + v.y + shadowyoffset)
				end
				love.graphics.setColor(unpack(color))
				love.graphics.print(text, x + v.x, y + v.y)
			end
		else
			love.graphics.setFont(font)
			if shadow then
				love.graphics.setColor(unpack(shadowcolor))
				love.graphics.print(text, x + v.x + shadowxoffset, y + v.y + shadowyoffset)
			end
			love.graphics.setColor(unpack(color))
			love.graphics.print(text, x + v.x, y + v.y)
		end
	end
	
end

--[[---------------------------------------------------------
	- func: SetMaxWidth(width)
	- desc: sets the object's maximum width
--]]---------------------------------------------------------
function newobject:SetMaxWidth(width)

	local original = self.original
	
	self.maxw = width
	self:SetText(original)
	
end

--[[---------------------------------------------------------
	- func: GetMaxWidth()
	- desc: gets the object's maximum width
--]]---------------------------------------------------------
function newobject:GetMaxWidth()

	return self.maxw
	
end

--[[---------------------------------------------------------
	- func: SetWidth(width)
	- desc: sets the object's width
--]]---------------------------------------------------------
function newobject:SetWidth(width)

	self:SetMaxWidth(width)
	
end

--[[---------------------------------------------------------
	- func: SetHeight()
	- desc: sets the object's height
--]]---------------------------------------------------------
function newobject:SetHeight(height)
	
	return
	
end

--[[---------------------------------------------------------
	- func: SetSize()
	- desc: sets the object's size
--]]---------------------------------------------------------
function newobject:SetSize(width, height)

	self:SetMaxWidth(width)
	
end

--[[---------------------------------------------------------
	- func: SetFont(font)
	- desc: sets the object's font
	- note: font argument must be a font object
--]]---------------------------------------------------------
function newobject:SetFont(font)

	local original = self.original
	
	self.font = font
	
	if original then
		self:SetText(original)
	end
	
end

--[[---------------------------------------------------------
	- func: GetFont()
	- desc: gets the object's font
--]]---------------------------------------------------------
function newobject:GetFont()

	return self.font
	
end

--[[---------------------------------------------------------
	- func: GetLines()
	- desc: gets the number of lines the object's text uses
--]]---------------------------------------------------------
function newobject:GetLines()

	return self.lines
	
end

--[[---------------------------------------------------------
	- func: SetIgnoreNewlines(bool)
	- desc: sets whether the object should ignore \n or not
--]]---------------------------------------------------------
function newobject:SetIgnoreNewlines(bool)

	self.ignorenewlines = bool
	
end

--[[---------------------------------------------------------
	- func: GetIgnoreNewlines()
	- desc: gets whether the object should ignore \n or not
--]]---------------------------------------------------------
function newobject:GetIgnoreNewlines()

	return self.ignorenewlines
	
end

--[[---------------------------------------------------------
	- func: SetShadow(bool)
	- desc: sets whether or not the object should draw a
			shadow behind its text
--]]---------------------------------------------------------
function newobject:SetShadow(bool)

	self.shadow = bool
	
end

--[[---------------------------------------------------------
	- func: GetShadow()
	- desc: gets whether or not the object should draw a
			shadow behind its text
--]]---------------------------------------------------------
function newobject:GetShadow()

	return self.shadow
	
end

--[[---------------------------------------------------------
	- func: SetShadowOffsets(offsetx, offsety)
	- desc: sets the object's x and y shadow offsets
--]]---------------------------------------------------------
function newobject:SetShadowOffsets(offsetx, offsety)

	self.shadowxoffset = offsetx
	self.shadowyoffset = offsety
	
end

--[[---------------------------------------------------------
	- func: GetShadowOffsets()
	- desc: gets the object's x and y shadow offsets
--]]---------------------------------------------------------
function newobject:GetShadowOffsets()

	return self.shadowxoffset, self.shadowyoffset
	
end

--[[---------------------------------------------------------
	- func: SetShadowColor(r, g, b, a)
	- desc: sets the object's shadow color
--]]---------------------------------------------------------
function newobject:SetShadowColor(r, g, b, a)
	
	self.shadowcolor = {r, g, b, a}
	
end

--[[---------------------------------------------------------
	- func: GetShadowColor()
	- desc: gets the object's shadow color
--]]---------------------------------------------------------
function newobject:GetShadowColor()
	
	return self.shadowcolor
	
end

--[[---------------------------------------------------------
	- func: SetDefaultColor(r, g, b, a)
	- desc: sets the object's default text color
--]]---------------------------------------------------------
function newobject:SetDefaultColor(r, g, b, a)

	self.defaultcolor = {r, g, b, a}
	
end

--[[---------------------------------------------------------
	- func: GetDefaultColor()
	- desc: gets the object's default text color
--]]---------------------------------------------------------
function newobject:GetDefaultColor()

	return self.defaultcolor
	
end