-- External requirements
local socket = require("socket")
local ffi = require("ffi")
local require_l = require

-- Disallow access to undefined global variables (helps detect errors)
assert(getmetatable(_G)==nil, "_G already has a metatable")
setmetatable(_G, {
	__index = function(t, i) error("attempt to access nil variable "..i, 2) end
})

-- Set save directory
OPT_SAVE_DIR = arg[1] or error("must specify save location")
OPT_SAVE_DIR = OPT_SAVE_DIR:gsub("\\", "/")
OPT_SAVE_DIR = OPT_SAVE_DIR:gsub("/$", "")
print("Save location set to \""..OPT_SAVE_DIR.."\"")

-- Local includes
dofile("iosafe.lua")
FFI = ffi
Socket = socket
require = require_l
dofile("utility.lua")
dofile("simulation.lua")
dofile("group.lua")
dofile("wire.lua")
dofile("gatedef.lua")
dofile("port.lua")
dofile("gate.lua")
dofile("save.lua")
dofile("network.lua")
dofile("compiled_sim_gates.lua")
FFI = nil
Socket = nil
require = nil

-- Default settings
OPT_TICK_ENABLED = true
OPT_TICK_TIME = 0.032
OPT_TICK_MULT = 1
OPT_FX_UPDATES = true
OPT_FX_TIME = 0.032

-- Tick rate measurement state
local tickdelay = 0
local ticksperinterval = 0
local lastticktime = 0
local ticks = 0
local tickrate = 0
local lastmeasuretime = 0
local lastfxtime = 0
local avgticks = {}
local totalticks = 0

-- Create new simulation
local sim = Simulation.new(Simulation)
GSim = sim

network_accept_client()

while true do
	network_update()
	
	local time = os.clock()
	
	if OPT_TICK_ENABLED then
		if time-lastticktime >= OPT_TICK_TIME then
			lastticktime = time
			
			Simulation.tickinit(sim)
			Simulation.tickinput(sim)
			
			for i = 1, OPT_TICK_MULT, 97 do
				local ticksthis = math.min(OPT_TICK_MULT-i+1, 97)
				for j = 1, ticksthis do
					Simulation.ticklogic(sim)
				end
				ticks = ticks+ticksthis
				
				if os.clock()-time>0.1 then
					break
				end
			end
			
			local sleeptime = time+OPT_TICK_TIME-os.clock()-0.005
			if sleeptime>0 then socket.sleep(sleeptime) end
		end
	else
		socket.sleep(0.05)
	end
	
	if time-lastfxtime >= OPT_FX_TIME then
		if OPT_FX_UPDATES then
			Simulation.sendfxupdate(sim)
		end
		Simulation.sendcallbacks(sim)
		lastfxtime = time
	end
	
	if time-lastmeasuretime >= 0.1 then
		if #avgticks >= 10 then
			totalticks = totalticks - table.remove(avgticks, 1)
		end
		
		table.insert(avgticks, ticks)
		totalticks = totalticks + ticks
		
		ticks = 0
		
		network_send("TPS\t" .. unitize((totalticks/#avgticks)/0.1) .. "\n")
		lastmeasuretime = os.clock()
	end
end