-- GLOBALS

states = {}
states.references = {}
states.renderOrder = {}
states.updateOrder = {}

function states.update(time)
	for index, state in ipairs(states.updateOrder) do
		if state.enabled and state.state.update and not state.paused then
			
			if DEBUG.showDebug and DEBUG.showPerformanceBreakdown and DEBUG.performanceGroup == "states" then
				debug.enterPerformanceType(state.id.." update", "states")
			end
			
			local newState = state.state:update(time)
			state.updated = true
			if newState then
				if state.state.close then
					state.state:close()
				end

				state.state = newState

				if state.state.init then
					state.state:init()
				end
			end
			
			if DEBUG.showDebug and DEBUG.showPerformanceBreakdown and DEBUG.performanceGroup == "states" then
				debug.exitPerformanceType(state.id.." update", "states")
			end
			
		end
	end
end

function states.getAll()
	return states.references
end

function states.getAllUpdateOrdered()
	return states.updateOrder
end

function states.getAllRenderOrdered()
	return states.renderOrder
end

function states.getHolder(id)
	return states.references[id]
end

function states.get(id)
	return states.references[id].state
end

function states.preRender()
	for index, state in ipairs(states.renderOrder) do
		if state.enabled and state.render and state.updated and state.state.preRender then	
			if DEBUG.showDebug and DEBUG.showPerformanceBreakdown and DEBUG.performanceGroup == "states" then
				debug.enterPerformanceType(state.id.." render", "states")
			end
			state.state:preRender()
			if DEBUG.showDebug and DEBUG.showPerformanceBreakdown and DEBUG.performanceGroup == "states" then
				debug.exitPerformanceType(state.id.." render", "states")
			end
		end
	end
end

function states.render()
	for index, state in ipairs(states.renderOrder) do
		if state.enabled and state.render and state.updated and state.state.render then	
			if DEBUG.showDebug and DEBUG.showPerformanceBreakdown and DEBUG.performanceGroup == "states" then
				debug.enterPerformanceType(state.id.." render", "states")
			end
			state.state:render()
			if DEBUG.showDebug and DEBUG.showPerformanceBreakdown and DEBUG.performanceGroup == "states" then
				debug.exitPerformanceType(state.id.." render", "states")
			end
		end
	end
end

local function renderOrderSort(a,b)
	return a.renderOrder < b.renderOrder
end

local function updateOrderSort(a,b)
	return a.updateOrder < b.updateOrder
end
		
function states.refreshOrder()
	for i=1, #states.renderOrder do
		table.remove(states.renderOrder, 1)
	end
	for i=1, #states.updateOrder do
		table.remove(states.updateOrder, 1)
	end
	for index, holder in pairs(states.references) do
		table.insert(states.renderOrder, holder)
		table.insert(states.updateOrder, holder)
	end
	shellsort(states.renderOrder, renderOrderSort)
	shellsort(states.updateOrder, updateOrderSort)
end

function states.setRenderOrder(id, order)
	local s = states.getHolder(id)
	if s then
		s.renderOrder = order
		states.refreshOrder()
	else
		debug.print(1, "cannot find "..id)
	end
end

function states.setUpdateOrder(id, order)
	local s = states.getHolder(id)
	if s then
		s.updateOrder = order
		states.refreshOrder()
	else
		debug.print(1, "cannot find "..id)
	end
end

function states.renderDebug()
	for index, state in pairs(states.renderOrder) do
		if state.enabled and state.render and state.updated and state.state.renderDebug then
			state.state:renderDebug()
		end
	end
end

function states.keyCharacter(byte)
	for index, state in pairs(states.references) do
		if state and state.enabled and state.state.keyCharacter then
			state.state:keyCharacter(byte)
		end
	end
end

function states.keyPressed(key)
	for index, state in pairs(states.references) do
		if state and state.enabled and state.state.keyPressed then
			state.state:keyPressed(key)
		end
	end
end

function states.mouseClick(x, y, button, count)
	for index, state in pairs(states.references) do
		if state and state.enabled and state.state.mouseClick then
			state.state:mouseClick(x,y,button,count)
		end
	end
end

function states.joyPressed(joy, btn)
	for index, state in pairs(states.references) do
		if state and state.enabled and state.state.joyButtonPressed then
			state.state:joyButtonPressed(joy,btn)
		end
	end
end

function states.joyReleased(joy, btn)
	for index, state in pairs(states.references) do
		if state and state.enabled and state.state.joyButtonReleased then
			state.state:joyButtonReleased(joy,btn)
		end
	end
end

function states.add(state, id)
	local holder = {}
	holder.id = id
	holder.enabled = true
	holder.render = true
	holder.updated = false
	holder.state = state
	holder.renderOrder = 0
	holder.updateOrder = 0
	
	if states.references[id] then
		states.destroy(id)
	end
	
	states.references[id] = holder
	states.refreshOrder()
	
	if state.init then
		state:init()
	end
	
	return state
end

function states.isEnabled(id)
	return states.references[id] and states.references[id].enabled
end

function states.enable(id)
	local state = states.references[id]
	if state then
		state.state:enable()
		state.enabled = true
	end
end

function states.disable(id)
	local state = states.references[id]
	if state then
		state.state:disable()
		state.enabled = false
	end
end

function states.pause(id)
	local state = states.references[id]
	if state then
		state.paused = true
	end
end

function states.unpause(id)
	local state = states.references[id]
	if state then
		state.paused = false
	end
end

function states.hide(id)
	local state = states.references[id]
	if state then
		if state.state.hide then
			state.state:hide()
		end
		state.render = false
	end
end

function states.show(id)
	local state = states.references[id]
	if state then
		if state.state.show then
			state.state:show()
		end
		state.render = true
	end
end

function states.toggle(id)
	local state = states.references[id]
	if state then
		state.enabled = not state._enabled
		if state.state.enabled then
			if state.state.enable then
				state.state:enable()
			end
		else
			if state.state.disable then 
				state.state:disable()
			end
		end
	end
end

function states.protect(id)
	local state = states.references[id]
	if state then
		state.protected = true
	end
end

function states.unProtect(id)
	local state = states.references[id]
	if state then
		state.protected = false
	end
end

function states.destroy(id)
	local state = states.references[id]
	if state then
		if not state.protected then
			if state.state.close then
				state.state:close()
			end
			states.references[id] = nil
		end
	end
	states:refreshOrder()
end

function states.destroyAll()
	for index, state in pairs (states.references) do
		if not state.protected then
			if state.state.close then
				state.state:close()
			end
			states.references[index] = nil
		end
	end
	states:refreshOrder()
end

function states.destroyAllForced()
	for index, state in pairs (states.references) do
		if state.state.close then
			state.state:close()
		end
		states.references[index] = nil
	end
	states:refreshOrder()
end

