PageList = {}
PageList_mt = { __index = PageList }
setmetatable(PageList, Control_mt)

function PageList.Create(root, parentObject, graph)
	-- Create object
	local pageList = Control.Create(root, parentObject)
	setmetatable(pageList, PageList_mt)
	
	-- Set constants
	pageList.kBottomBarHeight = 30
	pageList.kButtonHeight = 21
	pageList.kLineHeight = 20
	
	pageList.currentRect = GRect()
	pageList.listRect = GRect()
	pageList.bottomBarRect = GRect()
	pageList.scrollbarRect = GRect()
	
	-- Create scroll stuff
	local listSubControl = Control.Create(root, parentObject)
	listSubControl.HandleEvent = 
		function(self, window, rect, event)
			-- Check if click in list
			if (self.isActive) then
				if (event.type==kGEventMouseUp) then
					self:SetActive(false)
				end
			else
				if (event.type==kGEventMouseDown and event.button==kGEventMouseButtonLeft and rect:IsPointInside(event.pos)) then
					self:SetActive(true)
					
					-- Account for scroll offset
					local yPos = rect.top + self.scrollOffset.y
					
					-- Loop through pages
					local lineRect = GRect(rect)
					lineRect:SetHeight(pageList.kLineHeight)
					
					for i=0,pageList.graph.numPages-1 do
						lineRect:MoveTo(rect.left, yPos)
						
						if (lineRect:IsPointInside(event.pos)) then
							pageList:SelectPage(i)
							
							if (event.clickCount==2) then
								pageList.textEdit = retain(intruder.GTextEdit(lineRect, pageList.graph:GetPage(i).name, 13, kGAlignLeft, kGVerticalAlignCenter))
							end
						end
						
						yPos = yPos + pageList.kLineHeight
					end
				end
			end
			
			-- Check for text edit finish
			if (event.type==kGEventTextEditFinished) then
				if (pageList.textEdit) then
					if (pageList.textEdit.state==intruder.GTextEdit_kTextEditDone) then
						local newName = pageList.textEdit.text
						local page = pageList.graph:GetPage(pageList.currentPage)
					
						-- Check if name changed
						if (page.name ~= newName) then
							-- Update name and surface
							page.name = retain(newName)
							page.nameSurface = retain(pageList:CreatePageNameSurface(newName))
						end	
					end
					
					pageList.textEdit = nil
				end
			end
			
		end
		
	listSubControl.Draw =
		function(self, window, rect)
			window:PushScissor(rect)
				-- set start y pos
				yPos = rect.top + self.scrollOffset.y
				
				for i=0,pageList.graph.numPages-1 do
					-- compute rect
					local rect = GRect(rect.left, yPos, rect.right, yPos + pageList.kLineHeight)	
					
					-- draw highlight if applicable
					if (i==pageList.currentPage) then
						window:DrawRect(rect, GColor(150, 150, 150))
					end
					
					-- draw name
					local page = pageList.graph:GetPage(i)
					page.nameSurface:DrawTexture(GPoint(rect.left + 5, yPos))
					
					-- increment yPos
					yPos = yPos + pageList.kLineHeight
				end
			window:PopScissor()
		end
		
	listSubControl.GetCanvasSize =
		function(self, rect)
			return GPoint(rect:GetWidth(), pageList.kLineHeight*pageList.graph.numPages)		
		end
		
	listSubControl.SetScrollOffset =
		function(self, offset)
			self.scrollOffset = offset	
			--print("Setting scrolloffset ", offset.x, " ", offset.y)
		end
		
	pageList.scrollView = ScrollView.Create(root, self, listSubControl)
	
	-- Set attributes
	pageList.graph = graph
	pageList.currentPage = nil
	pageList.newPageCount = 0
	pageList.textEdit = nil
	
	-- Create buttons
	pageList.buttons = {}
	
	pageList.buttons.add    = {["xPos"] = 5,   ["control"] = Button.Create(root, self, 20, pageList.kButtonHeight, "+", nil)}
	pageList.buttons.remove = {["xPos"] = 25,  ["control"] = Button.Create(root, self, 20, pageList.kButtonHeight, "-", nil)}
	pageList.buttons.up     = {["xPos"] = 45,  ["control"] = Button.Create(root, self, 30, pageList.kButtonHeight, "Up", nil)}
	pageList.buttons.down   = {["xPos"] = 75,  ["control"] = Button.Create(root, self, 45, pageList.kButtonHeight, "Down", nil)}
	pageList.buttons.save   = {["xPos"] = 120, ["control"] = Button.Create(root, self, 40, pageList.kButtonHeight, "Save", nil)}
	pageList.buttons.load   = {["xPos"] = 160, ["control"] = Button.Create(root, self, 40, pageList.kButtonHeight, "Load", nil)}
	
	pageList.buttons.add.control.onClick =
		function()
			local command = {}
			
			-- create new page object
			local newPage = intruder.ZPage(pageList.graph, 64, 64)
			
			pageList.newPageCount = pageList.newPageCount + 1
			local startName = "New Page "..pageList.newPageCount
			
			command.Execute =
				function()
					newPage.name = retain(startName)
					newPage.nameSurface = retain(pageList:CreatePageNameSurface(startName))
					
					-- make space in page list
					local startIndex = 0
					
					if (pageList.currentPage) then
						startIndex = pageList.currentPage + 1
					end
					
					local endIndex = pageList.graph.numPages
					 
					for i = endIndex,startIndex,-1 do
						pageList.graph:SetPage(i, pageList.graph:GetPage(i - 1))
					end
					
					-- insert page
					pageList.graph:SetPage(startIndex, newPage)
					pageList.graph.numPages = pageList.graph.numPages + 1
					pageList:SelectPage(startIndex)
					
					pageList.root:NotifyPageListChanged()
				end	
			
			command.UnExecute =
				function()
					-- move pages up	
					local startIndex = pageList.currentPage 
					local endIndex = pageList.graph.numPages - 2
					 
					for i = endIndex,startIndex,-1 do
						pageList.graph:SetPage(i, pageList.graph:GetPage(i + 1))
					end
					
					-- Update position and count
					pageList.graph.numPages = pageList.graph.numPages - 1
					pageList:SelectPage(pageList.currentPage - 1)
					
					pageList.root:NotifyPageListChanged()
				end	
			
			pageList.root.undoStack:Execute(command)
			root.functionMenuChanged = true
		end
		
		
	-- NOTE
	-- IF WE DELETE A PAGE, WE MUST CHECK IF ANY NODES ARE ROOT VIEW FOR DEMO OBJECT	
		
	
	pageList.buttons.up.control.onClick =
		function()
			if (pageList.currentPage > 0) then
				local command = {}
				
				command.Execute =
					function(self, isInitialCall)
						pageList:MoveCurrentPageUp()
						pageList.root:NotifyPageListChanged()
					end
					
				command.UnExecute =
					function(self, isInitialCall)
						pageList:MoveCurrentPageDown()
						pageList.root:NotifyPageListChanged()
					end
					
				pageList.root.undoStack:Execute(command)
			end
			root.functionMenuChanged = true
		end
		
	pageList.buttons.remove.control.onClick =
		function()
			if (pageList.currentPage ~= nil) then
				-- move pages up	
				local startIndex = pageList.currentPage 
				local endIndex = pageList.graph.numPages - 2
				 
				for i = startIndex,endIndex do
					pageList.graph:SetPage(i, pageList.graph:GetPage(i + 1))
				end
				
				-- Update position and count
				pageList.graph.numPages = pageList.graph.numPages - 1
				
				if (pageList.graph.numPages > 0) then
					if (pageList.currentPage > 0) then
						pageList:SelectPage(pageList.currentPage - 1)
					else
						pageList:SelectPage(0)
					end	
				else
					pageList:SelectPage(nil)
				end
						
				pageList.root:NotifyPageListChanged()
			end
			root.functionMenuChanged = true
		end
		
	pageList.buttons.down.control.onClick =
		function()
			if (pageList.currentPage < pageList.graph.numPages-1) then
				local command = {}
				
				command.Execute =
					function(self, isInitialCall)
						pageList:MoveCurrentPageDown()
						pageList.root:NotifyPageListChanged()
					end
					
				command.UnExecute =
					function(self, isInitialCall)
						pageList:MoveCurrentPageUp()
						pageList.root:NotifyPageListChanged()
					end
					
				pageList.root.undoStack:Execute(command)
			end
			root.functionMenuChanged = true
		end
		
	pageList.buttons.save.control.onClick =
		function()
			if (pageList.currentPage < pageList.graph.numPages) then
				SavePageToFile(pageList.currentPage)
			end
			root.functionMenuChanged = true
		end
		
	pageList.buttons.load.control.onClick =
		function()
			if (pageList.currentPage) then
				LoadPageFromFile(pageList.currentPage + 1)
			else
				LoadPageFromFile(0)
			end
			root.functionMenuChanged = true
		end
		
		
	-- pageList.graph.numPages = 0
	
	
	--[[-- For testing purposes
	local pageNames = {"Misc Textures", "Timing", "First Scene", "Second Scene", "Main"}
	
	for i,pageName in pairs(pageNames) do
		local page = intruder.ZPage(20, 20)
		page.name = pageName
		page.nameSurface = GSurface(200, 20)
		page.nameSurface:Clear(GColor(0, 0, 0, 0))
		page.nameSurface:DrawTextAligned(intruder.kFontFaceLucidaGrande, pageName, GColor(0, 0, 0), 13, kGAlignLeft, kGVerticalAlignCenter);
		page.nameSurface:UpdateTexture()
		
		graph:SetPage(i-1, page)
		
		retain(page)
	end
	
	pageList.graph.numPages = 5
	pageList:SelectPage(3)
	]]
	
	return pageList
