dofile "scripts/demohighscores.lua"
dofile "world.lua"


--

dofile "scripts/res.lua"
dofile "scripts/entity.lua"
dofile "scripts/game.lua"

dofile "scripts/options.lua"


local w,h = window.width(), window.height()
window.refsize(w,h)
local mw,mh = 150,165
local mx = 80
menu = Container.getRootContainer():add(GroupFrame:new(mx,h*.5,mw,0))
menu:moveToRect(mx,(h-mh)*.5,mw,mh,.1,20)
menu.background = new(Game,system.projectpath().."/levels/level0.lua")
menu.background.gui:delete()
menu:getSkin():setSkinColor(0,0,0,.4)
local x,y,z = menu.background.cam:pos()
menu.background.cam:pos(x,y-2800,z)
menu.background.player.body:pos(x,y-3500,0)

function menu:showMenu(comp,title)
	
	local cw,ch = comp:getSize()
	if menu.lastcomp then 
		self:removeComponent(menu.lastcomp)
		menu.lastcomp = nil
	end
	
	menu:add(comp)
	comp:setBounds(5,35,cw,ch)
	local mw,mh = cw+10,ch+40
	menu:moveToRect(mx,(h-mh)*.5,mw,mh,.1,20)
	
	menu.lastcomp = comp
	menu.title:moveToRect(0,5,mw,30, .1,20)
	menu.title:setText(title or "Sparc")
	menu.line:moveToRect(5,30,mw-10,1, .1,20)
end

MouseCursor.showMouse(true)
for node in pairs(menu.background.list) do
	if node.activator then  node.activator:delete() end
	if node.geom then node.geom:delete() end
	if node.delete and node.body then node:delete() end
end

function menu.background.player:think() return 1 end

local function spawnplayertrails()
	for i,t in ipairs(menu.background.player.trails) do
		local x,y,z = menu.background.player.body:local2world(t.x,t.y,t.z)
		t:localtime(menu.background.simtime)
		t:spawn(x,y,z,0,0,1,0,-500,0)
	end
end

for i=1,40 do spawnplayertrails() end

function menu:think()
	local x,y,z = menu.background.cam:pos()
	menu.background.cam:pos(x,y+1,z)

	
	local plane = dgeomplane.new(0,0,1,0,pickspace)	
	local x,y = input.mousepos()
	local g,pos = UtilFunctions.picktest(plane,nil,nil,nil,menu.background.cam.camera)
	if g then
		local a,b,c = pos[1],pos[2],0
		local d,e,f = menu.background.player.body:pos()
		local dx,dy = a-d,b-e
		local d = math.sqrt(dx*dx+dy*dy)
		local f = math.min(.9,math.max(-.01,d*.01-1.5))
		local fx,fy = dx/d*f,dy/d*f
		local vx,vy,vz = menu.background.player.body:velocity()
		menu.background.player.body:addforce(fx,fy,0)
		menu.background.player.body:rotdeg(0,vx*12,0)
		menu.background.player.body:veldrag(.8,.8,.8)
		menu.background.player.age = menu.background.player.age + 1
		menu.background.player.energy = math.min(100,menu.background.player.energy + 5 + math.min(math.max(0,menu.background.player.energy*.2),10))
	
		--if dy>0 and dy<200 and math.abs(dx)<20 and math.sin(os.clock()*3)>.95 then
		--	menu.background.player:shoot("primary")
		--end
	end
--	menu.background.simtime = menu.background.simtime + 20
	menu.background:think(true)
	spawnplayertrails()
	
	
--	dworld.quickstep(1)
end

local function addlabel(x,y,w,h,tx,to,center,right)
	local text = (to or menu):add(Label:new(x,y,w,h,tx))
	if tx then text:setText(text:wrapLine(tx)) end
	text:setFontColor(0,1,0,1)
	if center then
		text:setAlignment(Label.LABEL_ALIGNCENTERED,Label.LABEL_ALIGNCENTERED)
		--text:getSkin():setFontColor(0,1,0,1)
	else
		text:setAlignment(nil,Label.LABEL_ALIGNTOP)
		--text:getSkin():setFontColor(0,1,0,1)
	end
	
	if right then text:setAlignment(Label.LABEL_ALIGNRIGHT) end
	return text
end
local function addrect (x,y,w,h,to)
	local line = (to or menu):add(ImageComponent:new(x,y,w,h,matsurface.vertexcolor()))
	line.l2d.image:color(0,1,0,1)
	line:color(0,1,0,1)
	return line
