include("shared.lua")
include("sh_config.lua")

local use_font = system.IsWindows() and "Tahoma" or "Verdana"
surface.CreateFont("Terminal_Close", {
	font = use_font,
	size = 13,
	weight = 1000
})

local performance_mode = CreateClientConVar("cl_terminal_performance_mode", 0, FCVAR_ARCHIVE)

local cam_start_2d = cam.Start2D
local cam_start_3d = cam.Start3D2D
local cam_end_2d = cam.End2D
local cam_end_3d = cam.End3D2D
local surface = surface
local draw_rect = surface.DrawRect
local draw_outlined_rect = surface.DrawOutlinedRect
local draw_textured_rect = surface.DrawTexturedRectUV
local draw_circle = surface.DrawCircle
local draw_mat = surface.SetMaterial
local set_color = surface.SetDrawColor
local draw = draw
local draw_stext = draw.SimpleText
local draw_stext_out = draw.SimpleTextOutlined
local render = render
local push_render_target = render.PushRenderTarget
local pop_render_target = render.PopRenderTarget
local clear_depth = render.ClearDepth
local clear = render.Clear
local render_view = render.RenderView
local random = math.random

local mat = CreateMaterial("protect_terminal_viewmat", "UnlitGeneric", {})
local view_width, view_height = 512, 300
local rts = {}
local inrt

local function AddListSpacer(list, height, vmargins, color)
	vmargins = vmargins or 0
	local spacer = vgui.Create("DPanel", list)
	spacer:SetTall(height + (vmargins * 2))
	if color then
		spacer.Paint = function(self, w, h)
			set_color(color)
			draw_rect(0, vmargins, w, height)
		end
	else
		spacer.Paint = nil
	end
	list:Add(spacer)
end