end

function PageList:SelectPage(index)
	self.currentPage = index
	
	local page = nil
	
	if (index) then
		page = self.root.graph:GetPage(index)
	end
	
	if (page) then
		self.root.nodeGrid:PageWasSelected(page)
		self.root.scrolledNodeGrid:SetScrollPos(page.normalizedScrollPos)
	else
		self.root.nodeGrid:PageWasSelected(nil)
		self.root.scrolledNodeGrid:SetScrollPos(GPoint(0, 0))
	end
end


function PageList:HandleEvent(window, rect, event)
	window:PushScissor(rect)
		-- Check if we should update layout
		if (not self.currentRect:IsEqual(rect)) then
			self:UpdateLayoutRects(rect)
		end
		
		-- Handle scrolled subview
		self.scrollView:HandleEvent(window, self.listRect, event)

		-- Handle buttons
		for i,button in pairs(self.buttons) do
			local rect = GRect(button.xPos, rect.bottom - self.kBottomBarHeight + 5, button.xPos + button.control.width, rect.bottom - self.kBottomBarHeight + 5 + self.kButtonHeight)	
			button.control:HandleEvent(window, rect, event)
		end
	window:PopScissor()
end

function PageList:Draw(window, rect)
	window:PushScissor(rect)
		-- Clear background
		window:DrawRect(rect, GColor(80, 80, 80))
		
		-- Draw scrolled subview
		self.scrollView:Draw(window, self.listRect)
		
		-- Draw bottom bar
		local rect = GRect(rect.left, rect.bottom - self.kBottomBarHeight, rect.right, rect.bottom)
		window:DrawRect(rect, GColor(120, 120, 120))
		
		-- Draw buttons
		for i,button in pairs(self.buttons) do
			local rect = GRect(button.xPos, rect.bottom - self.kBottomBarHeight + 5, button.xPos + button.control.width, rect.bottom - self.kBottomBarHeight + 5 + self.kButtonHeight)	
			button.control:Draw(window, rect)
		end
	window:PopScissor()
