
--===================================================
--										Area
--===================================================	

function GHU_Area(_parent,_width,_height,_xOff,_yOff)
	assert(type(_width)=="number","Line must be created with a width");
	assert(type(_xOff)=="number" and type(_yOff)=="number");
	assert(_parent.GetType and _parent:GetType()=="GHU_Page",_parent.GetType and _parent:GetType());
	
	local class = Class("GHU_Area");
	local parent,gui;
	
	local lines = {};
	local focusLine;
	local needUpdate,enabled;
	local width,height,xOff,yOff = _width,_height,_xOff,_yOff;
	
	
	
	-- ********* local functions **********
	local function GetLineIndex(line) 
		for i,o in pairs(lines) do
			if o == line then 
				return i;
			end
		end
		return;	
	end
	
	-- ********* public functions **********
	class.BackwardsDelete = function(self)
		if focusLine then
			if focusLine:BackwardsDelete() then
				
			end
		end
	end
	class.DeleteSelected = function(self)
	
	end
	class.Dispose = function(self)
	
	end
	class.ForwardDelete = function(self)
	
	end
	class.GetFocus = function(self)
	
	end
	class.GetFocusCoordinate = function(self)
		if focusLine then
			local x,y,font = focusLine:GetFocusCoordinate();
			return x+xOff,y+yOff,font;		
		end
	end
	class.GetGui = function(self)
		return gui;
	end
	class.GetHeight = function(self)
		return height;
	end
	class.GetLine = function(self,i)
		return lines[i];
	end
	class.GetLineIndex = function(self,line)
	
	end
	class.GetNumLines = function(self)
		return #(lines);
	end
	class.GetOffset = function(self) 
		return xOff,yOff;
	end
	class.GetParent = function(self)
		return parent;
	end
	class.GetPos = function(self,x,y,onlyFocusable)
		x,y = x-xOff,y-yOff;
		-- determine the line at the given x,y coordinate.
		local lastIndex = 0;
		for i,line in pairs(lines) do
			if line:IsEnabled() then
				if abs(line:GetOffset()) + line:GetHeight() > y then
					return i,line:GetPos(x,y,onlyFocusable);
				end	
				lastIndex = i;
			end
		end
		if lastIndex and lines[lastIndex] then
			return lastIndex,lines[lastIndex]:GetPos(x,y,onlyFocusable);
		end
		return;
	end
	class.GetSelection = function(self)
	
	end
	class.GetWidth = function(self)
		return width;
	end
	class.Hide = function(self)
	
	end
	class.InsertLine = function(self,line)
		-- check the input
		assert(line.IsClass and line:IsClass("GHU_Line"),"Inserted line must be of type GHU_Line");
		
		table.insert(lines,line);
		needUpdate = true
	end
	class.InsertText = function(self,str)
		if focusLine and focusLine:IsEnabled() then
			focusLine:InsertText(str);
		end
		needUpdate = true;
	end
	
	class.MoveLeft = function(self)
		if focusLine then
			if (focusLine:MoveLeft()) then
				local i = GetLineIndex(focusLine);
				if i > 1 then
					focusLine = lines[i-1];
					focusLine:MoveEnd();
				else
					return true; -- no more lines in the area
				end			
			end
		end
	end
	class.MoveRight = function(self)
		if focusLine then
			if (focusLine:MoveRight()) then
				local i = GetLineIndex(focusLine);
				
				if i < #(lines) then 
					focusLine = lines[i+1];
					focusLine:MoveHome();
				else
					return true; -- no more lines in the area
				end		
			end
		end
	end
	class.MoveHome = function(self)
		if focusLine then
			focusLine:MoveHome();	
		else
			focusLine = lines[1];
			focusLine:MoveHome();
		end
	end
	class.MoveEnd = function(self)
		if focusLine then
			focusLine:MoveEnd();
		else
			focusLine = lines[#(lines)];
			focusLine:MoveEnd();		
		end
	end
	class.MoveUp = function(self)
		if focusLine then
			local i = GetLineIndex(focusLine);
			local x,y = focusLine:GetFocusCoordinate();
					
			if i > 1 then
				-- look at previous line
				focusLine = lines[i-1];
				--print("Move focus",x,y);
				focusLine:SetFocus(focusLine:GetPos(x,y,true));			
			else
				-- this is first line
				return true;			
			end
			
		end
	end
	class.MoveDown = function(self)
		if focusLine then
			local i = GetLineIndex(focusLine);
			local x,y = focusLine:GetFocusCoordinate();
					
			if i < #(lines) then
				-- look at next line
				focusLine = lines[i+1];
				focusLine:SetFocus(focusLine:GetPos(x,y,true));			
			else
				-- this is first line
				return true;			
			end
			
		end
	end
	class.NeedsUpdate = function(self)
		return needUpdate;	
	end
	class.SetFocus = function(self,lineI,...)
		if lineI == nil then -- remove focus in case of lineI being nil
			if focusLine then
				focusLine:SetFocus(nil);
			end
			focusLine = nil;
			return		
		end
	
		assert(lines[lineI],"Focus line index out of bounds");
		
		local newFocusLine = lines[lineI];
		
		-- remove focus from old 
		if focusLine and not(newFocusLine == focusLine) then -- same Line
			focusLine:SetFocus(nil);			
		end
		
		-- set focus in new
		local x,y,font = newFocusLine:SetFocus(...);
		focusLine=newFocusLine;
		return x+xOff,y+yOff,font;
	end
	class.SetHeight = function(self)
	
	end
	class.SetOffset = function(self)
	
	end
	class.SetSelection = function(self)
	
	end
	class.SetWidth = function(self)
	
	end
	class.Show = function(self)
		gui:Show();
		for _,line in pairs(lines) do
			line:Show();		
		end
	end
	class.Update = function(self)
		local offset = 0;
		local objects = {};
		local i = 1;
		while i <= #(lines) do 
			local line = lines[i];
			line:Show();
			if line:NeedsUpdate() or #(objects) > 0 then
				-- insert the surplus objects from previous line
				local j = #(objects)
				while j > 0 do 
					line:InsertObject(objects[j],true);				
					j = j-1;	
				end
				
				-- update the line		
				objects = line:Update();	
				
				-- update the offset
				--print("line offset",i,offset,line:GetObject(1):GetText());
				line:SetOffset(offset);
				offset = offset + line:GetHeight();
				
				-- if there is still objects and no lines left insert a New
				if #(objects) > 0 and i == #(lines) then
					table.insert(lines,GHU_Line(self,width));
				end
			else
				offset = offset + line:GetHeight();
			end
			i = i+1;	
		end
		
		needUpdate = false;
	end
	
	-- ============== setup ==============
	parent = _parent;
	local f = parent;
	if (parent.GetGui) then 
		f = parent:GetGui();
	end
	
	gui = CreateFrame("Frame",nil,f);
	gui:ClearAllPoints();
	gui:SetPoint("TOPLEFT",f,"TOPLEFT",xOff,-yOff);
	gui:SetHeight(height);
	gui:SetWidth(width);
	gui:Hide();
	gui.model = class;
		
	enabled = true;
	
	--GHU_TestBG(class);
	
	return class;
end
