FrameLayout = {}
FrameLayout_mt = { __index = FrameLayout }
setmetatable(FrameLayout, Control_mt)

function FrameLayout.Create(root, parentObject)
	local object = Control.Create(root, parentObject)
	setmetatable(object, FrameLayout_mt)
	
	-- Constants
	object.kLineThickness = 5
	object.kTopMargin = 30
	object.kBottomMargin = 30
	
	-- Create split table
	object.splits = {}
	
		object.splits.vSplit = {} -- aux/main row
			object.splits.vSplit.normalizedPos = 0.3
			object.splits.vSplit.rect = GRect()
			object.splits.vSplit.isDragging = false
			object.splits.vSplit.cursor = intruder.GWindow_kGCursorArrowNS
			object.splits.vSplit.ComputeNormalizedPos =
				function(self, pos)
					local newY = pos.y - self.relativeStartDragPos.y
					local newNormalizedPosition = (newY - self.kTopMargin) / (self.height - self.kTopMargin - self.kBottomMargin - self.kLineThickness)
					
					return clamp(newNormalizedPosition, 0, 1)
				end
													
		object.splits.hSplitTop1 = {}
			object.splits.hSplitTop1.normalizedPos = 0.2
			object.splits.hSplitTop1.rect = GRect()
			object.splits.hSplitTop1.isDragging = false
			object.splits.hSplitTop1.cursor = intruder.GWindow_kGCursorArrowWE
			object.splits.hSplitTop1.ComputeNormalizedPos =
				function(self, pos)
					local newX = pos.x - self.relativeStartDragPos.x
					local newNormalizedPosition = newX / (self.width - self.kLineThickness)
					
					local maxPosition = self.splits.hSplitTop2.normalizedPos - self.kLineThickness/self.width
					
					return clamp(newNormalizedPosition, 0, maxPosition)
				end
														
		object.splits.hSplitTop2 = {}
			object.splits.hSplitTop2.normalizedPos = 0.4
			object.splits.hSplitTop2.rect = GRect()
			object.splits.hSplitTop2.isDragging = false
			object.splits.hSplitTop2.cursor = intruder.GWindow_kGCursorArrowWE
			object.splits.hSplitTop2.ComputeNormalizedPos =
				function(self, pos)
					local newX = pos.x - self.relativeStartDragPos.x
					local newNormalizedPosition = newX / (self.width - self.kLineThickness)
					
					local minPosition = self.splits.hSplitTop1.normalizedPos + self.kLineThickness/self.width
					
					return clamp(newNormalizedPosition, minPosition, 1)
				end

		object.splits.hSplitBottom = {}
			object.splits.hSplitBottom.normalizedPos = 0.25
			object.splits.hSplitBottom.rect = GRect()
			object.splits.hSplitBottom.isDragging = false
			object.splits.hSplitBottom.cursor = intruder.GWindow_kGCursorArrowWE
			object.splits.hSplitBottom.ComputeNormalizedPos =
				function(self, pos)
					local newX = pos.x - self.relativeStartDragPos.x
					local newNormalizedPosition = (newX) / (self.width - self.kLineThickness)
					
					return clamp(newNormalizedPosition, 0, 1)
				end

														
	-- Content rects
	object.pageListViewRect = GRect()
	object.nodeGridViewRect = GRect()
	object.mainDemoViewRect = GRect()
	object.auxDemoViewRect = GRect()
	object.parameterListViewRect = GRect()

	-- Other state
	object.topRect = GRect()
	object.bottomRect = GRect()

	object.relativeStartDragPos = nil
	
	object.width = nil
	object.height = nil
	
	return object
end