end
local function addlistbox(x,y,w,h,to)
	local lb = ListBox:new(x,y,w,h);
	(to or menu):add(lb)
	lb:getSkin():setSkinColor(0,1,0,.3)
	lb.scrollbar:getSkin():setSkinColor(0,1,0,.3)
	lb.scrollbar:getSkin():getIcon():setColor(0,1,0,1)
	function lb:renewList()
		ListBox.renewList (self)
		for i,btn in ipairs(self.viewarea.components) do			
			btn:getSkin():setSkinColor(0,1,0,.3)
			btn:getSkin():setFontColor(0,1,0,1)
		end
	end
	return lb
end

local function addbutton(x,y,w,h,to,tx,fun)
	local btn = (to or menu):add(Button:new(x,y,w,h,tx))
	btn.onClicked = fun
	btn:getSkin():setSkinColor(0,1,0,.3)
	btn:getSkin():setFontColor(0,1,0,1)
end

local function addedit(x,y,w,h,to,tx)
	local btn = (to or menu):add(TextField:new(x,y,w,h,tx))
	btn.dataTextField.selectioncolor = {0,0,.3,.5}
	btn.dataTextField.cursorcolor = {0,1,0,1}
	btn.dataTextField.textcolor = {0,1,0,1}
	btn:getSkin():setSkinColor(0,1,0,.3)
	btn:getSkin():setFontColor(0,1,0,1)
	btn:setText(tx)
	return btn
end

menu.title = addlabel(0,5,mw,30,"Sparc",nil,true)
menu.line = addrect(5,30,mw-10,1)

local mw = 80
local mainmenu = Container:new(0,0,mw,175)

local function showtextpage (lt,w,h,title,cen,backpage)
	local instructions = Container:new(0,0,w or 300,h or 200)
	local tx = addlabel(0,0,w or 300,(h or 200)-20,nil,instructions,cen)
	local stop
	addbutton((w or 300)-40,(h or 200)-20,40,20,instructions,"OK",function()
		stop = true menu:showMenu(backpage or mainmenu)end)
	local lt = tx:wrapLine(lt)
	local tpw = soundnode.new(snd.typewriter)
	tpw:autodelete(false)
	tpw:gain(1)
	tpw:pitch(4)
	TimerTask.new(
		function ()
			local i = 1
			while i<=#lt and not stop do
				local sleeplonger
				if lt:sub(i,i) == '\v' then
					i = i + 2
					if lt:sub(i-1,i-1) == 'x' then
						while lt:sub(i,i)~=';' do  i = i + 1 end
						i = i + 1
						sleeplonger = true
					end
				else
					if (lt:sub(i+1,i+1)~='\n') then
						tpw:play()
					end
				end
				local t = lt:sub(1,i)--..(lt:sub(i+1,i+1)~='\n' and "_" or "")
				local last = lt:sub(i+1,i+1)=='\n'
				tx:setText(last and t or t:gsub("(.....)(...)$",function (a,b)
					if b:match("\v") or a:match("\v") then return a..b else return a..b:gsub("(.)(.)(.)","\v494%1\v696%2\v999%3") end
					end))
				
				coroutine.yield(last and 200 or sleeplonger and 100 or 20)
				i = i + 1
			end
			tx:setText(lt)
		end,10)
	menu:showMenu(instructions,title)
	return tx
end

local function showinstructions ()
	showtextpage(
		"Key settings: \n"..
		"- ARROW KEYS: Steer the ship\n"..
		"- LEFT CONTROL: Shoot primary weapons (uses energy)\n"..
		"- LEFT SHIFT: Shoot secondary weapon (uses 1 scrap part)\n"..
		"- ENTER: Pause or stop playing\n"..
		"- ESC: Quit\n\n"..
		"- Green bar: Shield (regenerates)\n"..
		"- Red bar: Health (no regeneration)\n"..
		"- Yellow bar: Energy (regenerates)\n\n"..
		"Mission briefing:\n"..
		"- Shoot at incoming ships and collect as many wreck parts as possible",340,260,"Sparc - Instructions")
end

