if SERVER then
	CreateConVar("sbox_maxtextscreens", 8)
end

TOOL.Category = "Construction"
TOOL.Name = "Textscreen"

local function ClientColorConvar(name, default)
	TOOL.ClientConVar[name.."_r"] = tostring(default.r)
	TOOL.ClientConVar[name.."_g"] = tostring(default.g)
	TOOL.ClientConVar[name.."_b"] = tostring(default.b)
	TOOL.ClientConVar[name.."_a"] = tostring(default.a)
end

cleanup.Register("textscreens")

TOOL.Information = {
	{name = "left"},
	{name = "right"}
}

if CLIENT then
	language.Add("tool.textscreen.name", "Textscreen")
	language.Add("tool.textscreen.desc", "Ein Bildschirm, der Text darstellen kann!")
	language.Add("tool.textscreen.left", "Textscreen erstellen/aktualisieren")
	language.Add("tool.textscreen.right", "Textscreen-Einstellungen kopieren")
	language.Add("max_textscreens", "Maximale Textscreens")
	language.Add("SBoxLimit_textscreens", "You've hit the Textscreen Limit!")
	language.Add("Cleaned_textscreens", "Cleaned up all Textscreens")
	language.Add("Undone_Textscreen", "Undone Textscreen")
	language.Add("Cleanup_textscreens", "Textscreens")
	language.Add("tool.textscreen.cp_text", "Text")
	language.Add("tool.textscreen.cp_model", "Modell")
	language.Add("tool.textscreen.cp_fonts", "Schriftart")
	language.Add("tool.textscreen.cp_scale", "Textgröße")
	language.Add("tool.textscreen.cp_halign", "Horizontale Ausrichtung")
	language.Add("tool.textscreen.cp_valign", "Vertikale Ausrichtung")
	language.Add("tool.textscreen.cp_color", "Schriftfarbe")
	language.Add("tool.textscreen.cp_color2", "Hintergrundfarbe")
	language.Add("tool.textscreen.cp_freeze", "Einfrieren")
end

TOOL.ClientConVar["text"] = "Kein Text eingestellt."
TOOL.ClientConVar["font"] = "arial"
TOOL.ClientConVar["model"] = "models/hunter/plates/plate1x1.mdl"
TOOL.ClientConVar["scale"] = 1
TOOL.ClientConVar["valign"] = 1
TOOL.ClientConVar["halign"] = 1
TOOL.ClientConVar["freeze"] = 1

ClientColorConvar("fg", color_white)
ClientColorConvar("bg", color_black)

local function IsValidTextscreenModel(model)
	local modellower = model:lower()
	for mdl in pairs(list.Get("TextScreenModels")) do
		if (mdl:lower() == modellower) then return true end
	end
	return false
end

function TOOL:GetClientColor(name)
	local r = self:GetClientNumber(name.."_r")
	local g = self:GetClientNumber(name.."_g")
	local b = self:GetClientNumber(name.."_b")
	local a = self:GetClientNumber(name.."_a")
	return Color(r, g, b, a)
end

function TOOL:FindAngle(trace, model)
	local ang
	if math.abs(trace.HitNormal.x) < 0.001 and math.abs(trace.HitNormal.y) < 0.001 then
		ang = Vector(0, 0, trace.HitNormal.z):Angle()
	else
		ang = trace.HitNormal:Angle()
	end
	local mdl = list.Get("TextScreenModels")[model]
	if mdl and mdl.ang then
		mdl, ang = LocalToWorld(Vector(), mdl.ang, Vector(), ang)
	end
	if string.find(model, "hunter") then
		mdl, ang = LocalToWorld(Vector(), Angle(0, 90, 90), Vector(), ang)
	else
		mdl, ang = LocalToWorld(Vector(), Angle(-90, -90, 0), Vector(), ang)
	end
	return ang
end

function TOOL:FixupPosition(trace, ent)
	local pos = ent:GetPos()
	local near_point = ent:NearestPoint(pos - (trace.HitNormal * 512))
	ent:SetPos(trace.HitPos + pos - near_point)
end

