function save_game(ext)
	if not ext then ext = "" else ext = "."..ext end
	if not profile_manager():GetCurrentProfile() then error("There is no current profile!") end
	profile_manager():GetCurrentProfile():PrepareSave()
	g_App:Save("saves\\"..profile_manager():GetCurrentProfile():GetSaveFileNum()..ext)
end

function load_game(ext)
	if not ext then ext = "" else ext = "."..ext end
	if not profile_manager():GetCurrentProfile() then error("There is no current profile!") end
	g_App:Load("saves\\"..profile_manager():GetCurrentProfile():GetSaveFileNum()..ext)
end

function save_player(ext)
	if not ext then ext = "" else ext = "."..ext end
	if not profile_manager():GetCurrentProfile() then error("There is no current profile!") end
	profile_manager():GetCurrentProfile():PrepareSave()
	g_Player:Save("saves\\"..profile_manager():GetCurrentProfile():GetSaveFileNum()..ext)
end

function load_player(ext)
	if not ext then ext = "" else ext = "."..ext end
	if not profile_manager():GetCurrentProfile() then error("There is no current profile!") end
	g_Player:Load("saves\\"..profile_manager():GetCurrentProfile():GetSaveFileNum()..ext)
end

-------------------------------------------------------------------------------------------------

function pause_game(pause)
	if not g_Game then return end

	local last = g_GameVars.paused

	if pause then g_GameVars.paused = g_GameVars.paused + 1
	else g_GameVars.paused = g_GameVars.paused - 1 end

	g_Game:Disable(g_GameVars.paused>0)

	if (last>0 and g_GameVars.paused<=0) or (last<=0 and g_GameVars.paused>0) then
		if g_GameVars.paused>0 then 
			play_sound("sound_game_pause") 
			local cursor_pointer = 0
			SetCursor(cursor_pointer, true)
			ApplyCursor()
		else 
			if g_Cursor:GetShape().__ok then
				g_Cursor:UpdateCoords()
				g_Cursor:GetShape():OnPickupShape()
			end
			play_sound("sound_game_unpause") 
		end
	end
end

-------------------------------------------------------------------------------------------------

function gamestate_on_key(window, key, state)
	if not g_App:IsCheatsEnabled() then return end

	if key==76 and state==2 then
		-- Alt+L
		local window = CLuaWindow(g_Loader:GetTemplate("level_travel_window"), g_Lua)
		g_WidgetAgent:AddWidget(window)

	elseif key==83 and state==2 then
		-- Alt+S
		--g_App:Save("saves/save")
		save_game()

	elseif key==68 and state==2 then
		-- Alt+D
		--g_App:Load("saves/save") 
		load_game()
	end
end

-------------------------------------------------------------------------------------------------

function init_and_start_game(state, player)
	init_game(state, player)
	init_level(g_Player:GetLevel())
end

-------------------------------------------------------------------------------------------------

function init_game(state, player)
	log("init game")

	default_state_init(state)

	g_State = state
	g_Player = player

	local game = ConvertToCLuaWindow(state:GetWidget("game"))

	g_Game = game


	-- вытаскиваем основные игровые элементы
	g_Cursor = ConvertToCCursor(game:GetWidget("cursor"))
	g_Pipeline = ConvertToCPipeline(game:GetWidget("pipeline"))
	g_StripeArea = ConvertToCStripeArea(game:GetWidget("stripe_area"))
	g_Discard = ConvertToCDiscard(game:GetWidget("discard"))
	g_AmuletPlace = ConvertToCAmuletPlace(game:GetWidget("amulet_place"))
	g_GodPlace = ConvertToCGodPlace(game:GetWidget("god_place"))
	g_SatisfactionView = ConvertToCSatisfactionView(game:GetWidget("satisfaction_view"))
	g_LifeScene = ConvertToCLifeScene(game:GetWidget("life_scene"))

	g_Pipeline:SetLua(g_Lua)
	g_Discard:SetLua(g_Lua)


	g_AmuletName = ConvertToCLabelWidget(game:GetWidget("amulet_name"))
	g_AmuletCost = ConvertToCLabelWidget(game:GetWidget("amulet_cost"))
	g_AmuletsCount = ConvertToCLabelWidget(game:GetWidget("amulets_count"))

	g_GoalScoreView = ConvertToCLabelWidget(game:GetWidget("goal_score_view"))
	g_GlobalScoreView = ConvertToCLabelWidget(game:GetWidget("global_score_view"))
	g_ScoreView = ConvertToCLabelWidget(game:GetWidget("score_view"))
	g_GemsView = ConvertToCLabelWidget(game:GetWidget("gems_view"))

	g_AromaView = ConvertToCLabelWidget(game:GetWidget("aroma_view"))
	g_FoodView = ConvertToCLabelWidget(game:GetWidget("food_view"))
	g_LotusView = ConvertToCLabelWidget(game:GetWidget("lotus_view"))

	g_LivesView = ConvertToCLabelWidget(game:GetWidget("lives_view"))
	g_LevelView = ConvertToCLabelWidget(game:GetWidget("level"))
	g_CurAmuletValue = ConvertToCLabelWidget(game:GetWidget("cur_amulet_value"))

	-- переменные текущего состояния игры
	g_GameVars = {}

	g_GameVars.state_before_level = 1
	g_GameVars.state_playing_level = 2
	g_GameVars.state_after_level = 3
	g_GameVars.state_between_levels = 4
	g_GameVars.LevelState = g_GameVars.before_level

	g_GameVars.force_change = false
	g_GameVars.location = -1

	g_GameVars.easy_lvl1 = false
	g_GameVars.easy_lvl2 = false
	g_GameVars.easy_lvl3 = false
	g_GameVars.location_loses = 0

	g_GameVars.paused = 0
	g_GameVars.wrong_shape_pause = 0
	g_GameVars.enable_gem_bonus = false

	init_game_music()
	init_game_events()
