local meta = FindMetaTable("Player")

if SERVER then
	util.AddNetworkString("MG_CarDealer_OpenShop_S2C")

	function meta:MG_CarDealer_OpenShop(npc)
		net.Start("MG_CarDealer_OpenShop_S2C")
			net.WriteEntity(npc)
		net.Send(self)
	end
else
	net.Receive("MG_CarDealer_OpenShop_S2C", function()
		MG_CarDealer.OpenShop(net.ReadEntity())
	end)
end

if SERVER then
	util.AddNetworkString("MG_CarDealer_SendPlayerData_C2S")

	local function SendPlayerData(self, data, sid)
		local compressed = util.Compress(util.TableToJSON(data or {}))
		local leng = compressed:len()
		net.Start("MG_CarDealer_SendPlayerData_C2S")
			net.WriteUInt(leng, 16)
			net.WriteData(compressed, leng)
			net.WriteString(sid)
		net.Send(self)
	end

	function meta:MG_CarDealer_SendPlayerData(sid)
		MG_CarDealer_Provider.GetVehicles(sid, function(data)
			if !IsValid(self) then return end
			SendPlayerData(self, data, sid)
		end)
	end

	net.Receive("MG_CarDealer_SendPlayerData_C2S", function(len, ply)
		if !MG_CarDealerConfig:IsSuperAdmin(ply) then return end
		local sid = net.ReadString()
		MG_CarDealer_Provider.GetVehicles(sid, function(data)
			if !IsValid(ply) then return end
			SendPlayerData(ply, data, sid)
		end)
	end)
else
	function MG_CarDealer.GetPlayerData(sid)
		net.Start("MG_CarDealer_SendPlayerData_C2S")
			net.WriteString(sid)
		net.SendToServer()
	end
end

if SERVER then
	util.AddNetworkString("MG_CarDealer_Notice_S2C")

	function meta:MG_CarDealer_SendNotice(text)
		net.Start("MG_CarDealer_Notice_S2C")
			net.WriteString(text)
		net.Send(self)
	end
else
	local MG_CarDealerNoticePanel
	function MG_CarDealer.ShowNotice(text)
		if IsValid(MG_CarDealerNoticePanel) then MG_CarDealerNoticePanel:Remove() end	
		MG_CarDealerNoticePanel = vgui.Create("DPanel")
		MG_CarDealerNoticePanel:SetSize(ScrW(), ScrH())
		MG_CarDealerNoticePanel:MakePopup()
		MG_CarDealerNoticePanel:ParentToHUD()
		local ply = LocalPlayer()
		MG_CarDealerNoticePanel.Paint = function(slf)
			if !ply:Alive() then
				MG_CarDealerNoticePanel:Remove()
				return
			end
			surface.SetDrawColor(Color(0, 0, 0, 200))
			surface.DrawRect(0, 0, slf:GetWide(), slf:GetTall())
			draw.SimpleText(text, "MG_CarDealer_Treb_S30", ScrW() / 2, ScrH() / 2, Color(0, 255, 255, 255), TEXT_ALIGN_CENTER)
		end
		local Button_Okay = vgui.Create("CarDealer_DSWButton", MG_CarDealerNoticePanel)
		Button_Okay:SetPos(MG_CarDealerNoticePanel:GetWide() / 2 - 100, MG_CarDealerNoticePanel:GetTall() / 3 * 2)
		Button_Okay:SetSize(200, 30)
		Button_Okay:SetTexts("Okay")
		Button_Okay.Click = function(slf)
			MG_CarDealerNoticePanel:Remove()
		end
	end

	net.Receive("MG_CarDealer_Notice_S2C", function()
		MG_CarDealer.ShowNotice(net.ReadString())
	end)
end

if SERVER then
	util.AddNetworkString("MG_CarDealer_INVSync_S2C")

	MG_CarDealer.DrivingCars = {}
	function meta:MG_CarDealer_SyncInv()
		MG_CarDealer_Provider.GetVehicles(self:SteamID(), function(data)
			if !IsValid(self) then return end
			data = data or {}
			for i = #data, 1, -1 do
				local index = data[i]
				if index and index.id and MG_CarDealer.DrivingCars[tonumber(index.id)] then
					table.remove(data, i)
				end
			end
			local compressed = util.Compress(util.TableToJSON(data))
			local leng = compressed:len()
			net.Start("MG_CarDealer_INVSync_S2C")
				net.WriteUInt(leng, 16)
				net.WriteData(compressed, leng)
			net.Send(self)
			if func then
				func(data)
			end
		end)
	end