local function showoptions()
	local ow,oh = 200,100
	local con = Container:new(0,0,ow,oh)
	local y = 0
	addlabel(0,y,60,20,"PostFX",con,true,true)
	
	local function addbox(x,y,title,cmd,...)
		local items = {...}
		addlabel(x,y,95,20,title,con,true,true)
		
		local box = con:add(ComboBox:new(95+x,y,90,20))
		
		box.button:getSkin():setSkinColor(0,1,0,1)
		box.box:getSkin():setSkinColor(0,1,0,.3)
		box.box:getSkin():setFontColor(0,1,0,1)
		for i,v in ipairs(items) do
			box:addItem(v)
		end
		return box
	end
	
	local cbpostfx = PostProcessEffects and 
		addbox(0,0,"PostFX","postfx","None","Low","Medium", "High") or
		addbox(0,0,"PostFX","postfx","None")
	cbpostfx:select(PostProcessEffects and (postfx.detaillevel+1) or 1)
	local cbframerate = addbox(0,20,"Max. Framerate:","maxfps",
						"No limit","15","30","45","60","75","90","105","120")
	local fpsrate = ({[15] = 2, [30] = 3, [45] = 4, [60] = 5, [75] = 6, [90] = 7, [105] = 8, [120] = 9})[system.maxfps()] or 1
	cbframerate:select(fpsrate)
	
	local multisamp = addbox(0,40,"FS AntiAlias*:","multisamples","0","2","4","6","8","16")
	local function multisamples(n)
		if not n then
			local ms = window.multisamples()/2
			return (ms < 5 and ms+1 or 6)
		else
			window.multisamples( n < 6 and ((n-1)*2) or 16)
		end
	end
	multisamp:select(multisamples())
	addlabel(x,oh-40,ow,20,"* requires restart",con,true,true)
	
	--postfxinit(0-3)
	
	addbutton(ow-160,oh-20,80,20,con,"Cancel",
		function()
			menu:showMenu(mainmenu)
		end)
	addbutton(ow-80,oh-20,80,20,con,"OK",
		function()
			local fps = (cbframerate:getSelected()-1)*15
			system.maxfps(fps)
			multisamples(multisamp:getSelected())
			local id = cbpostfx:getSelected()
			gameoptions:set("postfx",id-1)
			menu:showMenu(mainmenu)
		end)
	menu:showMenu(con,"Sparc - Options")
end


local function showabout ()
	showtextpage(
"\vCEike Decker aka Zet\n\vCgameplay programming, artwork, sounds, testing\n\n"..
"\vCChristoph Kubisch aka CrazyButcher\n\vCgraphics effects programming, testing\n"..
"\n\n\vChttp://www.luxinia.de\n\n\n\vCHey thanks for reading!", 300,230, "Sparc - About version "..sparcversion,true)
end