function FrameLayout:HandleEvent(window, rect, event)
	if (event.type == intruder.kGEventResize) then
		-- Compute new rects from normalized positions
		self.width = event.width
		self.height = event.height
		
		self:UpdateRects()
	elseif (event.type == intruder.kGEventMouseMoved) then
		local isDragging = false
		
		-- Update split normalized position, if dragging
		for i,split in pairs(self.splits) do
			if (split.isDragging) then
				isDragging = true
				
				local newNormalizedPos = split.ComputeNormalizedPos(self, event.pos)
				
				-- Update normalized position
				if (newNormalizedPos ~= split.normalizedPos) then
					split.normalizedPos = newNormalizedPos
				
					self:UpdateRects()
				end
				
				-- Set cursor
				window:SetCursor(split.cursor)
			end
		end
		
		-- Check if we should set cursor
		if (isDragging == false) then
			for i,split in pairs(self.splits) do
				if (split.rect:IsPointInside(event.pos)) then
					if (not self:IsOtherControlActive()) then
						window:SetCursor(split.cursor)
					end
				end
			end
		end
	elseif (event.type == intruder.kGEventMouseDown) then
		if (event.button==kGEventMouseButtonLeft) then
			-- Check if we should start dragging
			for i,split in pairs(self.splits) do
				if (split.rect:IsPointInside(event.pos)) then
					-- Start dragging
					split.isDragging = true
					self:SetActive(true)
					self.relativeStartDragPos = GPoint(event.pos):Minus(split.rect:GetTopLeft())
				end
			end
		end
	elseif (event.type == intruder.kGEventMouseUp) then
		-- Check if we should stop dragging
		for i,split in pairs(self.splits) do
			if (split.isDragging) then
				-- Stop dragging
				self:SetActive(false)
				split.isDragging = false
			end
		end
	end
	
	-- Set scissoring
	window:ResetScissor(self.width, self.height)
end
						
function FrameLayout:Draw(window, rect)
	-- Set scissoring
	window:ResetScissor(self.width, self.height)
	local color = intruder.GColor(120, 120, 120)
	
	-- Draw top and bottom
	window:DrawRect(self.topRect, color)
	window:DrawRect(self.bottomRect, color)
	
	-- Draw splitters
	for i,split in pairs(self.splits) do
		window:DrawRect(split.rect, color)
	end
end

function FrameLayout:SaveToString()
	local data = {}

	data.splits_vSplit_normalizedPos = self.splits.vSplit.normalizedPos	
	data.splits_hSplitBottom_normalizedPos = self.splits.hSplitBottom.normalizedPos
	data.splits_hSplitTop1_normalizedPos = self.splits.hSplitTop1.normalizedPos
	data.splits_hSplitTop2_normalizedPos = self.splits.hSplitTop2.normalizedPos
	
	return SerializeTableToString(data)
end

function FrameLayout:LoadFromString(dataIn)	
	dataIn = 'return ' .. dataIn
	--print ('ps:\n' .. dataIn)
	local data = loadstring(dataIn)()
	
	--print ('np:\n' .. data.splits_vSplit_normalizedPos)

	self.splits.vSplit.normalizedPos = data.splits_vSplit_normalizedPos
	self.splits.hSplitBottom.normalizedPos = data.splits_hSplitBottom_normalizedPos
	self.splits.hSplitTop1.normalizedPos = data.splits_hSplitTop1_normalizedPos
	self.splits.hSplitTop2.normalizedPos = data.splits_hSplitTop2_normalizedPos
	self:UpdateRects()
end