else
	net.Receive("MG_CarDealer_INVSync_S2C", function()
		local leng = net.ReadUInt(16)
		MG_CarDealer_Inventory = util.JSONToTable(util.Decompress(net.ReadData(leng)))
		hook.Run("MG_CarDealer_InvAdjusted")
	end)
end

if SERVER then
	util.AddNetworkString("MG_CarDealer_BuyCar_C2S")

	net.Receive("MG_CarDealer_BuyCar_C2S", function(len, ply)
		local carclass = net.ReadString()
		if !ply:MG_CarDealer_CanBuyCar(carclass) then return end
		ply:MG_CarDealer_BuyVehicle(carclass)
	end)
else
	function MG_CarDealer.BuyVehicle(carclass)
		net.Start("MG_CarDealer_BuyCar_C2S")
			net.WriteString(carclass)
		net.SendToServer()
	end
end

if SERVER then
	util.AddNetworkString("MG_CarDealer_Admin_AddCar_C2S")

	net.Receive("MG_CarDealer_Admin_AddCar_C2S", function(len, ply)
		ply:MG_CarDealer_Admin_AddVehicle(net.ReadString(), net.ReadString())
	end)
else
	function MG_CarDealer.Admin_AddVehicle(sid, carclass)
		net.Start("MG_CarDealer_Admin_AddCar_C2S")
			net.WriteString(sid)
			net.WriteString(carclass)
		net.SendToServer()
	end
end

if SERVER then
	util.AddNetworkString("MG_CarDealer_SellVehicle_C2S")

	net.Receive("MG_CarDealer_SellVehicle_C2S", function(len, ply)
		ply:MG_CarDealer_SellVehicle(net.ReadUInt(32))
	end)
else
	function MG_CarDealer.SellVehicle(id)
		net.Start("MG_CarDealer_SellVehicle_C2S")
			net.WriteUInt(id, 32)
		net.SendToServer()
	end
end

if SERVER then
	util.AddNetworkString("MG_CarDealer_Admin_DestroyVehicle_C2S")

	net.Receive("MG_CarDealer_Admin_DestroyVehicle_C2S", function(len, ply)
		if !MG_CarDealerConfig:IsSuperAdmin(ply) then return end
		ply:MG_CarDealer_Admin_DestroyVehicle(net.ReadString(), net.ReadUInt(32))
	end)
else
	function MG_CarDealer.Admin_DestroyVehicle(sid, id)
		net.Start("MG_CarDealer_Admin_DestroyVehicle_C2S")
			net.WriteString(sid)
			net.WriteUInt(id, 32)
		net.SendToServer()
	end
end

if SERVER then
	util.AddNetworkString("MG_CarDealer_UpdateTuneData_C2S")

	function MG_CarDealer.ValidateTuning(tunedata)
		local too_much_list = {}
		for k, v in pairs(tunedata) do
			if k == "Elements" then
				for k, v in pairs(v) do
					local tuners = MG_CarDealer_Tuners[v.Type]
					if tuners then
						too_much_list[tuners.LuaName] = too_much_list[tuners.LuaName] and too_much_list[tuners.LuaName] + 1 or 1
						if too_much_list[tuners.LuaName] > tuners.Max then
							tunedata = {}
							return tunedata
						end
						for k, v in pairs(v.Vars) do
							local vars = tuners.Vars
							if !vars then continue end
							vars = tuners.Vars[k]
							if !vars then continue end
							if vars.Type == "number" then
								if !isnumber(v) or v < vars.Min or v > vars.Max then
									tunedata = {}
									return tunedata
								end
							elseif vars.Type == "color" then
								if !istable(v) or !isnumber(v.r) or !isnumber(v.g) or !isnumber(v.b) or !isnumber(v.a) then
									tunedata = {}
									return tunedata
								end
							elseif vars.Type == "optionselect" then
								local found = false
								for _, option in pairs(vars.Options) do
									if option.Data == v then
										found = true
									end
								end
								if !found then
									tunedata = {}
									return tunedata
								end
							end
						end
					end
				end
			end
		end
		return tunedata
	end

	net.Receive("MG_CarDealer_UpdateTuneData_C2S", function(len, ply)
		local id = net.ReadUInt(32)
		local tunedata = net.ReadTable()
		ply:MG_CarDealer_SendNotice("Tuning abgeschlossen.")
		tunedata = MG_CarDealer.ValidateTuning(tunedata)
		MG_CarDealer_Provider.UpdateTuneData(ply:SteamID(), id, tunedata)
	end)