end


-- THE FUNCTIONS BELOW ARE INTERNAL AND SHOULD NOT BE CALLED BY OTHER CLASSES -- THEY DO NOT SUPPORT UNDO/REDO

function PageList:UpdateLayoutRects(newRect)
	-- Set current rect
	self.currentRect:Copy(newRect)
	
	-- Compute bottom bar rect
	self.bottomBarRect:Copy(newRect)
	self.bottomBarRect.top = newRect.top - self.kBottomBarHeight
	
	-- Compute list view rect
	self.listRect:Copy(newRect)
	self.listRect.bottom = math.max(newRect.top, newRect.bottom - self.kBottomBarHeight)	
end

function PageList:MoveCurrentPageUp()
	assert(self.currentPage > 0, "PageList:MoveCurrentPageUp logic error")

	local currentPageRef = self.graph:GetPage(self.currentPage)
	local abovePageRef = self.graph:GetPage(self.currentPage - 1)
	
	self.graph:SetPage(self.currentPage, abovePageRef)
	self.graph:SetPage(self.currentPage - 1, currentPageRef)
	self.currentPage = self.currentPage - 1
	root.functionMenuChanged = true
end

function PageList:MoveCurrentPageDown()
	assert(self.currentPage < self.graph.numPages-1, "PageList:MoveCurrentPageDown logic error")

	local currentPageRef = self.graph:GetPage(self.currentPage)
	local belowPageRef = self.graph:GetPage(self.currentPage + 1)
	
	self.graph:SetPage(self.currentPage, belowPageRef)
	self.graph:SetPage(self.currentPage + 1, currentPageRef)
	self.currentPage = self.currentPage + 1
	root.functionMenuChanged = true
end

function PageList:CreatePageNameSurface(name)
	-- Compute coords
	local rect = GRect(0, 0, 200, self.kLineHeight)
	local textSize = 13

	-- Create surface
	local nameSurface = GSurface(200, self.kLineHeight)
	nameSurface:Clear(GColor(0, 0, 0, 0))
	nameSurface:DrawTextAligned(intruder.kFontFaceEnvyBold, name, GColor(0, 0, 0), textSize, kGAlignLeft, kGVerticalAlignCenter, GPoint(1,1));
	nameSurface:DrawTextAligned(intruder.kFontFaceEnvyBold, name, GColor(255, 255, 255), textSize, kGAlignLeft, kGVerticalAlignCenter, GPoint(0,0));
	nameSurface:UpdateTexture()
	
	return nameSurface
end
