dofile "Scripts/english.lua"


dofile "Scripts/game.lua"
dofile "Scripts/gui.lua"
dofile "Scripts/menu.lua"

dofile "Scripts/levels.lua"


focused = true
suspended = false
allowclose = true

display.on_close = function ( self )
	if allowclose == false then
		ShowCloseDialog ( )
	else
		return true
	end
end

display.on_destroy = function ( self )
	pcall ( SaveProgress )
	pcall ( SaveRecords )
	pcall ( SaveProfiles )
	pcall ( SaveSettings )
end

display.on_create = function ( self )

end


display.on_losefocus = function ( self )
	focused = false
end

display.on_gainfocus = function ( self )
	focused = true
end

display.on_suspend = function ( self )
	suspended = true
end

display.on_unsuspend = function ( self )
	suspended = false
end





function SaveProgress ( )
	local file = io.open ( "Save/slot" .. current_profile .. ".lua", "w+" )

	if showtips == false then
		file:write ( "showtips = false\n" )
	else
		file:write ( "showtips = true\n" )
	end
	if colorblind == true then
		file:write ( "colorblind = true\n" )
	else
		file:write ( "colorblind = false\n" )
	end
	file:write ( "difficulty = " .. difficulty .. "\n" )

	file:write ( "\n" )

	file:write ( "total_time = " .. total_time .. "\n" )
	file:write ( "total_cleared = " .. total_cleared .. "\n" )
	file:write ( "total_chains = " .. total_chains .. "\n" )
	file:write ( "total_longest_chain = " .. total_longest_chain .. "\n" )

	file:write ( "\n" )

	if completed == false then
		file:write ( "completed = false\n" )
	else
		file:write ( "completed = true\n" )
	end

	file:write ( "\n" )


	for i, v in pairs ( levels ) do
		if levels[i].locked == false then
			file:write ( "levels[" .. i .. "].locked = false\n" )
		else
			file:write ( "levels[" .. i .. "].locked = true\n" )
		end
	end
	file:close ( )
end


function OutString ( sz )
	return string.gsub ( sz, '"', "\\\"")
end

function LoadProgress ( )
	dofile ( "Save/slot" .. current_profile .. ".lua" )
end

function SaveRecords ( )
	local file = io.open ( "Save/records.lua", "w+" )

	for i, v in pairs ( records ) do
		local r = records[i]
		file:write ( "records[" .. i .. "].longest_chain = { " .. r.longest_chain[1] .. ", " .. r.longest_chain[2] .. ", " .. r.longest_chain[3] .. " }\n" )
		file:write ( "records[" .. i .. "].longest_chain_leader = " )
		file:write ( "{ " )
		file:write ( '"' .. OutString ( r.longest_chain_leader[1] ) .. '"' )
		file:write ( ', ' )
		file:write ( '"' .. OutString ( r.longest_chain_leader[2] ) .. '"' )
		file:write ( ', ' )
		file:write ( '"' .. OutString ( r.longest_chain_leader[3] ) .. '"' )
		file:write ( " }\n" )

		file:write ( "records[" .. i .. "].cleared = { " .. r.cleared[1] .. ", " .. r.cleared[2] .. ", " .. r.cleared[3] .. " }\n" )
		file:write ( "records[" .. i .. "].cleared_leader = " )
		file:write ( "{ " )
		file:write ( '"' .. OutString ( r.cleared_leader[1] ) .. '"' )
		file:write ( ', ' )
		file:write ( '"' .. OutString ( r.cleared_leader[2] ) .. '"' )
		file:write ( ', ' )
		file:write ( '"' .. OutString ( r.cleared_leader[3] ) .. '"' )
		file:write ( " }\n" )


		file:write ( "records[" .. i .. "].longest_time = { " .. r.longest_time[1] .. ", " .. r.longest_time[2] .. ", " .. r.longest_time[3] .. " }\n" )
		file:write ( "records[" .. i .. "].longest_time_leader = " )
		file:write ( "{ " )
		file:write ( '"' .. OutString ( r.longest_time_leader[1] ) .. '"' )
		file:write ( ', ' )
		file:write ( '"' .. OutString ( r.longest_time_leader[2] ) .. '"' )
		file:write ( ', ' )
		file:write ( '"' .. OutString ( r.longest_time_leader[3] ) .. '"' )
		file:write ( " }\n" )

		file:write ( "records[" .. i .. "].fastest = { " .. r.fastest[1] .. ", " .. r.fastest[2] .. ", " .. r.fastest[3] .. " }\n" )
		file:write ( "records[" .. i .. "].fastest_leader = " )
		file:write ( "{ " )
		file:write ( '"' .. OutString ( r.fastest_leader[1] ) .. '"' )
		file:write ( ', ' )
		file:write ( '"' .. OutString ( r.fastest_leader[2] ) .. '"' )
		file:write ( ', ' )
		file:write ( '"' .. OutString ( r.fastest_leader[3] ) .. '"' )
		file:write ( " }\n" )

		file:write ( "records[" .. i .. "].optimal = { " .. r.optimal[1] .. ", " .. r.optimal[2] .. ", " .. r.optimal[3] .. " }\n" )
		file:write ( "records[" .. i .. "].optimal_leader = " )
		file:write ( "{ " )
		file:write ( '"' .. OutString ( r.optimal_leader[1] ) .. '"' )
		file:write ( ', ' )
		file:write ( '"' .. OutString ( r.optimal_leader[2] ) .. '"' )
		file:write ( ', ' )
		file:write ( '"' .. OutString ( r.optimal_leader[3] ) .. '"' )
		file:write ( " }\n" )
		file:write ( "\n" )
	end
	file:close ( )