function TOOL:LeftClick(trace)
	local ent = trace.Entity
	if IsValid(ent) and ent:IsPlayer() then return false end
	if CLIENT then return true end
	local ply = self:GetOwner()
	local pos = trace.HitPos + trace.HitNormal
	local model = self:GetClientInfo("model")
	local font = self:GetClientInfo("font")
	local text = string.gsub(self:GetClientInfo("text"), "\\n", "\n")
	local scale = math.Clamp(self:GetClientNumber("scale"), 0.25, 1)
	local halign = math.Clamp(self:GetClientNumber("halign"), 0, 2) / 2
	local valign = math.Clamp(self:GetClientNumber("valign"), 0, 2) / 2
	local fgcolor = self:GetClientColor("fg")
	local bgcolor = self:GetClientColor("bg")
	local freeze = self:GetClientNumber("freeze") > 0
	if IsValid(ent) and ent:GetClass() == "textscreen" then
		ent:SetFont(font)
		ent:SetText(text)
		ent:SetTextScale(scale)
		ent:SetTextColor(fgcolor)
		ent:SetBackgroundColor(bgcolor)
		ent:SetAlign(halign, valign)
		ent:SendUpdate()
		return true
	end
	if !util.IsValidModel(model) or !util.IsValidProp(model) or !IsValidTextscreenModel(model) then return false end
	if !self:GetSWEP():CheckLimit("textscreens") then return false end
	local ang = self:FindAngle(trace, model)
	local newent = MakeTextScreen(ply, model, text, font, scale, fgcolor, bgcolor, valign, halign, {Pos = trace.HitPos, Angle = ang})
	if freeze then
		local phys = newent:GetPhysicsObject()
		if IsValid(phys) then
			phys:EnableMotion(false)
		end
	end
	self:FixupPosition(trace, newent)
	undo.Create("Textscreen")
		undo.AddEntity(newent)
		undo.SetPlayer(self:GetOwner())
	undo.Finish()
	ply:AddCount("textscreens", newent)
	ply:AddCleanup("textscreens", newent)
	DoPropSpawnedEffect(newent)
	return true
end

function TOOL:RightClick(trace)
	local ent = trace.Entity
	if !IsValid(ent) or ent:IsPlayer() then return false end
	if ent:GetClass() != "textscreen" then return false end
	if CLIENT then return true end
	local ply = self:GetOwner()
	ply:ConCommand("textscreen_model "..ent:GetModel())
	ply:ConCommand("textscreen_text "..string.gsub(ent.text, "\n", "\\n"))
	ply:ConCommand("textscreen_scale "..ent.scale)
	ply:ConCommand("textscreen_halign "..math.Clamp(ent.halign, 0, 2) * 2)
	ply:ConCommand("textscreen_valign "..math.Clamp(ent.valign, 0, 2) * 2)
	ply:ConCommand("textscreen_font "..ent.font)
	ply:ConCommand("textscreen_fg_r "..ent.fgcolor.r)
	ply:ConCommand("textscreen_fg_g "..ent.fgcolor.g)
	ply:ConCommand("textscreen_fg_b "..ent.fgcolor.b)
	ply:ConCommand("textscreen_fg_a "..ent.fgcolor.a)
	ply:ConCommand("textscreen_bg_r "..ent.bgcolor.r)
	ply:ConCommand("textscreen_bg_g "..ent.bgcolor.g)
	ply:ConCommand("textscreen_bg_b "..ent.bgcolor.b)
	ply:ConCommand("textscreen_bg_a "..ent.bgcolor.a)
	return true
end

function TOOL:UpdateGhost(ent, owner)
	if !IsValid(ent) then return end
	local trdata =  util.GetPlayerTrace(owner)
	local trace = util.TraceLine(trdata)
	if !trace.Hit then return end
	if trace.Entity:IsPlayer() or trace.Entity:GetClass() == "textscreen" then
		ent:SetNoDraw(true)
		return
	end
	ent:SetPos(trace.HitPos)
	ent:SetAngles(self:FindAngle(trace, self:GetClientInfo("model")))
	self:FixupPosition(trace, ent)
	ent:SetNoDraw(false)
end

