-- copy all globals into locals, some locals are prefixed with a G to reduce name clashes
local coroutine,package,string,table,math,io,os,debug,assert,dofile,error,_G,getfenv,getmetatable,ipairs,Gload,loadfile,loadstring,next,pairs,pcall,print,rawequal,rawget,rawset,select,setfenv,setmetatable,tonumber,tostring,type,unpack,_VERSION,xpcall,module,require=coroutine,package,string,table,math,io,os,debug,assert,dofile,error,_G,getfenv,getmetatable,ipairs,load,loadfile,loadstring,next,pairs,pcall,print,rawequal,rawget,rawset,select,setfenv,setmetatable,tonumber,tostring,type,unpack,_VERSION,xpcall,module,require

local apps=apps
local win=win


local function print(...) _G.print(...) end

local wstr=require("wetgenes.string")


module("bulb.levels")

function bake(state,levels)
	local levels=levels or {}
	
	local cake=state.cake
	local game=cake.game
	local fbs=cake.framebuffers
	local gl=state.gl
	
	local can	=state.rebake("bulb.can")
	local ball	=state.rebake("bulb.ball")


	function levels.loads()

	end
	
	function levels.setup()

	end

	function levels.update()
		
	end

	function levels.draw()

	end

	function levels.stage()
		levels.stage1()
	end
	
	function levels.stage1()
		levels.bags={}
		levels.maps={}
		
		local colors={
			{1,2,3,4,5},
			{2,3,4,5,17},
			{3,4,5,6,17},
			{4,5,6,7,17,18},
			{5,6,7,8,9,18},
			{6,7,8,9,10,17,19},
			{7,8,9,10,11,17,17},
			{8,9,10,11,12,17,18,19},
			{9,10,11,12,13,17,17,17},
			{10,11,12,13,14,17},
		}
		local shapes={
			{"full",6,6},
			{"right",1,8},
			{"left",1,8},
			{"center",1,8},
			{"left",1,8},
			{"right",1,8},
			{"full",6,7},
			{"center",1,8},
			{"center",1,9},
			{"center",1,10},
		}
		
		for idx=1,10 do
			local bag={}
			local map={}
			local fill={}
			levels.bags[idx]=bag
			levels.maps[idx]=map
			
			for i,v in ipairs( colors[idx] ) do fill[i]=v end
			
			local s=shapes[idx][1]
			local xh=shapes[idx][2]
			local yh=shapes[idx][3]
			local i=1
			for y=1,yh do
				local h= ( (y%2) == 1 ) and 0 or 0.5
				for x=1,6 do
				
					if     s=="full" then

						map[i]=-1

					elseif s=="left" then

						if (x+h) < xh+((yh-y)*0.5) then
							map[i]=-1
						else
							map[i]=0
						end

					elseif s=="right" then

						if (x+h) > 6 - (xh+((yh-y)*0.5)) then
							map[i]=-1
						else
							map[i]=0
						end

					elseif s=="center" then

						if ( (x+h) > 3.5 - (xh+((yh-y)*0.5)) ) and ( (x+h) < 3.5 + (xh+((yh-y)*0.5)) ) then
							map[i]=-1
						else
							map[i]=0
						end

					end


					i=i+1
				end
			end

			local f={}
			local function getfill()
				if not f[1] then
					for i,v in ipairs(fill) do
						f[i]=v
					end
				end
				if not f[1] then return end
				return table.remove(f,math.random(1,#f))
			end
			
			for i,v in ipairs(map) do
				if v<0 then
					map[i]=getfill()
				end
			end

			local t={}
			for i,v in pairs(map) do t[v]=true end
			for v in pairs(t) do bag[#bag+1]=v bag[#bag+1]=v end

		end
		
	end

	function levels.loaddata()
		local t=require("bulb.levelsdata")
		levels.maps=t.maps or {}
		levels.bags=t.bags or {}
	end
	
	function levels.savedata() -- hacks
		local fp=io.open("lua/bulb/levelsdata.lua","w")
		fp:write( "return "..wstr.serialize({maps=levels.maps,bags=levels.bags}) )
		fp:close()
	end

	function levels.setmapbag(id,map,bag)
		levels.bags[id]=bag
		levels.maps[id]=map
		levels.savedata()
	end
	
	function levels.rawbag(id)
		return levels.bags[id] or {}
	end

	function levels.getbag(id)
		local b=levels.bags[id] or {} -- levels.dgetbag(id)
		
		local m=levels.getmap(id) -- need to know whats in the level so we can add missing colors
		local t={}
		for i,v in pairs(m) do
			local color=can.color(v)
			if color and color>0 then t[color]=true end -- need this color in the bag
		end
		if ball.id then -- may get carried into the next level, so check it
			local color=can.color(ball.id)
			if color and color>0 then t[color]=true end -- need this color in the bag
		end
		for i,v in pairs(b) do
			local color=can.color(v)
			if color and color>0 then t[color]=nil end -- got this color in the bag so remove need
		end
		local bb={}
		for i,v in pairs(b) do
			if v>0 then bb[#bb+1]=v end -- skip and empty cells and fill up bb with bag ids 
		end
		for v in pairs(t) do 
			bb[#bb+1]=v -- add in the extra colors
		end
		
		-- finally randomize bb into the return list
		local r={}
		
		while bb[1] do
			r[#r+1]=table.remove(bb,math.random(1,#bb))
		end
		
		return r
	end

	function levels.rawmap(id)
		return levels.maps[id] or {}
	end

	function levels.getmap(id)
		local m=levels.maps[id] or {} -- levels.dgetmap(id)
		
		for i=1,6*14 do
			m[i]=m[i] or 0 -- fill with 0s
		end
		for i=6*14,1,-1 do
			if m[i]==0 then m[i]=nil else break end --remove trailing 0s
		end
		
		if not m[1] then -- blank map, random it all up
			m={}
			for i=1,6*6 do
				m[#m+1]=math.random(1,15)
			end
		end

		return m
	end
	
	function levels.dgetbag(idx)

		local ldata=require("bulb.levelsdata")
		local l=ldata.levels[idx]

	end
	
	function levels.dgetmap(idx)
	
		local m={}

		local ldata=require("bulb.levelsdata")
		local l=ldata.levels[idx]

		if l then
			for i=1,6*14 do
				m[i]=l.map[i]
			end
		end

		for i=1,6*14 do
			local id=m[i] or 0
			
			if id<=5 then
				if     id==1 then id=5
				elseif id==2 then id=3
				elseif id==3 then id=4
				elseif id==4 then id=13
				elseif id==5 then id=7
				else id=0
				end
			else
				if     id==6  then id=19
				elseif id==7  then id=17
				elseif id==8  then id=18
				elseif id==14 then id=20
				else id=0
				end
			end

			m[i]=id
		end

		return m
	end
	
	
	levels.loaddata()
--	levels.stage("green")


	levels.fbo_wrap=function(fbo,f)

		if not fbo then fbo=fbs.create() end

		gl.MatrixMode(gl.PROJECTION)
		gl.PushMatrix()
		gl.MatrixMode(gl.MODELVIEW)
		gl.PushMatrix()
		
		local fs=64
		local ds=64

		fbo:resize(fs,fs,0)
		fbs.bind_frame(fbo)
		local old_layout=cake.layouts.create{parent={w=fs,h=fs,x=0,y=0}}.apply(ds,ds,1/4,ds*8)
		
		gl.ClearColor(gl.C4(0x0000))
		gl.Clear(gl.COLOR_BUFFER_BIT+gl.DEPTH_BUFFER_BIT)

		-- draw stuff
		if f then f() end
		
		fbs.bind_frame(nil) -- remove fbs binding, should pop a stack?
		
		gl.MatrixMode(gl.PROJECTION)
		gl.PopMatrix()
		gl.MatrixMode(gl.MODELVIEW)
		gl.PopMatrix()
		
		old_layout.restore()
		
		return fbo
	end

	levels.fbo_draw=function(id)

		gl.Color(1,1,1,1)
		
		local bulbs=cake.sheets.get("bulbs")
		
		local unit=6
		local bpx=0+8
		local bpy=64-8

		local px=0
		local py=0
		local idx=1
		
		local map=levels.getmap(id)
		
		for y=1,14 do -- bottom to top
		
			for x=1,6 do
			
				px = ( (x-1) + ( (y%2)==1 and 0 or 0.5 ) ) * unit
				py = (y-1) * 3/4 * -unit

				local id=map[idx]
--				id=2
				if id and id>0 and id<=64 then 

					bulbs:draw(id,bpx + px, bpy + py ,0 , unit *5/4 * 1.25 )

				end
				
				idx=idx+1
			end
		end	

	end

	return levels

end