local terminal_frame
net.Receive("protect_terminal_settings", function(len)
	if IsValid(terminal_frame) then return end
	local ent = net.ReadEntity()
	if !IsValid(ent) then return end
	local ply = LocalPlayer()
	local owner = ent:Getowning_ent()
	local is_owner = ply == owner
	local non_owner_edit = false
	local feed
	if is_owner then
		non_owner_edit = net.ReadBool()
	end
	terminal_frame = vgui.Create("DFrame")
	terminal_frame:ShowCloseButton(false)
	terminal_frame:SetTitle("Terminal-Einstellungen")
	terminal_frame:SetSize(256, 190)
	terminal_frame:Center()
	terminal_frame:MakePopup()
	terminal_frame:ParentToHUD()
	terminal_frame.Think = function(slf)
		if !IsValid(ent) or !ply:Alive() or ply:EyePos():DistToSqr(ent:GetPos()) > 40000 then
			terminal_frame:Close()
		end
	end
	local Close = vgui.Create("DButton", terminal_frame)
	Close:SetSize(50, 20)
	Close:SetPos(terminal_frame:GetWide() - 52, 2)
	Close:SetText("X")
	Close:SetFont("Terminal_Close")
	Close:SetTextColor(color_white)
	Close.Paint = function(self, w, h)
		local col
		if self:IsHovered() then
			col = Color(255, 100, 100)
		else
			col = Color(200, 50, 50)
		end
		draw.RoundedBox(4, 0, 0, w, h, col)
	end
	Close.DoClick = function()
		surface.PlaySound("ui/buttonclick.wav")
		terminal_frame:Remove()
	end
	local scroll = vgui.Create("DScrollPanel", terminal_frame)
	scroll:SetPadding(5)
	scroll:SetPos(5, 30)
	scroll:SetSize(terminal_frame:GetWide() - 10, terminal_frame:GetTall() - 35)
	local list = vgui.Create("DListLayout", scroll)
	scroll.OldPerformLayout = scroll.PerformLayout
	scroll.PerformLayout = function(...)
		list:SetWide(scroll:InnerWidth() - (scroll:GetVBar():IsVisible() and 2 or 0))
		scroll.OldPerformLayout(...)
	end
	local allow_edit
	if is_owner then
		allow_edit = vgui.Create("DCheckBoxLabel", list)
		allow_edit:SetText("Bearbeitung durch andere erlauben")
		allow_edit:SetChecked(non_owner_edit)
		allow_edit:SizeToContents()
		list:Add(allow_edit)
		AddListSpacer(list, 2, 4, Color(255, 255, 255, 100))
	end
	local cam_list = vgui.Create("DLabel", list)
	cam_list:SetText("Verfügbare Kameras")
	cam_list:SizeToContents()
	list:Add(cam_list)
	local cams = {}
	for _, cam in ipairs(ents.FindByClass("protect_camera")) do
		if IsValid(cam:Getowning_ent()) and cam:Getowning_ent() == owner then
			table.insert(cams, cam)
		end
	end
	table.sort(cams, function(c1, c2)
		local c1n = c1:GetDeviceName()
		local c2n = c2:GetDeviceName()
		return (#c1n < #c2n) or ((#c1n == #c2n) and (c1n < c2n))
	end)
	for _,cam in ipairs(cams) do
		AddListSpacer(list, 4, 0)
		local pnl = vgui.Create("DPanel")
		pnl:SetTall(35)
		pnl.Paint = function(self, w, h)
			set_color(75, 75, 75, 255)
			draw_rect(0, 0, w, h)
		end
		local device_name = vgui.Create("DLabel", pnl)
		device_name:SetText(cam:GetDeviceName())
		device_name:SizeToContents()
		local feed_set = vgui.Create("DButton", pnl)
		feed_set:SetText("Feed setzen")
		feed_set:SetSize(75, 20)
		feed_set.DoClick = function()
			feed = cam
			terminal_frame:Remove()
		end
		pnl.PerformLayout = function()
			device_name:CenterVertical(0.5)
			device_name:AlignLeft(5)
			feed_set:CenterVertical(0.5)
			feed_set:AlignRight(5)
		end
		list:Add(pnl)
	end
	terminal_frame.OnRemove = function()
		if !IsValid(ent) or !feed and (!is_owner or non_owner_edit == allow_edit:GetChecked()) then return end
		net.Start("protect_terminal_settings")
			net.WriteEntity(ent)
			if is_owner then
				net.WriteBool(allow_edit:GetChecked())
			end
			net.WriteBool(feed != nil)
			if feed then
				net.WriteEntity(feed)
			end
		net.SendToServer()
	end
end)

local local_ply
hook.Add("PreRender", "protect_terminal_drawrts", function()
	if inrt then return end
	for _,term in pairs(DarkRP_Terminals) do
		local_ply = local_ply or LocalPlayer()
		if (IsValid(term) and term.CanDraw and term.NeedsRT and local_ply:EyePos():DistToSqr(term:GetPos()) <= term.DrawDistance) then
			if performance_mode:GetBool() then
				if local_ply:GetEyeTrace().Entity != term then
					return
				end
			end
			term.CanDraw = nil
			inrt = true
			local rtdata = rts[term]
			if !rtdata then
				rts[term] = rtdata or GetRenderTarget("protect_termview_"..term:EntIndex(), 512, 512)
			end
			term:RenderToRT(rts[term])
			inrt = nil
		end
	end
end)

hook.Add("ShouldDrawLocalPlayer", "protect_terminal_nodrawlp", function()
	if inrt then return true end 
end)

local veh, product
local function IsInFront(local_ply, pos, shoot_pos, direction)
	veh = local_ply:GetVehicle()
	if IsValid(veh) then
		veh = veh:GetThirdPersonMode()
		if veh then
			return true
		end
	end
	product = (pos.x - shoot_pos.x) * direction.x + (pos.y - shoot_pos.y) * direction.y + (pos.z - shoot_pos.z) * direction.z
	return product < 0
end

local scale = 0.109
local vector_static = Vector(6.1, -27.9, 35.3)
local angle_static = Angle(0, 90, 90)
local pos, ang, rt
local color_red = Color(255, 0, 0, 255)
function ENT:Draw()
	self:DrawModel()
	local_ply = local_ply or LocalPlayer()
	if performance_mode:GetBool() then
		if local_ply:GetEyeTrace().Entity != self then
			return
		end
	end
	pos = self:GetPos()
	ang = self:LocalToWorldAngles(angle_static)
	if !IsInFront(local_ply, pos, local_ply:GetShootPos(), ang:Up()) then return end
	local pos = self:LocalToWorld(vector_static)
	if local_ply:EyePos():DistToSqr(pos) > self.DrawDistance then 
		cam_start_3d(pos, ang, scale)
			set_color(0, 0, 0)
			draw_rect(0, 0, view_width, view_height)
		cam_end_3d()
		return
	end
	self.CanDraw = true
	local feed = self:GetCamera()
	rt = self.rt
	cam_start_3d(pos, ang, scale)
		if self.NeedsRT and rt then
			mat:SetTexture("$basetexture", rt)
			set_color(color_white)
			draw_mat(mat)
			draw_textured_rect(0, 0, view_width, view_height, 0, 0, math.min(view_width / rt:GetMappingWidth(), 1), math.min(view_height / rt:GetMappingHeight(), 1))
		else
			set_color(0, 0, 0)
			draw_rect(0, 0, view_width, view_height)
			draw_stext((IsValid(feed) and !feed:GetNoDraw() and feed.Damageable and feed:Health() <= 0) and "Kein Signal!" or "Kein Feed!", "mg_instructions", view_width / 2, view_height / 2, color_red, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
		end
		self.NeedsRT = IsValid(feed) and !feed:GetNoDraw() and (!feed.Damageable or feed:Health() > 0)
	cam_end_3d()
end

local x, y, x1, xh, w, h
local yl, yh = 2, 6
local xl, xh = 2, 12
function ENT:DrawStatic(alpha)
	if alpha <= 0 then return end
	x, y = 0, 0
	set_color(0, 0, 0, alpha)
	draw_rect(0, 0, view_width, view_height)
	set_color(150, 150, 150, alpha)
	while y < view_height do
		h = random(yl, yh)
		h = (h <= (view_height - y)) and h or (view_height - y)
		while x < view_width do
			w = random(xl, xh)
			w = (w <= (view_width - x)) and w or (view_width - x)
			if (w % 2) == 0 then
				draw_rect(x, y, w, h)
			end
			x = x + w
		end
		x = 0
		y = y + h
	end
end

local view_render = {
	x = 0,
	y = 0,
	dopostprocess = false,
	drawhud = false,
	drawmonitors = false,
	drawviewmodel = false
}

local vector_static = Vector(5, 0, 0)
local angle_static = Angle(0, 0, 0)
function ENT:RenderToRT(rt)
	local tb = self:GetTable()
	local rate = tb.FrameRate
	if rate == 0 or (SysTime() - (tb.LastUpdate or 0)) >= (1 / rate) then
		local feed = self:GetCamera()
		if !IsValid(feed) or feed:GetNoDraw() then return end
		local salpha = 0
		if feed.Damageable then
			local hfrac = math.Clamp(feed:Health() / feed:GetMaxHealth(), 0, 1)
			local threshold = 0.5
			if hfrac < threshold then
				salpha = math.sin(((threshold - hfrac) / threshold) * (math.pi / 2)) * 0.5
				salpha = salpha * 255
			end
		end
		push_render_target(rt, 0, 0, view_width, view_height)
		clear_depth()
		clear(0, 0, 0, 0)
		cam_start_2d()
			view_render["origin"] = feed:LocalToWorld(vector_static)
			view_render["angles"] = feed:LocalToWorldAngles(angle_static)
			view_render["w"] = view_width
			view_render["h"] = view_height
			view_render["fov"] = tb.FOV
			render_view(view_render)
			self:DrawStatic(salpha)
			set_color(color_white)
			draw_outlined_rect(view_width / 4, view_height / 4, view_width / 2, view_height / 2)
			draw_circle(view_width / 2, view_height / 2, view_height / 24, color_white)
			draw_stext("REC", "mg_instructions", view_width - 10, 5, Color(255, 0, 0, 255), TEXT_ALIGN_RIGHT, TEXT_ALIGN_TOP)
			draw_stext_out(feed:GetDeviceName(), "mg_instructions", 10, 5, color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP, 1, color_black)
		cam_end_2d()
		pop_render_target()
		tb.rt = rt
		tb.LastUpdate = SysTime()
	end
end

function ENT:GetTip()
end