function TOOL:Think()
	local mdl = self:GetClientInfo( "model" )
	if !IsValidTextscreenModel(mdl) then self:ReleaseGhostEntity() return end
	if (!IsValid(self.GhostEntity) or self.GhostEntity:GetModel() != mdl) then
		self:MakeGhostEntity(mdl, Vector(0, 0, 0), Angle(0, 0, 0))
	end
	self:UpdateGhost(self.GhostEntity, self:GetOwner())
end

if SERVER then
	function MakeTextScreen(ply, model, text, font, scale, fgcolor, bgcolor, valign, halign, Data)
		if IsValid(ply) and !ply:CheckLimit("textscreens") then return false end
		local ent = ents.Create("textscreen")
		if !IsValid(ent) then return false end
		ent.model = model
		ent:SetText(text)
		ent:SetFont(font)
		ent:SetTextColor(fgcolor)
		ent:SetBackgroundColor(bgcolor)
		ent:SetAlign(halign, valign)
		ent:SetTextScale(scale)
		duplicator.DoGeneric(ent, Data)
		ent:SetCollisionGroup(COLLISION_GROUP_WORLD)
		ent:Spawn()
		ent:Activate()
		duplicator.DoGenericPhysics(ent, ply, Data)
		return ent
	end
end

local gmod_fonts = {
	["DebugFixed"] = true,
	["DebugFixedSmall"] = true,
	["Default"] = true,
	["DermaDefault"] = true,
	["DermaDefaultBold"] = true,
	["DermaLarge"] = true,
	["Default"] = true,
	["Trebuchet18"] = true,
	["Trebuchet24"] = true,
	["HudHintTextLarge"] = true,
	["HudHintTextSmall"] = true,
	["CenterPrintText"] = true,
	["HudSelectionText"] = true,
	["CloseCaption_Normal"] = true,
	["CloseCaption_Bold"] = true,
	["CloseCaption_BoldItalic"] = true,
	["TargetID"] = true,
	["TargetIDSmall"] = true,
	["HudNumbers"] = true,
	["BudgetLabel"] = true,
	["GModNotify"] = true
}

