PS = {}
PS.__index = PS

PS.Items = {}
PS.Categories = {}
PS.ClientsideModels = {}

local cnt = 0

function PS:ValidateItems(items)
	if !istable(items) then
		return {}
	end
	for item_id, item in pairs(items) do
		if !self.Items[item_id] then
			items[item_id] = nil
		end
	end
	return items
end

function PS:FindCategoryByName(cat_name)
	for id, cat in pairs(self.Categories) do
		if cat.Name == cat_name then
			return cat
		end
	end
	return false
end

function PS:ModifyModel(tbl, ply, model, pos, ang)
	tbl = tbl and tbl or {ang = {0, 0, 0}, pos = {0, 0, 0}}

	local tb = model:GetTable()

	if tbl["size"] and !tb.matrix then
		local size = Vector(tbl["size"][1], tbl["size"][2], tbl["size"][3])

		tb.matrix = Matrix()
		tb.matrix:Scale(size)
		model:EnableMatrix("RenderMultiply", tb.matrix)
	end

	if !tb.mang then
		tb.mang = Angle(tbl["ang"][1], tbl["ang"][2], tbl["ang"][3])
	end
	if !tb.mpos then
		tb.mpos = Vector(tbl["pos"][1], tbl["pos"][2], tbl["pos"][3])
	end

	pos = pos + (ang:Forward() * tb.mpos.x) + (ang:Up() * tb.mpos.z) + (ang:Right() * tb.mpos.y)

	ang:RotateAroundAxis(ang:Forward(), tb.mang.p)
	ang:RotateAroundAxis(ang:Up(), tb.mang.y)
	ang:RotateAroundAxis(ang:Right(), tb.mang.r)

	return model, pos, ang
end

function PS:AddItem()
	if !ITEM.ID then
		ErrorNoHalt("Missing item ID for "..(ITEM.Name or "undefined item").."!")
	else
		local item = {}

		item.ID = ITEM.ID
		item.Category = CATEGORY.Name
		item.AlowedEquipped = CATEGORY.AllowedEquipped
		item.Price = 0
		item.AdminOnly = false
		item.AllowedUserGroups = {}
		item.TeamExclude = {}
		item.TeamOnly = {}
		item.SingleUse = false
		item.NoPreview = false
		item.CanPlayerBuy = true
		item.CanPlayerSell = true
		item.CanPlayerEquip = true
		item.CanPlayerHolster = true
		item.SharedInventory = false
		item.OnBuy = function()
		end
		item.OnSell = function()
		end
		item.OnPlayerEquip = function()
		end
		item.OnEquip = function()
		end
		item.OnPlayerHolster = function()
		end
		item.OnHolster = function()
		end
		item.OnModify = function()
		end
		item.ModifyClientsideModel = function(ITEM, ply, model, pos, ang)
			return model, pos, ang
		end
		item.PostModifyClientsideModel = function(ITEM, ply, model, pos, ang)
		end
		table.Merge(item, ITEM)
		if !item.Name then
			ErrorNoHalt("[Krämer] Missing item name: "..CATEGORY.Name.."/"..item.Name.."\n")
		elseif !item.Price then
			ErrorNoHalt("[Krämer] Missing item price: "..CATEGORY.Name.."/"..item.Name.."\n")
		elseif !item.Model and !item.Material then
			ErrorNoHalt("[Krämer] Missing item model or material: "..CATEGORY.Name.."/"..item.Name.."\n")
		else
			if item.Model then
				util.PrecacheModel(item.Model)
			end

			self.Items[item.ID] = item
		end

		cnt = cnt + 1
	end

	ITEM = {}
end

function PS:LoadItems()
	self.Loaded = true

	cnt = 0

	local time = SysTime()
	print("[Krämer] Starting to load all chandler items...")
	local _, dirs = file.Find("ps_items/*", "LUA")
	for _, category in pairs(dirs) do
		local f = file.Find("ps_items/"..category.."/__category.lua", "LUA")
		if #f > 0 then
			CATEGORY = {}
			CATEGORY.Name = ""
			CATEGORY.Order = 0
			CATEGORY.AllowedEquipped = -1
			CATEGORY.AllowedUserGroups = {}
			CATEGORY.CanPlayerSee = function()
				return true
			end
			if SERVER then
				AddCSLuaFile("ps_items/"..category.."/__category.lua")
			end
			include("ps_items/"..category.."/__category.lua")
			if !self.Categories[category] then
				self.Categories[category] = CATEGORY
			end
			local files = file.Find("ps_items/"..category.."/*.lua", "LUA")

			for _, name in pairs(files) do
				if name != "__category.lua" then
					if SERVER then
						AddCSLuaFile("ps_items/"..category.."/"..name)
					end

					ITEM = {}

					include("ps_items/"..category.."/"..name)
				end
			end

			CATEGORY.ItemCount = cnt

			ITEM = nil

			CATEGORY = nil
		end
	end
	self.ItemCount = cnt
	print("[Krämer] Added "..cnt.." chandler items in "..(SysTime() - time).."s.")
end

concommand.Add("shop_reload", function(ply)
	if !MG_DeveloperGroups[ply:GetUserGroup()] then return end

	PS:LoadItems()
end)

function PS:IsCosmetic(item_id)
	local ITEM = self.Items[item_id]
	return (ITEM.Bone or ITEM.Attachment) and !ITEM.WeaponClass and !ITEM.NoPreview
end