else
	function MG_CarDealer.UpdateTuneData(id, tunedata)
		net.Start("MG_CarDealer_UpdateTuneData_C2S")
			net.WriteUInt(id, 32)
			net.WriteTable(tunedata)
		net.SendToServer()
	end
end

if SERVER then
	util.AddNetworkString("MG_CarDealer_RepairCar_C2S")

	net.Receive("MG_CarDealer_RepairCar_C2S", function(len, ply)
		ply:MG_CarDealer_Repair(net.ReadUInt(32))
	end)
else
	function MG_CarDealer.RepairCar(id)
		net.Start("MG_CarDealer_RepairCar_C2S")
			net.WriteUInt(id, 32)
		net.SendToServer()
	end
end

if SERVER then
	util.AddNetworkString("MG_CarDealer_RefillCar_C2S")

	net.Receive("MG_CarDealer_RefillCar_C2S", function(len, ply)
		ply:MG_CarDealer_Refill(net.ReadUInt(32))
	end)
else
	function MG_CarDealer.RefillCar(id)
		net.Start("MG_CarDealer_RefillCar_C2S")
			net.WriteUInt(id, 32)
		net.SendToServer()
	end
end

if SERVER then
	util.AddNetworkString("MG_CarDealer_UntowCar_C2S")

	net.Receive("MG_CarDealer_UntowCar_C2S", function(len, ply)
		ply:MG_CarDealer_Untow(net.ReadUInt(32))
	end)
else
	function MG_CarDealer.UntowCar(id)
		net.Start("MG_CarDealer_UntowCar_C2S")
			net.WriteUInt(id, 32)
		net.SendToServer()
	end
end

if SERVER then
	util.AddNetworkString("MG_CarDealer_Admin_RepairCar_C2S")

	net.Receive("MG_CarDealer_Admin_RepairCar_C2S", function(len, ply)
		if !MG_CarDealerConfig:IsSuperAdmin(ply) then return end
		ply:MG_CarDealer_Admin_Repair(net.ReadString(), net.ReadUInt(32))
	end)
else
	function MG_CarDealer.Admin_RepairCar(sid, id)
		net.Start("MG_CarDealer_Admin_RepairCar_C2S")
			net.WriteString(sid)
			net.WriteUInt(id, 32)
		net.SendToServer()
	end
end

if SERVER then
	util.AddNetworkString("MG_CarDealer_Admin_RefillCar_C2S")

	net.Receive("MG_CarDealer_Admin_RefillCar_C2S", function(len, ply)
		if !MG_CarDealerConfig:IsSuperAdmin(ply) then return end
		ply:MG_CarDealer_Admin_Refill(net.ReadString(), net.ReadUInt(32))
	end)
else
	function MG_CarDealer.Admin_RefillCar(sid, id)
		net.Start("MG_CarDealer_Admin_RefillCar_C2S")
			net.WriteString(sid)
			net.WriteUInt(id, 32)
		net.SendToServer()
	end
end

if SERVER then
	util.AddNetworkString("MG_CarDealer_Admin_UntowCar_C2S")

	net.Receive("MG_CarDealer_Admin_UntowCar_C2S", function(len, ply)
		if !MG_CarDealerConfig:IsSuperAdmin(ply) then return end
		ply:MG_CarDealer_Admin_Untow(net.ReadString(), net.ReadUInt(32))
	end)
else
	function MG_CarDealer.Admin_UntowCar(sid, id)
		net.Start("MG_CarDealer_Admin_UntowCar_C2S")
			net.WriteString(sid)
			net.WriteUInt(id, 32)
		net.SendToServer()
	end