if CLIENT then
	local ConVarsDefault = TOOL:BuildConVarList()
	function TOOL:BuildCPanel()
		self:AddControl("Header", {Description = "#tool.textscreen.desc"})
		self:AddControl("ComboBox", {
			MenuButton = 1,
			Folder = "textscreen",
			Options = {["#preset.default"] = ConVarsDefault},
			CVars = table.GetKeys(ConVarsDefault)
		})
		local modellist = {}
		for k in pairs(list.Get("TextScreenModels")) do
			modellist[k] = {}
		end
		self:AddControl("PropSelect", {
			Label = "#tool.textscreen.cp_model", 
			ConVar = "textscreen_model", 
			Height = 2, 
			Models = modellist
		})
		local tb = self:AddControl("TextBox",{
			Label = "#tool.textscreen.cp_text"
		})
		tb:SetTall(64)
		tb:SetMultiline(true)
		tb:SetWrap(true)
		local cvar_text = GetConVar("textscreen_text")
		tb:SetText(string.gsub(cvar_text:GetString(), "\\n", "\n"))
		local old_slf = tb.OnLoseFocus
		function tb:OnLoseFocus(...)
			local text = string.gsub(self:GetText(),"\n","\\n")
			if cvar_text:GetString() != text then
				LocalPlayer():ConCommand(string.format("textscreen_text \"%s\"",text))
			end
			old_slf(self, ...)
		end
		cvars.AddChangeCallback("textscreen_text", function(_, old, new)
			local text = string.gsub(new, "\\n", "\n") or ""
			if IsValid(tb) and tb:GetText() != text then
				tb:SetText(text)
			end
		end, "UpdateGUI")
		local fonts = {}
		for _, v in pairs(list.Get("TextScreenFonts")) do
			fonts[string.lower(v)] = v
		end
		local combobox = self:AddControl("ComboBox", {
			Label = "#tool.textscreen.cp_fonts"
		})

		local sel_font = fonts[string.lower(GetConVar("textscreen_font"):GetString())]
		if sel_font then
			combobox:SetValue(string.Replace(sel_font, "TextScreen_", ""))
		end
		function combobox:OpenMenu()
			if IsValid(self.Menu) then
				self.Menu:Remove()
				self.Menu = nil
			end
			self.Menu = DermaMenu(false, self)
			self.GModFonts = self.Menu:AddSubMenu("Garry's Mod")
			self.OtherFonts = self.Menu:AddSubMenu("Modern Gaming")
			self.OtherFontsBig = self.Menu:AddSubMenu("Modern Gaming (Groß)")
			for _, v in SortedPairsByValue(fonts) do
				if !gmod_fonts[v] then continue end
				self.GModFonts:AddOption(v, function()
					self:SetValue(v)
					RunConsoleCommand("textscreen_font", v)
				end)
			end
			for _, v in SortedPairsByValue(fonts) do
				if gmod_fonts[v] or string.find(v, "_Big") then continue end
				local text = string.Replace(v, "TextScreen_", "")
				self.OtherFonts:AddOption(text, function()
					self:SetValue(text)
					RunConsoleCommand("textscreen_font", v)
				end)
			end
			for _, v in SortedPairsByValue(fonts) do
				if gmod_fonts[v] or !string.find(v, "_Big") then continue end
				local text = string.Replace(v, "TextScreen_", "")
				text = string.Replace(text, "_Big", "")
				self.OtherFontsBig:AddOption(text, function()
					self:SetValue(string.Replace(v, "TextScreen_", ""))
					RunConsoleCommand("textscreen_font", v)
				end)
			end
			local x, y = self:LocalToScreen(0, self:GetTall())
			self.Menu:SetMinimumWidth(self:GetWide())
			self.Menu:Open(x, y, false, self)
		end

		self:AddControl("Slider", {
			Label = "#tool.textscreen.cp_scale",
			Command = "textscreen_scale",
			Type = "Float",
			Min = 0.25,
			Max = 1
		})
		self:AddControl("Slider", {
			Label = "#tool.textscreen.cp_halign",
			Command = "textscreen_halign",
			Type = "Int",
			Min = 0,
			Max = 2
		})
		self:AddControl("Slider", {
			Label = "#tool.textscreen.cp_valign",
			Command = "textscreen_valign",
			Type = "Int",
			Min = 0,
			Max = 2
		})
		self:AddControl("Color", {
			Label = "#tool.textscreen.cp_color",
			Red =   "textscreen_fg_r",
			Green = "textscreen_fg_g",
			Blue =  "textscreen_fg_b",
			Alpha = "textscreen_fg_a"
		})
		self:AddControl("Color", {
			Label = "#tool.textscreen.cp_color2",
			Red =   "textscreen_bg_r",
			Green = "textscreen_bg_g",
			Blue =  "textscreen_bg_b",
			Alpha = "textscreen_bg_a"
		})
		self:AddControl("CheckBox", {
			Label = "#tool.textscreen.cp_freeze",
			Command = "textscreen_freeze",
		})
	end
end

for k in pairs(gmod_fonts) do
	list.Add("TextScreenFonts", k)
end

local function AddBigFont(name, tbl)
	if !tbl.size then return end
	local new_tbl = table.Copy(tbl)
	name = "TextScreen_"..name.."_Big"
	tbl.size = tbl.size * 1.5
	if CLIENT then
		surface.CreateFont(name, tbl)
	end
	list.Add("TextScreenFonts", name)
end

local function AddCustomFont(name, tbl, big)
	name = "TextScreen_"..name
	if CLIENT then
		surface.CreateFont(name, tbl)
	end
	list.Add("TextScreenFonts", name)
	if big then
		AddBigFont(name, tbl)
	end
end

AddCustomFont("Arial", {
	font = "Arial",
	size = 32,
	weight = 500,
	blursize = 0,
	scanlines = 0,
	antialias = true
}, true)

AddCustomFont("Akbar", {
	font = "akbar",
	size = 32,
	weight = 500,
	blursize = 0,
	scanlines = 0,
	antialias = true
}, true)

AddCustomFont("Roboto", {
	font = "Roboto",
	size = 32,
	weight = 500,
	blursize = 0,
	scanlines = 0,
	antialias = true
}, true)

AddCustomFont("Roboto Condensed", {
	font = "Roboto Cn",
	size = 32,
	weight = 500,
	blursize = 0,
	scanlines = 0,
	antialias = true
}, true)

