
---- Encapsulating and running the game ----
-------------------------------------------------------------------------------

Game = {
	score = 0, prevScore = 0,
	quit = false, finished = false,
	levelnum = 0, crystnum = 0,
	speciallevel = false, bosslevel = false,
	countdown = 1.0
}

function Game:start()
	Alis.nbombs = Difficulty.startnbombs
	self.score, self.prevScore = 0, 0
	self.quit, self.finished = false, false
	self.levelnum, self.crystnum = 0, 0
	self:run()
end

function Game:initLevel()
	self.levelnum = self.levelnum + 1
	if self.levelnum == Difficulty.clocklevel then
		System.setClock(300)
		Window:showText("Not Bad", "Impressed by your formidable prowess,\nthe Crysts had to request more power!\n\n(PSP clock speed increased)")
	end
	
	if math.mod(self.levelnum, 3) == 0 then
		Levels:randomize()
		self.speciallevel = true
	else self.speciallevel = false end
	if math.mod(self.levelnum, 5) == 0 then
		Levels:randomize()
		self.bosslevel = true
	else self.bosslevel = false end
	if math.mod(self.levelnum, 3) ~= 0 and math.mod(self.levelnum, 5) then
		Level = Levels.standard
		self.crystnum = self.crystnum+1
	end
	
	Crysts:reset()
	Circle:reset()
	Fibers:stop()
	Alis:reset()
	for i=1, (Difficulty.startcrysts+self.crystnum)*Level.crystNumFactor do 
		Cryst:new() 
	end
	if self.bosslevel then 
		Cryst:newBoss()
		MusicPlayer:playBoss()
	else
		MusicPlayer:playGame()
	end
	
	self.countdown = 1.0
	self.prevScore = self.score
	-- try to prevent garbage collection during gameplay
	collectgarbage()
end

function Game:addScore(s)
	local old = self.score
	self.score = self.score + s
	if math.floor(self.score/5000) > math.floor(old/5000) then
		Crystal:print("NBomb awarded!", SCREEN_WIDTH2, SCREEN_HEIGHT2, Font.CENTER, colors.yellowish)
		Alis:addNBomb()
	end
end

function Game:drawBackground()
	screen:setTint(colors.bgtint)
	screen:textureRect(8, 0, SCREEN_WIDTH-16, 8, imgs.border.hor)
	screen:textureRect(8, SCREEN_HEIGHT-10, SCREEN_WIDTH-16, 8, imgs.border.hor)
	screen:textureRect(0, 8, 8, SCREEN_HEIGHT-18, imgs.border.vert)
	screen:textureRect(SCREEN_WIDTH-8, 8, 8, SCREEN_HEIGHT-18, imgs.border.vert)
	screen.blitRotated(0, 0, imgs.border.corner, 0)
	screen.blitRotated(SCREEN_WIDTH-8, 0, imgs.border.corner, 90)
	screen.blitRotated(0, SCREEN_HEIGHT-10, imgs.border.corner, 270)
	screen.blitRotated(SCREEN_WIDTH-8, SCREEN_HEIGHT-10, imgs.border.corner,  180)
	screen:setTint()
	
	screen:fillRect(1, 9, 6, SCREEN_HEIGHT-20, colors.black150)
	screen:textureRect(2, 10, 4, (SCREEN_HEIGHT-22)*Alis.stoppower, imgs.stopbarbg)
	screen:fillRect(SCREEN_WIDTH-7, 9, 6, SCREEN_HEIGHT-20, colors.black150)
	screen:textureRect(SCREEN_WIDTH-6, 10, 4, (SCREEN_HEIGHT-22)*Alis.turbopower, imgs.turbobarbg)
	
	screen:fillRect(9, SCREEN_HEIGHT-9, SCREEN_WIDTH-18, 6, colors.black150)
	screen:setTint(Color.new((1.0-self.countdown)*240, self.countdown*220, 80))
	screen:textureRect(10, SCREEN_HEIGHT-8, (SCREEN_WIDTH-20)*self.countdown, 4, imgs.timebarbg)
	screen:setTint()
	
	for i=0, Alis.nbombs-1 do
		screen:blit(i*12 + S_BORDER, 0, imgs.nbombicon)
	end
end

function Game:drawStats()
	tim = Timing:getTime()
	perfcolor = tim < 12 and colors.lightgreen or ( tim < 25 and colors.lightyellow or colors.lightred)
	screen:blit(SCREEN_WIDTH - 139, 11, imgs.scp)
	Vera:print(string.format("%d", self.score), SCREEN_WIDTH - 20, 12, Font.RIGHT)
	Vera:print(string.format("%d", table.getn(Crysts.list)), SCREEN_WIDTH - 20, 24, Font.RIGHT)
  	Vera:print(string.format("%.2f", Timing:getTime()), SCREEN_WIDTH - 20, 36, Font.RIGHT, perfcolor)
end

function Game:draw()
	screen:fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, colors.clear)
	
	self:drawBackground()
	
	Circle:draw()
	Fibers:draw()
	Crysts:draw()
	Alis:draw()
	Effects:draw()
	
	self:drawStats()	
end

function Game:fadeIn()
	for i=255, 0, -8 do
		self:draw()
		screen:flash(Color.new(0, 0, 0, i))
		screen.flip()
	end
end