function FrameLayout:UpdateRects()
	local newY, newX
	-- Update topRect
	self.topRect.left = 0
	self.topRect.right = self.width
	self.topRect.top = 0
	self.topRect.bottom = self.kTopMargin
	
	-- Update vSplit rect
	self.splits.vSplit.rect.left = 0 
	self.splits.vSplit.rect.right = self.width
	
	newY = math.max(math.floor(self.kTopMargin + self.splits.vSplit.normalizedPos * (self.height - self.kTopMargin - self.kBottomMargin - self.kLineThickness)), self.kTopMargin)
	self.splits.vSplit.rect.top = newY
	self.splits.vSplit.rect.bottom = newY + self.kLineThickness
	
	-- Update bottom rect
	self.bottomRect.left = 0
	self.bottomRect.right = self.width
	
	newY = math.max(self.height - self.kBottomMargin, self.splits.vSplit.rect.bottom)
	self.bottomRect.top = newY
	self.bottomRect.bottom = newY + self.kBottomMargin
	
	-- Update hSplitBottomRect
	self.splits.hSplitBottom.rect.left = math.floor(self.splits.hSplitBottom.normalizedPos * (self.width - self.kLineThickness))
	self.splits.hSplitBottom.rect.right = self.splits.hSplitBottom.rect.left + self.kLineThickness
	self.splits.hSplitBottom.rect.top = self.splits.vSplit.rect.bottom
	self.splits.hSplitBottom.rect.bottom = self.bottomRect.top
	
	-- Update hSplitTop1
	self.splits.hSplitTop1.rect.left = math.floor(self.splits.hSplitTop1.normalizedPos * (self.width - self.kLineThickness))
	self.splits.hSplitTop1.rect.right = self.splits.hSplitTop1.rect.left + self.kLineThickness
	self.splits.hSplitTop1.rect.top = self.topRect.bottom
	self.splits.hSplitTop1.rect.bottom = self.splits.vSplit.rect.top
	
	-- Update hSplitTop2
	self.splits.hSplitTop2.rect.left = math.max(math.floor(self.splits.hSplitTop2.normalizedPos * (self.width - self.kLineThickness)), self.splits.hSplitTop1.rect.right)
	self.splits.hSplitTop2.rect.right = self.splits.hSplitTop2.rect.left + self.kLineThickness
	self.splits.hSplitTop2.rect.top = self.topRect.bottom
	self.splits.hSplitTop2.rect.bottom = self.splits.vSplit.rect.top
	
	-- PageList View Rect
	self.pageListViewRect.left = 0
	self.pageListViewRect.top = self.splits.vSplit.rect.bottom
	self.pageListViewRect.right = self.splits.hSplitBottom.rect.left
	self.pageListViewRect.bottom = self.bottomRect.top
	
	-- NodeGrid View Rect
	self.nodeGridViewRect.left = self.splits.hSplitBottom.rect.right
	self.nodeGridViewRect.top = self.splits.vSplit.rect.bottom
	self.nodeGridViewRect.right = self.width
	self.nodeGridViewRect.bottom = self.bottomRect.top
	
	-- ParameterList View Rect
	self.parameterListViewRect.left = self.splits.hSplitTop2.rect.right
	self.parameterListViewRect.top = self.topRect.bottom
	self.parameterListViewRect.right = self.width
	self.parameterListViewRect.bottom = self.splits.vSplit.rect.top
	
	-- Main Demo View Rect
	self.mainDemoViewRect.left = 0
	self.mainDemoViewRect.top = self.topRect.bottom
	self.mainDemoViewRect.right = self.splits.hSplitTop1.rect.left
	self.mainDemoViewRect.bottom = self.splits.vSplit.rect.top
	
	-- Aux Demo View Rect
	self.auxDemoViewRect.left = self.splits.hSplitTop1.rect.right
	self.auxDemoViewRect.top = self.topRect.bottom
	self.auxDemoViewRect.right = self.splits.hSplitTop2.rect.left
	self.auxDemoViewRect.bottom = self.splits.vSplit.rect.top
	
	-- Update demo viewports
	local rect
	rect = self.mainDemoViewRect
	g_pDemo.mainViewport:Set(rect.left, self.height - rect.top, rect.right, self.height - rect.bottom)
	rect = self.auxDemoViewRect
	g_pDemo.auxViewport:Set(rect.left, self.height - rect.top, rect.right, self.height - rect.bottom)

	g_pDemo:SaveLayout()
end

function FrameLayout:GetPageListViewRect()
	return self.pageListViewRect
end

function FrameLayout:GetNodeGridViewRect()
	return self.nodeGridViewRect
end

function FrameLayout:GetMainDemoViewRect()
	return self.mainDemoViewRect
end

function FrameLayout:GetAuxDemoViewRect()
	return self.auxDemoViewRect
end

function FrameLayout:GetParameterListViewRect()
	return self.parameterListViewRect
end