AddCustomFont("Roboto Thin", {
	font = "Roboto Th",
	size = 32,
	weight = 500,
	blursize = 0,
	scanlines = 0,
	antialias = true
}, true)

AddCustomFont("Tahoma", {
	font = "Tahoma",
	size = 32,
	weight = 500,
	blursize = 0,
	scanlines = 0,
	antialias = true
}, true)

AddCustomFont("Verdana", {
	font = "Verdana",
	size = 32,
	weight = 500,
	blursize = 0,
	scanlines = 0,
	antialias = true
}, true)

AddCustomFont("Trebuchet MS", {
	font = "Trebuchet MS",
	size = 32,
	weight = 500,
	blursize = 0,
	scanlines = 0,
	antialias = true
}, true)

AddCustomFont("Courier New", {
	font = "Courier New",
	size = 32,
	weight = 500,
	blursize = 0,
	scanlines = 0,
	antialias = true
}, true)

AddCustomFont("Times New Roman", {
	font = "Times New Roman",
	size = 32,
	weight = 500,
	blursize = 0,
	scanlines = 0,
	antialias = true
}, true)

AddCustomFont("Lucida Console", {
	font = "Lucida Console",
	size = 32,
	weight = 500,
	blursize = 0,
	scanlines = 0,
	antialias = true
}, true)

AddCustomFont("Coolvetica", {
	font = "coolvetica",
	size = 32,
	weight = 500,
	blursize = 0,
	scanlines = 0,
	antialias = true
}, true)

AddCustomFont("Bebas Neue", {
	font = "BebasNeue",
	size = 32,
	weight = 500,
	blursize = 0,
	scanlines = 0,
	antialias = true
}, true)

AddCustomFont("Open Sans Condensed", {
	font = "Open Sans Condensed",
	size = 32,
	weight = 500,
	blursize = 0,
	scanlines = 0,
	antialias = true
}, true)

AddCustomFont("Open Sans", {
	font = "Open Sans",
	size = 32,
	weight = 500,
	blursize = 0,
	scanlines = 0,
	antialias = true
}, true)

AddCustomFont("Prototype", {
	font = "Prototype",
	size = 32,
	weight = 500,
	blursize = 0,
	scanlines = 0,
	antialias = true
}, true)

timer.Simple(0, function()
	if DarkRP then
		AddCustomFont("Nimbus San PCon", {
			font = "NimbusSanPCon",
			size = 32,
			weight = 500,
			blursize = 0,
			scanlines = 0,
			antialias = true
		}, true)

		AddCustomFont("New X Digital", {
			font = "New X Digital tfb Light",
			size = 32,
			weight = 500,
			blursize = 0,
			scanlines = 0,
			antialias = true
		}, true)

		AddCustomFont("Copasetic", {
			font = "Copasetic",
			size = 32,
			weight = 500,
			blursize = 0,
			scanlines = 0,
			antialias = true
		}, true)

		AddCustomFont("Century Gothic", {
			font = "Century Gothic",
			size = 32,
			weight = 500,
			blursize = 0,
			scanlines = 0,
			antialias = true
		}, true)

		AddCustomFont("Montserrat", {
			font = "Montserrat",
			size = 32,
			weight = 500,
			blursize = 0,
			scanlines = 0,
			antialias = true
		}, true)

		AddCustomFont("Orbitron", {
			font = "Orbitron",
			size = 32,
			weight = 500,
			blursize = 0,
			scanlines = 0,
			antialias = true
		}, true)

		AddCustomFont("Subway Ticker Grid", {
			font = "Subway Ticker Grid",
			size = 32,
			weight = 500,
			blursize = 0,
			scanlines = 0,
			antialias = true
		}, true)
	elseif PVP then
		AddCustomFont("Nexa Bold", {
			font = "Nexa Bold",
			size = 32,
			weight = 500,
			blursize = 0,
			scanlines = 0,
			antialias = true
		}, true)

		AddCustomFont("Aero Matics Display", {
			font = "Aero Matics Display",
			size = 32,
			weight = 500,
			blursize = 0,
			scanlines = 0,
			antialias = true
		}, true)
	end
end)

