

--===================================================
--										Page
--===================================================	

function GHU_Page(_parent,pageLayout,font,_width,_height,_xOff,_yOff) 
	-- input check
	assert(pageLayout.IsClass and pageLayout:IsClass("GHU_PageLayout"),"Page must be defined with a page layout of the type GHU_PageLayout",pageLayout.GetType and pageLayout:GetType());
	assert(type(_xOff)=="number" and type(_yOff)=="number");
	
	-- definition	
	local class = Class("GHU_Page");
	
	local linkedAreas,floatingAreas = {},{};
	local focusArea;
	local parent = _parent;
	local gui;
	local xOff,yOff = _xOff,_yOff;
	local width,height = _width,_height;
	local layout = pageLayout;
	local materialTex
		
	-- local functions	
	local function GetAreaIndex(area) 
		for i,o in pairs(linkedAreas) do
			if o == area then 
				return i;
			end
		end
		return;	
	end
	
	-- ********* public functions **********
	class.BackwardsDelete = function(self)
		if focusArea then
			if focusArea:BackwardsDelete() then
				
			end
		end
	end
	class.DeleteSelected = function(self)
	
	end
	class.Disable = function(self)
	
	end
	class.Dispose = function(self)
	
	end
	class.Enable = function(self)
	
	end
	class.ForwardDelete = function(self)
	
	end
	class.GetFocus = function(self)
	
	end
	class.GetFocusCoordinate = function(self)
		if focusArea then
			local x,y,font = focusArea:GetFocusCoordinate();
			return x+xOff,y+yOff,font;		
		end
	end
	class.GetGui = function(self)
		return gui;
	end
	class.GetHeight = function(self)
	
	end
	class.GetArea = function(self,i)
		return linkedAreas[i];
	end
	class.GetAreaIndex = function(self,area)
	
	end
	class.GetNumAreas = function(self)
		return #(linkedAreas)+#(floatingAreas),#(linkedAreas),#(floatingAreas)
	end
	class.GetOffset = function(self) 
	
	end
	class.GetParent = function(self)
	
	end
	class.GetPos = function(self,x,y,onlyFocusable)
		x,y = x-xOff,y-yOff;
		-- determine the line at the given x,y coordinate.
		local closestDist;
		local closestIndex;
		local closestType;
		
		-- linked
		for i,area in pairs(linkedAreas) do
			-- calculate the distance from point to closest area side
			local axOff,ayOff = area:GetOffset();
			local dx = min(abs(x-axOff),abs(x-axOff+area:GetWidth()));
			local dy = min(abs(y-ayOff),abs(y-ayOff+area:GetHeight()));
			local d = min(dx,dy);
			if not(closestDist) or d < closestDist then
				closestIndex = i;
				closestType = "linked";
			end			
		end
		
		-- floating
		for i,area in pairs(floatingAreas) do
			-- calculate the distance from point to closest area side
			local axOff,ayOff = area:GetOffset();
			local dx = min(abs(x-axOff),abs(x-axOff+area:GetWidth()));
			local dy = min(abs(y-ayOff),abs(y-ayOff+area:GetHeight()));
			local d = min(dx,dy);
			if not(closestDist) or d < closestDist then
				closestIndex = i;
				closestType = "floating";
			end			
		end
		
		-- return the pos in the closest area;
		if closestIndex then
			if closestType == "linked" then 
				return closestIndex,linkedAreas[closestIndex]:GetPos(x,y,onlyFocusable);
			elseif closestType == "floating" then
				return -closestIndex,floatingAreas[closestIndex]:GetPos(x,y,onlyFocusable);
			end
		end
		return;
	end
	class.GetSelection = function(self)
	
	end
	class.GetWidth = function(self)
	
	end
	class.Hide = function(self)
	
	end
	class.InsertArea = function(self,area,floating)
		-- check the input
		assert(area.IsClass and area:IsClass("GHU_Area"),"Inserted area must be of type GHU_Area");
				
		if floating then
			table.insert(floatingAreas,area);
		else
			table.insert(linkedAreas,area);
		end
		needUpdate = true
	end
	class.InsertText = function(self,str)
		if focusArea then
			focusArea:InsertText(str);
		end
		needUpdate = true;
	end
	class.MoveLeft = function(self)
		if focusArea then
			if (focusArea:MoveLeft()) then
				local i = GetAreaIndex(focusArea);
				if i > 1 then
					focusArea = linkedAreas[i-1];
					focusArea:MoveEnd();
				else
					return true; -- no more areas on the page				
				end			
			end
		end
	end
	class.MoveHome = function(self)
		if focusArea then
			focusArea:MoveHome();
		else
			focusArea = linkedAreas[1];
			if focusArea then
				focusArea:MoveHome();
			end
		end
	end
	class.MoveRight = function(self)
		if focusArea then
			if (focusArea:MoveRight()) then
				local i = GetAreaIndex(focusArea);
				if i < #(linkedAreas) then
					focusArea = linkedAreas[i+1];
					focusArea:MoveHome();
				else
					return true; -- no more areas on the page				
				end
			end
		end
	end
	class.MoveUp = function(self)
		if focusArea:MoveUp() then
			-- move up failed, insert in buttom line of next area
			local i = GetAreaIndex(focusArea);
			local x,y = focusArea:GetFocusCoordinate();
			local xOff,yOff = focusArea:GetOffset();
								
			if i > 1 then
				-- look at previous line
				focusArea = floatingAreas[i-1];
				local xOff2,yOff2 = focusArea:GetOffset();
				focusArea:SetFocus(focusArea:GetPos(x-xOff+xOff2,y+yOff+yOff,true));			
			else
				-- this is first line
				return true;			
			end
		end
	end
	class.MoveDown = function(self)
		if focusArea:MoveDown() then
			-- move up failed, insert in buttom line of next area
			local i = GetAreaIndex(focusArea);
			local x,y = focusArea:GetFocusCoordinate();
			local xOff,yOff = focusArea:GetOffset();
								
			if i < #(floatingAreas) then
				-- look at previous line
				focusArea = floatingAreas[i+1];
				local xOff2,yOff2 = focusArea:GetOffset();
				focusArea:SetFocus(focusArea:GetPos(x-xOff+xOff2,focusArea:GetHeight()-yOff+yOff,true));			
			else
				-- this is first line
				return true;			
			end
		end
	end
	class.MoveHome = function(self)
		if focusArea then
			focusArea:MoveHome();	
		else
			focusArea = linkedAreas[1];
			focusArea:MoveHome();
		end
	end
	class.MoveEnd = function(self)
		if focusArea then
			focusArea:MoveEnd();	
		else
			focusArea = linkedAreas[#(linkedAreas)];
			focusArea:MoveEnd();
		end
	end
	class.NeedsUpdate = function(self)
		return needUpdate;	
	end
	class.SetFocus = function(self,areaI,...)
		if areaI == nil then -- remove focus in case of areaI being nil
			if focusArea then
				focusArea:SetFocus(nil);
			end
			focusArea = nil;
			return		
		end
	
		assert(linkedAreas[areaI],"Focus line index out of bounds");
		
		local newFocusArea = linkedAreas[areaI];
		
		-- remove focus from old 
		if focusArea and not(newFocusArea == focusArea) then -- same Line
			focusArea:SetFocus(nil);			
		end
		
		-- set focus in new
		local x,y,font = newFocusArea:SetFocus(...);
		focusArea=newFocusArea;
		
		return x+xOff,y+yOff,font;
	end
	class.SetHeight = function(self)
	
	end
	class.SetOffset = function(self,_xOff,_yOff)
	
	end
	class.SetSelection = function(self)
	
	end
	class.SetWidth = function(self)
	
	end
	class.Show = function(self)
		gui:Show();
		for _,area in pairs(linkedAreas) do
			area:Show();		
		end
		for _,area in pairs(floatingAreas) do
			area:Show();		
		end
	end
	class.Update = function(self)
		
		for _,area in pairs(linkedAreas) do
			if area:NeedsUpdate() then
				area:Update();		
			end
		end
		for _,area in pairs(floatingAreas) do
			if area:NeedsUpdate() then
				area:Update();		
			end
		end
		
		-- update height and width
	end	
	
	
	
	
	-- ============== setup ==============
	-- gui
	gui = CreateFrame("Frame",nil,parent:GetGui());
	gui:ClearAllPoints();
	gui:SetPoint("TOPLEFT",parent:GetGui(),"TOPLEFT",xOff,-yOff);
	gui:SetWidth(width);
	gui:SetHeight(height);
	gui:Hide();
		
	layout:ApplyAreas(class,font);
	
	materialTex = GHU_DocTexture(class:GetGui(),width,height,0,0,10);
	materialTex:SetTextures(GHU_GetCollection("material","Parchment 2"));

	
	
	
	return class;
end