end

function LoadRecords ( )
	dofile ( "Save/records.lua" )
end


function SaveProfiles ( )
	local file = io.open ( "Save/profiles.lua", "w+" )

	file:write ( "current_profile = " .. current_profile .. "\n\n" )
	for i, v in pairs ( profiles ) do
		file:write ( "profiles[" .. i .. "] = " .. '"' .. OutString ( profiles[i] ) .. '"\n' )
	end
	file:close ( )
end

function LoadProfiles ( )
	dofile ( "Save/profiles.lua" )
end


function SaveSettings ( )
	local file = io.open ( "Save/settings.lua", "w+" )

	file:write ( "resx = " .. resx .. "\n" )
	file:write ( "resy = " .. resy .. "\n" )
	if windowed == false then
		file:write ( "windowed = false\n" )
	else
		file:write ( "windowed = true\n" )
	end
	file:write ( 'sound_volume = ' .. sound_volume .. '\n' )
	file:write ( 'music_volume = ' .. music_volume .. '\n' )

	file:close ( )
end

function LoadSettings ( )
	dofile ( "Save/settings.lua" )
end




function InitInput ( )
	if mouse == nil then
		return false
	end
	return true
end

function InitAudio ( )
	if audio == nil	or audio:set_mode ( 16, 1, 44100 ) == false then
		audio = nil
		return false
	end

	music = Music ( )



	diag = Sound ( )
	if diag:load ( "Sounds/dialog.wav" ) == false then
		ShowDialog ( text.file_not_found, "Sounds/dialog.wav" )
	end
	diag.volume = sound_volume

	swoosh = Sound ( )
	if swoosh:load ( "Sounds/swoosh.wav" ) == false then
		ShowDialog ( text.file_not_found, "Sounds/swoosh.wav" )
	end
	swoosh.volume = sound_volume

	tip = Sound ( )
	if tip:load ( "Sounds/tip.wav" ) == false then
		ShowDialog ( text.file_not_found, "Sounds/tip.wav" )
	end
	tip.volume = sound_volume

	gameover = Sound ( )
	if gameover:load ( "Sounds/gameover.wav" ) == false then
		ShowDialog ( text.file_not_found, "Sounds/gameover.wav" )
	end
	gameover.volume = sound_volume

	advance = Sound ( )
	if advance:load ( "Sounds/advance.wav" ) == false then
		ShowDialog ( text.file_not_found, "Sounds/advance.wav" )
	end
	advance.volume = sound_volume

	record = Sound ( )
	if record:load ( "Sounds/record.wav" ) == false then
		ShowDialog ( text.file_not_found, "Sounds/record.wav" )
	end
	record.volume = sound_volume

	return true
end

