USGN_DEFAULTDATA = {}
USGN_DATAPATH = mod_path.."data/"

-- User
USER_DATA = {}
USER_META = {}
USER = {}

function USER_META.__index(t,id)
	if type(id) == "number" and id > 0 then
		if not USER_DATA[id] then
			if player(id, "usgn") > 0 then
				USER_DATA[id] = USGN[player(id,"usgn")]
			else
				USER_DATA[id] = {}
				USER_DATA[id].data = table.copy(USGN_DEFAULTDATA or {})
				setmetatable(USER_DATA[id], USGN_USERMETA)
			end
		end
		return USER_DATA[id]
	end
end

function USER_META.__newindex(t,k,v)
	t["data"][k] = v
end

-- USGN
USGN_META = {}
USGN_DATA = {}
function USGN_META.__index(t,id)
	if USGN_DATA[id] then return USGN_DATA[id] end
	if type(id) == "number" and id > 0 then
		return LoadUSGN(id)
	end
end

USGN = {}
USGN_USERMETA = {}

function USGN_USERMETA.__index(t,k)
	return t["data"][k]
end

function USGN_USERMETA.__newindex(t,k,v)
	t["data"][k] = v
end

function NewUSGN(id)
	USGN_DATA[id] = CreateData()
	USGN_DATA[id].data = table.copy(USGN_DEFAULTDATA or {})
	return USGN_DATA[id]
end

function LoadUSGN(id)
	local t = NewUSGN(id)
	local stream = ReadStream(USGN_DATAPATH..id..".txt")

	if stream then
		local data_name, data_value = ReadData(stream)
		while data_name ~= nil and data_value ~= nil do
			t.data[data_name] = data_value
			data_name, data_value = ReadData(stream)
		end
		CloseStream(stream)
	end
	return t
end

function SaveUSGN(id)
	if id > 0 then
		local t = USGN[id]
		local stream = WriteStream(USGN_DATAPATH..id..".txt")

		if stream then
			for k, v in pairs(t.data) do
				SaveData(stream, k, v)
			end
			CloseStream(stream)
			return true
		end
	end
end

-- USER TEMP
USERTEMP_DEFAULTDATA = {}

USERTEMP = {}
USERTEMP_DATA = {}
USERTEMP_META = {}

function USERTEMP_META.__index(t,id)
	if not USERTEMP_DATA[id] then
		USERTEMP_DATA[id] = CreateData()
		USERTEMP_DATA[id] = table.copy(USERTEMP_DEFAULTDATA) or {}
	end
	return USERTEMP_DATA[id]
end

-- IP Data
USERIP_DEFAULTDATA = {}

USERIP = {}
USERIP_DATA = {}
USERIP_META = {}

function USERIP_META.__index(t,ip)
	if not USERIP_DATA[ip] then LoadIPData(ip) end
	return USERIP_DATA[ip]
end

function LoadIPData(ip)
	local t = CreateData()
	local stream = ReadStream(mod_path.."data/ip_"..ip..".txt")
	t.data = table.copy(USERIP_DEFAULTDATA or {})
	
	if stream then
		local data_name, data_value = ReadData(stream)
		while data_name and data_value do
			t.data[data_name] = data_value
			data_name, data_value = ReadData(stream)
		end
		
		CloseStream(stream)
	end
	
	USERIP_DATA[ip] = t
	return t
end

function SaveIPData(ip)
	local t = USERIP[ip]
	if not t then return end
	if table.size(t.data) == 0 then
		return os.remove(mod_path.."data/ip_"..ip..".txt")
	end
	
	local stream = WriteStream(mod_path.."data/ip_"..ip..".txt")
	if stream then
		for k, v in pairs(t.data) do
			SaveData(stream, k, v)
		end
		CloseStream(stream)
		return true
	end
end

-- Data functions
function CreateData()
	local t = {data = {}}
	setmetatable(t, USGN_USERMETA)
	return t
end

function LoadData(file)
	local t = {data = {}}
	local stream = ReadStream(file)
	
	if stream then
		local data_name, data_value = ReadData(stream)
		while data_name ~= nil and data_value ~= nil do
			t.data[data_name] = data_value
			data_name, data_value = ReadData(stream)
		end
		CloseStream(stream)
		
		setmetatable(t, USGN_USERMETA)
		return t
	end
end

function SaveDataFile(t, file)
	if table.size(t.data) == 0 then return end
	local stream = WriteStream(file)
	if stream then
		for k, v in pairs(t.data) do
			SaveData(stream, k, v)
		end
		CloseStream(stream)
		return true
	end
end

function SaveUSER(id)
	if player(id,"usgn") > 0 then
		SaveUSGN(player(id, "usgn"))
	end
end

setmetatable(USGN, USGN_META)
setmetatable(USER, USER_META)
setmetatable(USERTEMP, USERTEMP_META)
setmetatable(USERIP, USERIP_META)

function ReadData(s)
	local key_type = ReadByte(s)
	local data_name
	if key_type == 110 then
		data_name = tonumber(ReadLine(s))
	elseif key_type == 115 then
		data_name = ReadLine(s)
	end

	local data_type = ReadString(s, 2)
	local data_value
	if data_type == "nu" then
		data_value = tonumber(ReadLong(s))
	elseif data_type == "st" then
		data_value = ReadLine(s)
	elseif data_type == "ta" then
		data_value = {}

		local size = ReadInt(s)
		for i = 1, size do
			local dn, dv = ReadData(s)
			data_value[dn] = dv
		end
	elseif data_type == "bo" or data_type == "ni" then
		local v = tonumber(ReadByte(s))
		if v == 1 then
			data_value = true
		elseif v == 0 then
			data_value = false
		end
	end

	return data_name, data_value
end

function SaveData(s,data_name,data_value)
	local key_type = string.byte(type(data_name), 1)
	WriteByte(s, key_type)
	WriteLine(s, data_name)

	local data_type = string.sub(type(data_value), 1, 2)
	WriteString(s, data_type)

	if data_type == "nu" then
		WriteLong(s, data_value)
	elseif data_type == "st" then
		WriteLine(s, data_value)
	elseif data_type == "ta" then
		WriteInt(s, table.size(data_value))
		for k, v in pairs(data_value) do
			SaveData(s, k, v)
		end
	elseif data_type == "bo" or data_type == "ni" then
		if data_value then
			WriteByte(s, 1)
		elseif not data_value then
			WriteByte(s, 0)
		end
	end
end

function ReloadUSER(id)
	USER_DATA[id] = nil
	return USER[id]
end

function ReloadUSGN(id)
	USGN[id] = nil
	return USGN[id]
end

function ReloadTEMP(id)
	USERTEMP_DATA[id] = nil
	return USERTEMP[id]
end

function DeleteUSGN(u)
	USGN[u] = nil
end

function DeleteUSER(id)
	USER[id] = nil
end