APP = {
	gameString = "daisyMoonGame",
	versionString = "0.0",
	maxUpdateTime = .06,
	fixedStep = true,
	stepTime = .015625,
	turnStepTime = .00625,
	yieldStep = .015625*10,
	timeFactor = 1,
	protectRandomInRendering = false,
	optimizeInit = true,
	garbageCollectionRate = 10,
	garbageCollectionOvercheck = 1.1,
}

app = {}

app.runtime = {
	updateCount = 0,
	time = 0,
	strayTime = 0,
	configs = {},
	initOptimizationTimer = 0,
	realFps = 0,
	showMouse = true,
	blurSleep = true,
	gcPool = 0,
}

function app.checkYield(yield, ...)
	if yield and not yield.disabled and daisy.getSeconds() > yield:getThredhold() then
		coroutine.yield(...)
	end
end


function app.setWindowBlurSleep(f) 
	if f ~= nil then
		if f ~= app.runtime.blurSleep then
			app.runtime.blurSleep = f
			daisy.setWindowBlurSleep(f)
		end
	else
		daisy.setWindowBlurSleep(app.runtime.blurSleep)
	end
end

function app.init()
	app.started = true
	-- init interface
	daisy.setMouseVisible(not APP.hideMousePointer)
	video.setForcePointSampling(true)
end

function app.update(time)

	app.runtime.time = app.runtime.time + time
	
	if app.runtime.showMouse then
		daisy.setMouseVisible(app.runtime.showMouse)
	else
		local mx,my = daisy.getMousePosition()
		if mx >= 0 and mx <= window.w and my >= 0 and my <= window.h then
			daisy.setMouseVisible(app.runtime.showMouse)
		else
			daisy.setMouseVisible(true)
		end
	end
	
	app.runtime.realFps = 1/time
	
	if APP.maxUpdateTime and time > APP.maxUpdateTime then time = APP.maxUpdateTime end
		
	if APP.fixedStep then
		if (DEBUG.forceOneFramePerRender or DEBUG.oneFramePerRender) then time = math.min(time, APP.stepTime) end

		app.runtime.strayTime = app.runtime.strayTime + time
		local step = APP.stepTime*(APP.timeFactor or 1)

		while app.runtime.strayTime >= APP.stepTime do
			debug.enterFrame(APP.stepTime)
			app.runtime.updateCount = app.runtime.updateCount + 1
			app.runtime.strayTime = app.runtime.strayTime - APP.stepTime
			if DEBUG.enableSlowDown then
				states.update(step/8)
			else
				states.update(step)
			end
		end
		states.interpolate(math.min(0,math.min(1,app.runtime.strayTime/step)))
	else
		debug.enterFrame(time)
		states.update(time)
	end

	if APP.optimizeInit then
		if app.runtime.initOptimizationTimer <= 1 then
			if app.runtime.realFps <= 50 or app.runtime.doOptimize then
				app.runtime.skipRender = true
				app.runtime.doOptimize = true
			end
			app.runtime.initOptimizationTimer = app.runtime.initOptimizationTimer + time/0.1
			if app.runtime.initOptimizationTimer >= 1 then
				app.runtime.skipRender = false
				app.runtime.doOptimize = false
			end
		end
	end
end

function app.collectGarbage(time)
	if not DEBUG.disableGc then
		app.runtime.mem = collectgarbage("count")
		if app.runtime.lastMem then
			collectgarbage("step", math.max(APP.garbageCollectionRate,time*app.runtime.gcPool*APP.garbageCollectionOvercheck))
			app.runtime.gcPool = math.max(0,app.runtime.gcPool + math.max(0,app.runtime.mem - app.runtime.lastMem) - app.runtime.gcPool*time)
		end
		app.runtime.lastMem = app.runtime.mem
	end
end

local function protectedRandom(a,b) 
	--print("don't use random in rendering") 
end

function app.render()
	local oldRand = math.random
	
	if APP.protectRandomInRendering then		
		math.random = protectedRandom
	end

	if not DEBUG.disableRender and not app.runtime.skipRender then
		states.preRender()
		states.render()		
		
	end
	
	

	if APP.protectRandomInRendering then
		math.random = oldRand
	end
end

function app.postRender()
end

-- Setup garbage collection
-- "setstepmul" is a multiplier which says how much clean-up that should be made each
--    clean-up phase. According to the documentation, lower values means faster (where
--    0 means "clean up everything"), but that doesn't match how it is implemented.
--    The default value is 200.
-- "setpause" is how much the memory must grow before the garbage collector is
--    started. This value is a percentage of the current memory (I think). So the
--    default value 200 means that the memory needs to double to start the garbage
--    collector.
function app.initGarbageCollect()
	collectgarbage("setstepmul", 200)	-- keep default
	collectgarbage("setpause", 105)		-- almost always run the collector 
end

function app.hideMouse()
	app.runtime.showMouse = false
	daisy.setMouseVisible(false)
end