function InitVideo ( )
	if display:create ( "Chains", resx, resy, 32, windowed ) == false then
		return false
	end

	silkscreen11 = Font ( )
	if silkscreen11:load_file ( "Fonts/silkscreen.ttf", 11 ) == false then
		silkscreen11:load_system ( "Arial", 11 )
	end

	silkscreen14 = Font ( )
	if silkscreen14:load_file ( "Fonts/silkscreen.ttf", 14 ) == false then
		silkscreen14:load_system ( "Arial", 14 )
	end

	silkscreen17 = Font ( )
	if silkscreen17:load_file ( "Fonts/silkscreen.ttf", 17 ) == false then
		silkscreen17:load_system ( "Arial", 17 )
	end

	silkscreen20 = Font ( )
	if silkscreen20:load_file ( "Fonts/silkscreen.ttf", 20 ) == false then
		silkscreen20:load_system ( "Arial", 20 )
	end

	silkscreen23 = Font ( )
	if silkscreen23:load_file ( "Fonts/silkscreen.ttf", 23 ) == false then
		silkscreen23:load_system ( "Arial", 23 )
	end

	camera = Camera ( )

	scene = Layer ( )
	scene:add_child ( camera )
	display.camera = camera

	overlay = Sprite ( )
	scene:add_child ( overlay )
	overlay.depth = -100

--	viewport = Viewport ( 0, 0, resx, resy )
--	viewport.camera = camera
--	viewport.camera:set_scale ( 1, 1 )
--	display:add_child ( viewport )

	hud = Sprite ( )
	hud.depth = -1000
	display:add_child ( hud )

	level_curtain = Sprite ( )
	level_curtain.depth = -1999
	level_curtain.alpha = 1
	level_curtain.canvas:rectangle ( resx, resy )
	level_curtain.canvas:set_fill_style ( BLACK, 1 )
	level_curtain.canvas:fill ( )
	display:add_child ( level_curtain )






	selector = Image ( )
	if selector:load ( "Images/selector.png" ) == false then
		ShowDialog ( text.file_not_found, "Images/selector.png" )
	end

	title_image = Image ( )
	if title_image:load ( "Images/title.png" ) == false then
		ShowDialog ( text.file_not_found, "Images/title.png" )
	end
	glow = Image ( )
	if glow:load ( "Images/glow.png" ) == false then
		ShowDialog ( text.file_not_found, "Images/glow.png" )
	end
	ball = Image ( )
	if ball:load ( "Images/ball.png" ) == false then
		ShowDialog ( text.file_not_found, "Images/ball.png" )
	end

	return true
end








state = 'menu'
demo = false

--
-- Assets
--
title_image = nil
glow = nil
ball = nil
camera = nil
scene = nil
overlay = nil
viewport = nil
silkscreen11 = nil
silkscreen14 = nil
silkscreen17 = nil
hud = nil
level_curtain = nil

--
-- Settings
--
resx = 800
resy = 600
windowed = true
music_volume = 1
sound_volume = 0.8

pcall ( LoadSettings )


-- derivative globals

resx_hw = resx / 2
resy_hh = resy / 2
camera_scaler = 600 / resy






math.randomseed ( os.time ( ) )
effects = EffectsManager:Create ( )


if InitVideo ( ) == false then
	return
end
if InitInput ( ) == false then
	ShowDialog ( text.input_error, text.no_mouse )
end
if InitAudio ( ) == false then
	ShowDialog ( text.audio_error, text.no_sound )
end





--
-- Profiles
--
difficulty = 2
showtips = true
completed = false
colorblind = false

total_time = 0
total_cleared = 0
total_chains = 0
total_longest_chain = 0

current_profile = 0
profile_count = 0
profiles = {}

-- check the number of profiles
if pcall ( LoadProfiles ) == true then
	for i, v in pairs ( profiles ) do
		if v ~= nil then
			profile_count = profile_count + 1
		end
	end
end

-- current profile is invalid, load the first available one
if profiles[current_profile] == nil then
	for i, v in pairs ( profiles ) do
		if v ~= nil then
			current_profile = i
			break
		end
	end
end

-- no profile, create one
if profile_count == 0 then
	profiles[1] = text.newplayer .. "1"
	current_profile = 1
	profile_count = 1
	pcall ( SaveProfiles )
	if pcall ( SaveProgress ) == false then
		ShowDialog ( text.fail_save, text.no_save )
	end
end


pcall ( LoadProgress )


--
-- Records
--
records = {}
for i, v in pairs ( levels ) do
	records[i] = {}
	records[i].longest_chain = { 0, 0, 0 }
	records[i].longest_chain_leader = { "", "", "" }
	records[i].cleared = { 0, 0, 0 }
	records[i].cleared_leader = { "", "", "" }
	records[i].longest_time = { 0, 0, 0 }
	records[i].longest_time_leader = { "", "", "" }
	records[i].fastest = { 0, 0, 0 }
	records[i].fastest_leader = { "", "", "" }
	records[i].optimal = { 0, 0, 0 }
	records[i].optimal_leader = { "", "", "" }