end

-------------------------------------------------------------------------------------------------

local g_LuaInfoTime = 0

function game_update(game, dt)
	g_LuaInfoTime = g_LuaInfoTime - dt
	if g_LuaInfoTime<=0 then
		lua_info()
		g_LuaInfoTime = 1000
	end

	g_Globals.value_chaged_timer = g_Globals.value_chaged_timer - dt
	if g_Globals.value_chaged_timer<0 then g_Globals.value_chaged_timer = 0 end

	g_GameVars.wrong_shape_pause = g_GameVars.wrong_shape_pause - dt
	if  g_GameVars.wrong_shape_pause<0 then g_GameVars.wrong_shape_pause = 0 end

	g_Loader:UpdateFileChanges()
	g_Lua:CheckFileChanges()
	string_table():CheckChanges()

	if g_Game:IsEnabled() then 
		update_level(game, dt) 
		if not trial_controller():IsRegistered() then
			trial_controller():UpdateF(dt)
			if trial_controller():GetTimeLeft()<=0 then
				pause_game(true)				
				local dlg = create_dialog(g_State, "time_expired_dialog")
				dlg:SetGenericActionHandler("ingame_time_expired_dialog_generic_handler")
			end
		end
	end

end

-------------------------------------------------------------------------------------------------

function ingame_time_expired_dialog_generic_handler(window, action, widget)
	standard_generic_handler(window, action, widget)

	if action=="pressed" then
		if widget:GetId()=="right" then
			pause_game(false)
			ShellExecute("registrator.exe", "1 1")
			quit_game()
			window:Close()
		
		elseif widget:GetId()=="left" then
			pause_game(false)
			start_mainmenu_state()
			window:Close()
		end
	end
end

-------------------------------------------------------------------------------------------------

function game_generic_handler(window, action, widget)
	standard_generic_handler(window, action, widget)

	if action=="pressed" then
		if widget:GetId()=="menu" then
			show_game_options(g_State)
		elseif widget:GetId()=="help" then
			show_help(g_State)
		end
	end

	if action=="layer_mouse_down" and widget:GetId()=="lualayerwidget" then
		window:RemoveWidget(widget)
		g_GameVars.StatePause = 0
	end
end

-------------------------------------------------------------------------------------------------

function on_game_key_down(game, key, state)

	if key==keycodes.KEYCODE_SPACE then
		if g_GameVars.LevelState~=g_GameVars.state_playing_level or not g_StripeArea:IsPlaying()  then return end
		if g_Cursor:GetShape().__ok
		then 	
			local shape = g_Cursor:GetShape()
			g_Cursor:ClearShape()
			discard_shape(shape)
		else 
			if not g_Discard:IsReady() then return end
			local shape = g_Pipeline:GetShape(0)
			g_Pipeline:RemoveFirstShape()
			discard_shape(shape)
			g_Discard:Pause()
			add_shape(g_Pipeline)
		end

	elseif key==27 or key==80 or key==19 then
		-- Esc, P, Pause
		show_game_options(g_State)

	elseif key==112 then
		-- F1
		show_help(g_State)

	elseif g_App:IsCheatsEnabled() then
		if key>=49 and key<=53 then 
			-- от '1' до '5'
			g_StripeArea:RemoveStripe(g_StripeArea:GetStripe(key-49))
			create_stripe(g_StripeArea, -g_StripeArea:GetStripe(0):GetSpeed())
		elseif key==13 then 
			-- enter
			add_score(g_GameVars.current_amulet_value)
			change_amulet()
		elseif key==107 then
			-- add
			add_coins(1)
		elseif key==9 then
			-- Tab
			if state~=4 then add_score(g_GameVars.goal_score) end
			end_level()
		elseif key==81 then
			-- Q
			local shape = g_Pipeline:GetShape(0)
			g_Pipeline:RemoveFirstShape()
			discard_shape(shape)
			g_Discard:Pause()
			add_shape(g_Pipeline, 1)
		elseif key==87 then 
			-- W 
			local shape = g_Pipeline:GetShape(0)
			g_Pipeline:RemoveFirstShape()
			discard_shape(shape)
			g_Discard:Pause()
			add_shape(g_Pipeline, 2)
		elseif key==69 then 		
			-- E
			local shape = g_Pipeline:GetShape(0)
			g_Pipeline:RemoveFirstShape()
			discard_shape(shape)
			g_Discard:Pause()
			add_shape(g_Pipeline, 3)
		elseif key==65 then 
			-- A
			create_hole_bonus("Gem")
		elseif key==83 then 
			-- S
			create_hole_bonus("Revealer")
		elseif key==68 then 
			-- D
			create_hole_bonus("Pause")
		end
	end

end