list.Set("TextScreenModels", "models/blacknecro/tv_plasma_4_3.mdl", {
	pos = Vector(0.3, 0.05, 0),
	ang = Angle(0, 90, 90),
	scale = Vector(28, 21.5, 1)
})
list.Set("TextScreenModels", "models/cheeze/pcb/pcb4.mdl", {
	pos = Vector(0, 0, 0.5),
	ang = Angle(0, -90, 0),
	scale = Vector(16, 16, 1)
})
list.Set("TextScreenModels", "models/cheeze/pcb/pcb5.mdl", {
	pos = Vector(0, -0.5, 0.5),
	ang = Angle(0, -90, 0),
	scale = Vector(31.5, 16, 1)
})
list.Set("TextScreenModels", "models/cheeze/pcb/pcb6.mdl", {
	pos = Vector(8, -0.5, 0.5),
	ang = Angle(0, -90, 0),
	scale = Vector(31.5, 24, 1)
})
list.Set("TextScreenModels", "models/cheeze/pcb/pcb7.mdl", {
	pos = Vector(0, 0, 0.5),
	ang = Angle(0,-90,0),
	scale = Vector(31.7, 32, 1)
})
list.Set("TextScreenModels", "models/cheeze/pcb2/pcb8.mdl", {
	pos = Vector(0, 0, 0.5),
	ang = Angle(0, -90, 0),
	scale = Vector(64, 64, 1)
})
list.Set("TextScreenModels", "models/hunter/plates/plate025x025.mdl", {
	pos = Vector(0, 0, 1.7),
	ang = Angle(),
	scale = Vector(5.4, 5.4, 1)
})
list.Set("TextScreenModels", "models/hunter/plates/plate1x1.mdl", {
	pos = Vector(0, 0, 1.7),
	ang = Angle(),
	scale = Vector(22.5, 22.5, 1)
})
list.Set("TextScreenModels", "models/hunter/plates/plate05x05.mdl", {
	pos = Vector(0, 0, 1.7),
	ang = Angle(),
	scale = Vector(11, 11, 1)
})
list.Set("TextScreenModels", "models/hunter/plates/plate2x2.mdl", {
	pos = Vector(0, 0, 1.7),
	ang = Angle(),
	scale = Vector(46, 46, 1)
})
list.Set("TextScreenModels", "models/hunter/plates/plate3x3.mdl", {
	pos = Vector(0, 0, 1.8),
	ang = Angle(),
	scale = Vector(69.5, 69.5, 1)
})
list.Set("TextScreenModels", "models/hunter/plates/plate4x4.mdl", {
	pos = Vector(0, 0, 1.9),
	ang = Angle(),
	scale = Vector(93, 93, 1)
})
list.Set("TextScreenModels","models/kobilica/wiremonitorsmall.mdl", {
	pos = Vector(0.53, 0.01, 5.023),
	ang = Angle(0, 90, 90),
	scale = Vector(4.2, 4.2, 1)
})
list.Set("TextScreenModels","models/kobilica/wiremonitorbig.mdl", {
	pos = Vector(0.53, 0.01, 13),
	ang = Angle(0, 90, 90),
	scale = Vector(11.3, 11.3, 1)
})
list.Set("TextScreenModels", "models/props/cs_assault/billboard.mdl", {
	pos = Vector(1.03, 0, 0.2),
	ang = Angle(0, 90, 90),
	scale = Vector(110.6, 57.3, 1)
})
list.Set("TextScreenModels", "models/props/cs_office/computer_monitor.mdl", {
	pos = Vector(3.3, 0, 16.8),
	ang = Angle(0, 90, 90),
	scale = Vector(10.4, 8, 1)
})
list.Set("TextScreenModels", "models/props/cs_office/tv_plasma.mdl", {
	pos = Vector(6.52, 0.18, 18.8),
	ang = Angle(0, 90, 90),
	scale = Vector(28.4, 16.8, 1)
})
list.Set("TextScreenModels", "models/props_lab/monitor01b.mdl", {
	pos = Vector(6.4, -1, 0.5),
	ang = Angle(0, 90, 90),
	scale = Vector(4.6, 4.6, 1)
})