function Game:run()
	local ctrl = Controls.read()
	local perfcolor, tim = colors.white, 0
	while not (self.quit or globalquit) do
		self:initLevel()
		self:fadeIn()
		Window:show(120, self:generateWindowBgFunc(), self:generateStartWindowFgFunc())
		self.finished = false
		while not (self.quit or self.finished or globalquit) do		
			Alis:control(ctrl)
			Alis:move()
			
			Crysts:move()
			
			self:draw()
			
			Timing:tick()
			screen.flip()
			Timing:start()
			
			self.countdown = self.countdown - Difficulty.countdec
			if self.countdown <= 0 then self:over() end
			
			ctrl = Controls.read()
		
			--if ctrl:l() and Crysts.list[1] then table.remove(Crysts.list); System.sleep(200) end
			--if ctrl:r() then Cryst:new(); System.sleep(200) end
			--if ctrl:triangle() then Circle:showQuads() end
			--if ctrl:square() then
			--	Circle.points = { {S_BORDER, S_BORDER}, 
			--		{SCREEN_WIDTH-S_BORDER, S_BORDER}, 
			--		{SCREEN_WIDTH-S_BORDER, SCREEN_HEIGHT-S_BORDER-2}, 
			--		{S_BORDER, SCREEN_HEIGHT-S_BORDER-2} }
			--end
		end
		MusicPlayer:stopTurboSpeed()
		if self.finished then
			Window:show(120, self:generateWindowBgFunc(), self:generateEndWindowFgFunc())
			self:addScore(self.countdown*1000 + Circle.area/100 + (self.score-self.prevScore)*(self.levelnum/15))
		end
		for i = 0,60 do
			screen:fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, colors.clear)
			screen.flip()
		end
		collectgarbage()
	end
	if not globalquit then
		self.score = math.floor(self.score)
		Window:show(160, nil, self:generateGameOverWindowFgFunc(), 
			self:generateGameOverWindowCtrlFunc())
		Highscores:add(self.score, self.levelnum)
	end
end

function Game:finishedLevel()
	self.finished = true
end

function Game:over()
	self.quit = true
end


function Game:generateWindowBgFunc()
	return function() 
		self:draw() 
		Window:drawDarkRect()
	end
end

function Game:generateStartWindowFgFunc()
	local i = 0
	return function() 
		i = i+1
		Crystal:print("Starting Level "..self.levelnum, SCREEN_WIDTH2, 84, Font.CENTER, Color.new(255,255,255,i*8))
		Vera:print("Music: " .. MusicPlayer:description(), SCREEN_WIDTH2-130, 112, Font.LEFT, Color.new(255,255,255,i*8))
		Vera:print("Game difficulty: " .. Difficulty.name, SCREEN_WIDTH2-130, 124, Font.LEFT, Color.new(255,255,255,i*8))
		
		if self.speciallevel then
			Vera:print("SPECIAL MODE: " .. Level.name, SCREEN_WIDTH2-130, 142, Font.LEFT, Color.new(255,255,80,i*8))
		end
		if self.bosslevel then
			Vera:print("BOSS LEVEL", SCREEN_WIDTH2-130, 154, Font.LEFT, Color.new(255,70,70,i*8))
		end
		
		Vera:print("Start with Cross or Circle.", SCREEN_WIDTH2, 180, Font.CENTER, colors.lightgray, Color.new(200,200,200,i*8))
	end
end

function Game:generateEndWindowFgFunc()
	local i = 0
	local x, sy = SCREEN_WIDTH2-100, 110
	local c, form = nil, string.format
	local cscore, bonus = self.score-self.prevScore, (self.score-self.prevScore)*(self.levelnum/15)
	return function() 
		i = i+1
		c = Color.new(255,255,255,i*8)
		Crystal:print("Level "..self.levelnum.." completed!", SCREEN_WIDTH2, 84, Font.CENTER, c)
		Vera:print(form("Previous Score: %9d", self.prevScore), x, sy, Font.LEFT, c)
		Vera:print(form("This Level:     %9d", cscore), x, sy+1*12, Font.LEFT, c)
		Vera:print(form("Time Bonus:     %9d", self.countdown*1000), x, sy+2*12, Font.LEFT, c)
		Vera:print(form("Area Bonus:     %9d", Circle.area/100), x, sy+3*12, Font.LEFT, c)
		Vera:print(form("Progress Bonus: %9d", bonus), x, sy+4*12, Font.LEFT, c)
		
		Vera:print("Continue with Cross or Circle.", SCREEN_WIDTH2, 180, Font.CENTER, Color.new(200,200,200,i*8))
	end
end

function Game:generateGameOverWindowFgFunc()
	local i = 0
	local x, sy = SCREEN_WIDTH2-100, 95
	local c, form = nil, string.format
	return function() 
		i = i+1
		c = Color.new(255,255,255,i*8)
		Crystal:print("Game Over", SCREEN_WIDTH2, 64, Font.CENTER, c)
		Vera:print(form("Game difficulty: %7s", Difficulty.name), x, sy, Font.LEFT, c)
		Vera:print(form("Overall Score: %9d", self.score), x, sy+14, Font.LEFT, c)
		Vera:print(form("Reached level: %9d", self.levelnum), x, sy+28, Font.LEFT, c)
		
		if Highscores:isHighscore(self.score) then
			Vera:print("NEW HIGHSCORE!", x, sy+48, Font.LEFT, Color.new(255,70,70,i*8))
			Vera:print("Placed "..placify(Highscores:getPlace(self.score)), x, sy+60, Font.LEFT, c)
			Vera:print("Your name: "..playername, x, sy+72, Font.LEFT, c)
			Vera:print("    (Triangle to change)", x, sy+84, Font.LEFT, c)
		end
		
		Vera:print("Continue with Cross or Circle.", SCREEN_WIDTH2, 200, Font.CENTER, Color.new(200,200,200,i*8))
	end
end

function Game:generateGameOverWindowCtrlFunc()
	return function()
		local ctrl = Controls.read()
		if ctrl:triangle() then
			playername = TextEntry:getString(playername)
		elseif ctrl:cross() or ctrl:circle() then
			Window:close()
		end
	end
end