end
pcall ( LoadRecords )







InitGUI ( )
EnterMainMenu ( )



game = Game:Create ( )
game.OnClear = function ( game, count )
	cleared = cleared + count
	total_cleared = total_cleared + count

	-- stats
	chains = chains + 1
	total_chains = total_chains + 1
	if count > longest_chain then
		longest_chain = count
		if longest_chain > total_longest_chain then
			total_longest_chain = longest_chain
		end
	end


	if audio ~= nil and sound_volume > 0 then
		for i = 1, count do
			local effect = Play:Create ( "Sounds/clear" .. math.random ( 1, 5 ) .. ".wav", sound_volume )
			effects:AddEffect ( effect, 0, 50 * i + 100 )
		end
	end

	if current_level ~= 0 then
		local x = -resx_hw + 20
		local y = resy_hh - 50
		local lc = records[current_level].longest_chain[difficulty]
		if lc < longest_chain then
			if longest_chain > 3 then
				if record ~= nil and sound_volume > 0 then
					record:play ( )
				end

				local w = silkscreen17:get_width ( count )
				local h = silkscreen17:get_size ( )

				local t = Sprite ( )
				t.depth = -1000
				t.canvas:move_to ( x + w / 2, y + h / 2 - 2 )
				t.canvas:circle ( 15 )
				t.canvas:set_fill_style ( WHITE, 0.5 )
				t.canvas:fill ( )
				t.canvas:set_source_image ( glow, x + w / 2, y + h / 2 )
				t.canvas:paint ( )

				t.canvas:move_to ( x, y )
				t.canvas:set_font ( silkscreen17, WHITE )
				t.canvas:write ( count )
				t.canvas:move_to ( x + w + 10, y )
				t.canvas:set_font ( silkscreen17, WHITE )
				t.canvas:write ( text.new_level_record )
				t.canvas:move_to ( x + w + 10, y + 20 )
				t.canvas:set_font ( silkscreen11, BLACK )
				t.canvas:write ( text.longest_chain )

				display:add_child ( t )
				local effect = Fade:Create ( t, 0 )
				effects:AddEffect ( effect, 2000, 1000 )
				local effect = Remove:Create ( t, display )
				effects:AddEffect ( effect, 0, 3000 )

				y = y - 50
			end
			records[current_level].longest_chain[difficulty] = count
			records[current_level].longest_chain_leader[difficulty] = profiles[current_profile]
		end
		local c = records[current_level].cleared[difficulty]
		if c < cleared then
			if cleared_record == false and c ~= nil and c > 0 then
				if record ~= nil and sound_volume > 0 then
					record:play ( )
				end

				local w = silkscreen17:get_width ( cleared )
				local h = silkscreen17:get_size ( )

				local t = Sprite ( )
				t.depth = -1000
				t.canvas:move_to ( x + w / 2, y + h / 2 - 2 )
				t.canvas:circle ( 15 )
				t.canvas:set_fill_style ( WHITE, 0.5 )
				t.canvas:fill ( )
				t.canvas:set_source_image ( glow, x + w / 2, y + h / 2 )
				t.canvas:paint ( )

				t.canvas:move_to ( x, y )
				t.canvas:set_font ( silkscreen17, WHITE )
				t.canvas:write ( cleared )
				t.canvas:move_to ( x + w + 10, y )
				t.canvas:set_font ( silkscreen17, WHITE )
				t.canvas:write ( text.new_level_record )
				t.canvas:move_to ( x + w + 10, y + 20 )
				t.canvas:set_font ( silkscreen11, BLACK )
				t.canvas:write ( text.most_cleared )

				display:add_child ( t )
				local effect = Fade:Create ( t, 0 )
				effects:AddEffect ( effect, 2000, 1000 )
				local effect = Remove:Create ( t, display )
				effects:AddEffect ( effect, 0, 3000 )

				y = y - 50
			end
			cleared_record = true
			records[current_level].cleared[difficulty] = cleared
			records[current_level].cleared_leader[difficulty] = profiles[current_profile]
		end
	end


end