end

if SERVER then
	util.AddNetworkString("MG_CarDealer_BuyUpgrade_C2S")

	net.Receive("MG_CarDealer_BuyUpgrade_C2S", function(len, ply)
		ply:MG_CarDealer_BuyUpgrade(net.ReadUInt(32), net.ReadString())
	end)
else
	function MG_CarDealer.BuyUpgrade(id, upgrade)
		net.Start("MG_CarDealer_BuyUpgrade_C2S")
			net.WriteUInt(id, 32)
			net.WriteString(upgrade)
		net.SendToServer()
	end
end

if SERVER then
	util.AddNetworkString("MG_CarDealer_Admin_AddUpgrade_C2S")

	net.Receive("MG_CarDealer_Admin_AddUpgrade_C2S", function(len, ply)
		if !MG_CarDealerConfig:IsSuperAdmin(ply) then return end
		ply:MG_CarDealer_Admin_AddUpgrade(net.ReadString(), net.ReadUInt(32), net.ReadString())
	end)
else
	function MG_CarDealer.Admin_AddUpgrade(sid, id, upgrade)
		net.Start("MG_CarDealer_Admin_AddUpgrade_C2S")
			net.WriteString(sid)
			net.WriteUInt(id, 32)
			net.WriteString(upgrade)
		net.SendToServer()
	end
end

if SERVER then
	util.AddNetworkString("MG_CarDealer_SellUpgrade_C2S")

	net.Receive("MG_CarDealer_SellUpgrade_C2S", function(len, ply)
		ply:MG_CarDealer_SellUpgrade(net.ReadUInt(32), net.ReadString())
	end)
else
	function MG_CarDealer.SellUpgrade(id, upgrade)
		net.Start("MG_CarDealer_SellUpgrade_C2S")
			net.WriteUInt(id, 32)
			net.WriteString(upgrade)
		net.SendToServer()
	end
end

if SERVER then
	util.AddNetworkString("MG_CarDealer_Admin_RemoveUpgrade_C2S")

	net.Receive("MG_CarDealer_Admin_RemoveUpgrade_C2S", function(len, ply)
		if !MG_CarDealerConfig:IsSuperAdmin(ply) then return end
		ply:MG_CarDealer_Admin_RemoveUpgrade(net.ReadString(), net.ReadUInt(32), net.ReadString())
	end)
else
	function MG_CarDealer.Admin_RemoveUpgrade(sid, id, upgrade)
		net.Start("MG_CarDealer_Admin_RemoveUpgrade_C2S")
			net.WriteString(sid)
			net.WriteUInt(id, 32)
			net.WriteString(upgrade)
		net.SendToServer()
	end
end

if SERVER then
	util.AddNetworkString("MG_CarDealer_ChangeUpgrade_C2S")

	net.Receive("MG_CarDealer_ChangeUpgrade_C2S", function(len, ply)
		ply:MG_CarDealer_ChangeUpgrade(net.ReadUInt(32), net.ReadString(), net.ReadBool())
	end)
else
	function MG_CarDealer.ChangeUpgrade(id, upgrade, enabled)
		net.Start("MG_CarDealer_ChangeUpgrade_C2S")
			net.WriteUInt(id, 32)
			net.WriteString(upgrade)
			net.WriteBool(enabled)
		net.SendToServer()
	end
end

if SERVER then
	util.AddNetworkString("MG_CarDealer_Admin_ChangeUpgrade_C2S")

	net.Receive("MG_CarDealer_Admin_ChangeUpgrade_C2S", function(len, ply)
		if !MG_CarDealerConfig:IsSuperAdmin(ply) then return end
		ply:MG_CarDealer_Admin_ChangeUpgrade(net.ReadString(), net.ReadUInt(32), net.ReadString(), net.ReadBool())
	end)
else
	function MG_CarDealer.Admin_ChangeUpgrade(sid, id, upgrade, enabled)
		net.Start("MG_CarDealer_Admin_ChangeUpgrade_C2S")
			net.WriteString(sid)
			net.WriteUInt(id, 32)
			net.WriteString(upgrade)
			net.WriteBool(enabled)
		net.SendToServer()
	end
end