local function showscores()
	local tx = {}
	for i,v in ipairs(highscores.scores) do 
		tx[#tx+1] = ("%.02d. %s\vx100;%s\vx200;%.05d\n"):format(i,v.date,v.name,v.points)
	end
	local tx = showtextpage(table.concat(tx),300,nil,"Sparc - Highscores")
	tx:setAlignment(Label.LABEL_ALIGNCENTERED,Label.LABEL_ALIGNTOP)
end

local function showeditcampaign(which)
	local ow,oh = 200,260
	local con = Container:new(0,0,ow*2,oh)
	local info 
	xpcall(
		function ()
			info = dofile(system.projectpath().."/campaigns/"..which.."/campaigninfo.lua")
		end,
		function (err)
			showtextpage ("Could not execute campaigninfo.lua file: \n"..err,400,100,"Campaign corrupt",true,mainmenu)
		end)
	if not info then return end
	addbutton((ow-160)*.5,oh-20,160,20,con,"Back to mainmenu",
		function()
			menu:showMenu(mainmenu)
		end)
	
	local cpath = system.projectpath().."/campaigns/"..which
		
	addlabel(0,0,ow,16,"Levels of the campaign",con,true)
	local levels = addlistbox((ow-160)*.5,16,160,100,con)
	local function updatelevels()
		levels:clearItems()
		local list = {}
		for name in FileSystem.dir(cpath) do
			if name:match("^level%-%d+%.lua$") and FileSystem.attributes(cpath.."/"..name,"mode")~=directory then
				list[#list+1] = name
			end
		end
		table.sort(list)
		for i,name in ipairs(list) do
			local tab = World.load(cpath.."/"..name,false)
			levels:addItem(("%.3d: %s"):format(i,tab.title or "Untitled"))
		end
	end
	updatelevels()
		
	local function createlevel()
		local n = levels:itemCount()
		World.createnew(("%s/level-%.3d.lua"):format(cpath,(n+1)))
		updatelevels()
	end
	
	local function editlevel ()
		
	end
		
	addbutton((ow-160)*.5,120,60,20,con,"Up",function () end)
	addbutton((ow-160)*.5+100,120,60,20,con,"Down",function () end)
	addbutton((ow-160)*.5,140,160,20,con,"Edit Level",editlevel)
	addbutton((ow-160)*.5,160,160,20,con,"Delete Level",function () end)
	addbutton((ow-160)*.5,180,160,20,con,"Create Level",createlevel)
	
	addrect(ow,0,1,oh,con)
	
	addlabel(ow,0,ow,16,"Campaign settings",con,true)
	addlabel(ow,24,60,16,"Title:",con,false,true)
	local title = addedit(ow+60,20,ow-60,24,con,info.title)
	addbutton(ow+(ow-160)*.5,oh-20,160,20,con,"Save campaign parameters",
		function()
			info.title = title:getText()
			local dir = system.projectpath().."/campaigns/"..which
			local fp,err = io.open(dir.."/campaigninfo.lua","w")
			
			if not fp then
				showtextpage ("An error occured when creating the information file: \n"..err,200,100,"Error",true,con)
				return 
			end
			fp:write(UtilFunctions.serialize(info))
			fp:close()
			showtextpage ("The campaign settings saved successfully.",200,100,"Success",true,con)
		end)
	
	
	
	menu:showMenu(con,"Sparc - Edit "..info.title)
end

local function showedit ()
	local ow,oh = 200,200
	local con = Container:new(0,0,ow,oh)
	
	local lb = addlistbox((ow-160)*.5,0,160,100,con)
	
	local function showcreatecampaign()
		local c = Container:new(0,0,ow,oh)
		addlabel(0,0,ow,20,"Directory name:",c)
		local dirname = addedit(0,15,ow,24,c,"")
		addlabel(0,40,ow,20,"Campaign title:",c)
		local title = addedit(0,55,ow,24,c,"")
		addbutton(0,oh-20,80,20,c,"Cancel",
		function()
			menu:showMenu(con)
		end)	
		
		addbutton(ow-80,oh-20,80,20,c,"ok",
		function()
			local dir = dirname:getText():lower()
			local tit = title:getText()
			if not dir:match("^[a-zA-Z0-9%-]+$") then
				showtextpage ("The directory name may only contain the letters:\nA-Z  a-z  0-9  - \nand must contain at least one letter.",200,100,"Input error",true,c)
				return 
			end
			dir = system.projectpath().."/campaigns/"..dir
			if FileSystem.attributes(dir) then
				showtextpage ("The directory name is already used.",200,100,"Input error",true,c)
				return 
			end
			local suc,err = FileSystem.mkdir(dir)
			if not suc then
				showtextpage ("An error occured when creating the directory: \n"..err,200,100,"Input error",true,c)
				return 
			end
			local info = {title = tit, created = os.time()}
			local fp,err = io.open(dir.."/campaigninfo.lua","w")
			if not fp then
				showtextpage ("An error occured when creating the information file: \n"..err,200,100,"Input error",true,c)
				return 
			end
			fp:write(UtilFunctions.serialize(info))
			fp:close()
			showtextpage ("The project was created successful",200,100,"Success",true,con)
			lb:addItem(dirname:getText().." ("..tit..")",dirname:getText())
		end)	
		menu:showMenu(c,"Sparc - Create Campaign")
		addlabel(0,80,ow,80,"The directory name is the location of the campaign and should not be long or contain special characters. The title can contain any characters of any length and can be changed anytime later.",c)
	end
	
	local dir = system.projectpath().."/campaigns"
	for name in FileSystem.dir(dir) do
		if not name:match("^%.") and FileSystem.attributes(dir.."/"..name,"mode")=="directory" 
			and loadfile(dir.."/"..name.."/campaigninfo.lua") then
			xpcall(function ()
				local info = dofile(dir.."/"..name.."/campaigninfo.lua")
				lb:addItem(name.." ("..info.title..")",name)
			end, function(err) print(err) end)
		end
	end
	
	addbutton((ow-160)*.5,100,160,20,con,"Edit Campaign",
		function () 
			local idx, name,cmd = lb:getSelected()
			showeditcampaign(cmd)
		end)
	addbutton((ow-160)*.5,120,160,20,con,"Create new Campaign",
		function () 
			showcreatecampaign()
		end)
	
	addbutton((ow-160)*.5,oh-20,160,20,con,"Back to mainmenu",
		function()
			menu:showMenu(mainmenu)
		end)
	menu:showMenu(con,"Sparc - Chose a campaign to edit")
end


addbutton(0,0,mw,25,mainmenu,"Free play",function () 
	menu.background = nil
	menu = nil
	startgame(function () 
	local function fn()
		startmenu() 
		TimerTask.new(function () collectgarbage"collect" end,1)
	end
	game:showMessage("You are dead - you need to survive to enter your name in the highscores",fn)
	end)  end )
addbutton(0,25,mw,25,mainmenu,"Highscores",showscores)
addbutton(0,50,mw,25,mainmenu,"Options",showoptions )
addbutton(0,75,mw,25,mainmenu,"Instructions",showinstructions )
addbutton(0,100,mw,25,mainmenu,"About",showabout)
addbutton(0,125,mw,25,mainmenu,"Editor",showedit)
addbutton(0,150,mw,25,mainmenu,"Quit",function () system.exit() end)
menu:showMenu(mainmenu)