game.OnDie = function ( game, ball )
	lost = lost + 1
	if audio ~= nil and sound_volume > 0 then
		local effect = Play:Create ( "Sounds/die" .. math.random ( 1, 5 ) .. ".wav", sound_volume )
		effects:AddEffect ( effect, 0, 200 )
	end
end

game.OnLose = function ( )
	if state == 'gameover' then
		return
	end

	if gameover ~= nil and sound_volume > 0 then
		gameover:play ( )
	end

	state = 'gameover'
	Destroy ( level_gui )
	ShowGameoverMenu ( )
end

game.OnWin = function ( game )

	local l = records[current_level].fastest[difficulty]
	if l > time or l == 0 then
		records[current_level].fastest[difficulty] = time
		records[current_level].fastest_leader[difficulty] = profiles[current_profile]
	end
	
	local l = records[current_level].optimal[difficulty]
	if l > chains or l == 0 then
		records[current_level].optimal[difficulty] = chains
		records[current_level].optimal_leader[difficulty] = profiles[current_profile]
	end
	if advance ~= nil and sound_volume > 0 then
		advance:play ( )
	end

	if demo == true and current_level == 5 then
		state = 'paused'
		ShowDemoOverMenu ( )
		return
	end

	if current_level < #levels then
		local n = levels[current_level + 1]
		if n.locked == nil or n.locked == true then
			state = 'paused'
			n.locked = false
			ShowUnlockMenu ( )
		else
			state = 'paused'
			ShowWinMenu ( )
		end
	else
		-- the end
		state = 'paused'
		if completed == true then
			ShowTheEndMenu ( )
		else
			completed = true
			ExitLevel ( )
			EnterTheEndLevel ( )
		end
	end
end

timer = Timer ( )
timer:start ( 16, true )
timer.on_tick = function ( timer )
	local ms = timer:get_delta_ms ( )

	if focused == false or suspended == true then
		game:Paint ( )
		return
	end

	effects:Update ( ms )

	if state == 'playing' or state == 'gameover' then
		local ms = timer:get_delta_ms ( )
		-- stats
		time = time + ms
		total_time = total_time + ms

		local mins = math.floor ( time / 1000 / 60 )
		local secs = math.floor ( time / 1000 ) - ( mins * 60 )
		if secs < 10 then
			time_sz = ( mins .. ":0" .. secs  )
		else
			time_sz = ( mins .. ":" .. secs  )
		end

		hud.canvas:clear ( )


		game:Attach ( mouse.xaxis, mouse.yaxis )
		game:Update ( ms )
		game:Paint ( )


		if current_level ~= 0 and state == 'playing' then
			local x = -resx_hw + 20
			local y = resy_hh - 50
			local l = records[current_level].longest_time[difficulty]
			if l < time then
				if longest_time_record == false and l > 0 then
					if record ~= nil and sound_volume > 0 then
						record:play ( )
					end

					local w = silkscreen17:get_width ( time_sz )
					local h = silkscreen17:get_size ( )

					local t = Sprite ( )
					t.depth = -1000
					t.canvas:move_to ( x + w / 2, y + h / 2 - 2 )
					t.canvas:circle ( 15 )
					t.canvas:set_fill_style ( WHITE, 0.5 )
					t.canvas:fill ( )
					t.canvas:set_source_image ( glow, x + w / 2, y + h / 2 )
					t.canvas:paint ( )

					t.canvas:move_to ( x, y )
					t.canvas:set_font ( silkscreen17, WHITE )
					t.canvas:write ( time_sz )
					t.canvas:move_to ( x + w + 10, y )
					t.canvas:set_font ( silkscreen17, WHITE )
					t.canvas:write ( text.new_level_record )
					t.canvas:move_to ( x + w + 10, y + 20 )
					t.canvas:set_font ( silkscreen11, BLACK )
					t.canvas:write ( text.longest_playing_time )

					display:add_child ( t )
					local effect = Fade:Create ( t, 0 )
					effects:AddEffect ( effect, 2000, 1000 )
					local effect = Remove:Create ( t, display )
					effects:AddEffect ( effect, 0, 3000 )

					y = y - 50
				end
				longest_time_record = true
				records[current_level].longest_time[difficulty] = time
				records[current_level].longest_time_leader[difficulty] = profiles[current_profile]
			end
		end

	elseif state == 'paused' then
		
	elseif state == 'menu' then
		UpdateMenu ( ms )
	end
end


