if SERVER then
	AddCSLuaFile()
end

SWEP.Base = "weapon_base"

SWEP.Category = "Fesseln"
SWEP.Instructions = ""
SWEP.DrawCrosshair = false
SWEP.DrawWeaponInfoBox = false

SWEP.Spawnable = false

SWEP.Slot = 100
SWEP.PrintName = "Gefesselt!"

SWEP.ViewModelFOV = 60
SWEP.ViewModel = Model("models/weapons/c_arms_citizen.mdl")
SWEP.WorldModel = Model("models/weapons/w_toolgun.mdl")
SWEP.UseHands = true

SWEP.Primary.Recoil = 1
SWEP.Primary.Damage = 0
SWEP.Primary.NumShots = 1
SWEP.Primary.Cone = 0
SWEP.Primary.Delay = 1

SWEP.Primary.ClipSize = -1
SWEP.Primary.DefaultClip = -1
SWEP.Primary.Automatic = false
SWEP.Primary.Ammo = "none"

SWEP.Secondary.ClipSize = -1
SWEP.Secondary.DefaultClip = -1
SWEP.Secondary.Automatic = false
SWEP.Secondary.Ammo = "none"

SWEP.DeploySpeed = 1.5

SWEP.PrimaryAnim = ACT_VM_PRIMARYATTACK
SWEP.ReloadAnim = ACT_VM_RELOAD
SWEP.HoldType = "duel"

SWEP.IsHandcuffs = true

function SWEP:SetupDataTables()
	self:NetworkVar("Entity", 0, "FriendBreaking")
	self:NetworkVar("Entity", 1, "Kidnapper")
	self:NetworkVar("Float", 0, "CuffBroken")
	self:NetworkVar("Float", 1, "CuffStrength")
	self:NetworkVar("Float", 2, "CuffRegen")
	self:NetworkVar("Float", 3, "RopeLength")
	self:NetworkVar("String", 0, "RopeMaterial")
	self:NetworkVar("String", 1, "CuffMaterial")
	self:NetworkVar("Bool", 0, "CanGag")
	self:NetworkVar("Bool", 1, "IsGagged")
	self:NetworkVar("Bool", 2, "CanBlind")
	self:NetworkVar("Bool", 3, "IsBlind")
	self:NetworkVar("Bool", 4, "DragRestricted")
	self:NetworkVar("Bool", 5, "IsCollar")
end

function SWEP:PreDrawViewModel()
	if self:GetIsCollar() then
		return true
	end
end

function SWEP:Initialize()
	timer.Simple(0, function()
		if !IsValid(self) or !IsValid(self.Owner) then return end
		local ply = self.Owner
		ply:SetNW2Entity("CuffEntity", self)
		if CLIENT and ply == LocalPlayer() then
			hook.Add("RenderScreenspaceEffects", self, self.RenderScreenSpaceEffects)
		end
	end)
	if self:GetCuffStrength() <= 0 then
		self:SetCuffStrength(1)
	end
	if self:GetCuffRegen() <= 0 then
		self:SetCuffRegen(1)
	end
	self:SetCuffBroken(0)
	self:SetHoldType(self.HoldType)
	self:DrawShadow(false)
end

hook.Add("PlayerHurt", "Cuffs_PreventUncuffing", function(ply, att, rem, dmg)
	if dmg <= 3 then return end
	ply.Cuffs_WasHit = CurTime() + 1
end)

function SWEP:PrimaryAttack()
	if SERVER and !IsValid(self:GetFriendBreaking()) then
		if (self.Owner.Cuffs_WasHit or 0) > CurTime() then return end
		self:AttemptBreak()
	end
end

function SWEP:SecondaryAttack()
end

function SWEP:Reload()
end

function SWEP:Deploy()
	local vm = self.Owner:GetViewModel()
	if IsValid(vm) then
		vm:SendViewModelMatchingSequence(vm:LookupSequence("fists_idle_01"))
	end
	return true
end

function SWEP:Holster()
	return false
end

function SWEP:OnRemove()
	if IsValid(self.cmdl_LeftCuff) then
		self.cmdl_LeftCuff:Remove()
	end
	if IsValid(self.cmdl_RightCuff) then
		self.cmdl_RightCuff:Remove()
	end
	return true
end

function SWEP:PreDrawViewModel(vm)
	if IsValid(vm) then
		vm:SetMaterial("engine/occlusionproxy")
	end
end

function SWEP:PostDrawViewModel(vm)
	if IsValid(vm) then
		vm:SetMaterial("")
	end
end

function SWEP:Uncuff()
	self:Remove()
	local ply = IsValid(self.Owner) and self.Owner
	if ply then
		ply:ConCommand("lastinv")
	end
end

if SERVER then
	local BreakSound = Sound("physics/metal/metal_barrel_impact_soft4.wav")
	local ResistSounds = {Sound("physics/metal/metal_box_strain1.wav"), Sound("physics/metal/metal_box_strain2.wav"), Sound("physics/metal/metal_box_strain3.wav"), Sound("physics/metal/metal_box_strain4.wav")}
	local ReleaseSounds = {Sound("physics/cardboard/cardboard_box_impact_soft1.wav"), Sound("physics/cardboard/cardboard_box_impact_soft2.wav"), Sound("physics/cardboard/cardboard_box_impact_soft3.wav"), Sound("physics/cardboard/cardboard_box_impact_soft4.wav"), Sound("physics/cardboard/cardboard_box_impact_soft5.wav"), Sound("physics/cardboard/cardboard_box_impact_soft6.wav")}

	function SWEP:Breakout()
		if IsValid(self.Owner) then
			sound.Play(BreakSound, self.Owner:GetShootPos(), 75, 100, 1)
			local friend = self:GetFriendBreaking()
			if IsValid(friend) then
				hook.Run("Cuffs_OnHandcuffBreak", self.Owner, self, friend)
			else
				hook.Run("Cuffs_OnHandcuffBreak", self.Owner, self)
			end
		end
		self:Uncuff()
	end

	function SWEP:AttemptBreak()
		local cur_time = CurTime()
		if self:GetFriendBreaking():IsValid() or (self.LastEscapeAttempt or 0) > cur_time then return end
		local owner = self:GetOwner()
		if hook.Run("Cuffs_AttemptBreak", owner, self) == false then return end
		self.LastEscapeAttempt = cur_time + 0.1
		local cuff_str = math.abs(4 / self:GetCuffStrength())
		self:SetCuffBroken(self:GetCuffBroken() + (hook.Run("Cuffs_BreakStrength", owner, cuff_str, self) or cuff_str))
		if self:GetCuffBroken() >= 100 then
			self:Breakout()
		end
		if cur_time > (self.NextResistSound or 0) then
			sound.Play(ResistSounds[math.random(1, #ResistSounds)], owner:GetShootPos(), 75, 100, math.Clamp((self:GetCuffStrength() - 0.5) / 2, 0.1, 1))
			self.NextResistSound = cur_time + 0.5
		end
	end
	
	local function GetTrace(ply)
		local tr = util.TraceLine({start = ply:EyePos(), endpos = ply:EyePos() + (ply:EyeAngles():Forward() * 100), filter = ply})
		local ent = tr.Entity
		if IsValid(ent) and ent:IsPlayer() then
			if ent:IsHandcuffed() then
				return tr
			end
		end
	end

	function SWEP:Think()
		self:BreakThink()
	end

	function SWEP:BreakThink()
		local cur_time = CurTime()
		if (self.NextRegen or 0) <= cur_time then
			local regen = self:GetCuffRegen()
			local friend = self:GetFriendBreaking()
			if IsValid(friend) and friend:IsPlayer() then
				local tr = GetTrace(friend)
				if tr and tr.Entity == self.Owner then
					regen = (regen * 0.5) - (2 / self:GetCuffStrength())
				else
					self:SetFriendBreaking()
				end
				if cur_time > (self.NextReleaseSound or 0) then
					sound.Play(ReleaseSounds[math.random(1, #ReleaseSounds)], self.Owner:GetShootPos(), 75, 100, self:GetCuffStrength() / 1.5)
					self.NextReleaseSound = cur_time + 0.25
				end
			end
			local regen_spd = math.abs(regen)
			self:SetCuffBroken(math.Approach(self:GetCuffBroken(), regen < 0 and 100 or 0, hook.Run("Cuffs_RegenSpeed", self.Owner, regen_spd, self) or regen_spd))
			self.NextRegen = cur_time + 0.05
			if self:GetCuffBroken() >= 100 then
				self:Breakout()
			end
		end
	end
end

if CLIENT then
	surface.CreateFont("HandcuffsText", {font = "Arial", size = 20, weight = 700})

	local Col = {Text = Color(255, 255, 255), TextShadow = Color(0, 0, 0), BoxOutline = Color(0,0,0), BoxBackground = Color(255, 255, 255, 20), BoxLeft = Color(255, 0, 0), BoxRight = Color(0, 255, 0), Blind = Color(0, 0, 0, 253), Blind2 = Color(0, 0, 0, 255)}
	local matGrad = Material("gui/gradient")
	function SWEP:DrawHUD()
		if self.Owner != LocalPlayer() then return end
		if self.Owner:GetActiveWeapon() != self then return end
		local w, h = (ScrW() / 2), (ScrH() / 2)
		local TextPos = h + 30
		local str = string.format("Deine Hände sind ")
		str = str..string.format("mit einem %s Material ", ((self:GetCuffRegen() >= 1) and "starken") or "weichen")
		str = str..string.format("%s verbunden", ((self:GetCuffStrength() >= 1) and "fest") or "lose")
		draw.SimpleText(str, "HandcuffsText", w + 1, TextPos + 1, Col.TextShadow, TEXT_ALIGN_CENTER)
		draw.SimpleText(str, "HandcuffsText", w, TextPos, Col.Text, TEXT_ALIGN_CENTER)
		if self:GetIsBlind() then
			TextPos = TextPos + 20
			draw.SimpleText("Deine Augen sind verbunden", "HandcuffsText", w + 1, TextPos + 1, Col.TextShadow, TEXT_ALIGN_CENTER)
			draw.SimpleText("Deine Augen sind verbunden", "HandcuffsText", w, TextPos, Col.Text, TEXT_ALIGN_CENTER)
		end
		if self:GetIsGagged() then
			TextPos = TextPos + 20
			draw.SimpleText("Dein Mund ist geknebelt", "HandcuffsText", w + 1, TextPos + 1, Col.TextShadow, TEXT_ALIGN_CENTER)
			draw.SimpleText("Dein Mund ist geknebelt", "HandcuffsText", w, TextPos, Col.Text, TEXT_ALIGN_CENTER)
		end
		TextPos = TextPos + 20
		local trans = (input.LookupBinding("+attack") or "[PRIMÄR]"):upper()
		if trans == "MOUSE1" then
			trans = "Linksklick"
		end
		str = string.format("%s, um dich zu befreien", trans)
		draw.SimpleText(str, "HandcuffsText", w + 1, TextPos + 1, Col.TextShadow, TEXT_ALIGN_CENTER)
		draw.SimpleText(str, "HandcuffsText", w, TextPos, Col.Text, TEXT_ALIGN_CENTER)
		TextPos = TextPos + 25
		surface.SetDrawColor(Col.BoxOutline)
		surface.DrawOutlinedRect(w - 101, TextPos - 1, 202, 22)
		surface.SetDrawColor(Col.BoxBackground)
		surface.DrawRect(w - 100, TextPos, 200, 20)
		render.SetScissorRect(w - 100, TextPos, (w - 100) + ((self:GetCuffBroken() / 100) * 200), TextPos + 20, true)
		surface.SetDrawColor(Col.BoxRight)
		surface.DrawRect(w - 100, TextPos, 200,20)
		surface.SetMaterial(matGrad)
		surface.SetDrawColor(Col.BoxLeft)
		surface.DrawTexturedRect(w - 100, TextPos, 200, 20)
		render.SetScissorRect(0, 0, 0, 0, false)
	end

	function SWEP:RenderScreenSpaceEffects()
		if self:GetIsBlind() then
			surface.SetDrawColor(Col.Blind)
			surface.DrawRect(-1, -1, ScrW() + 2, ScrH() + 2)
			surface.SetDrawColor(Col.Blind2)
			for i=1, ScrH(), 5 do
				surface.DrawRect(-1, i, ScrW() + 2, 4)
			end
			for i=1, ScrW(), 5 do
				surface.DrawRect(i, -1, 4, ScrH()+ 2)
			end
		end
	end
end

local RenderPos = {left = {bone = "ValveBiped.Bip01_L_Wrist", pos = Vector(0.4, 0.15, -0.45), ang = Angle(90, 0, 0), scale = Vector(0.035, 0.035, 0.015)}, right = {bone = "ValveBiped.Bip01_R_Wrist", pos = Vector(0.2, -0.15, 0.35), ang = Angle(100, 0, 0), scale = Vector(0.035, 0.035, 0.015)}, rope = {l = Vector(-0.2, 1.3, -0.25), r = Vector(0.4, 1.4, -0.2)}}
local CuffMdl = Model("models/hunter/tubes/tube2x2x1.mdl")
local DefaultRope = Material("cable/cable2")
local RopeCol = Color(255, 255, 255)
function SWEP:ViewModelDrawn(vm)
	if !IsValid(vm) then return end
	local left_cuff = self.cmdl_LeftCuff
	if !IsValid(left_cuff) then
		self.cmdl_LeftCuff = ClientsideModel(CuffMdl)
		left_cuff = self.cmdl_LeftCuff
		if !IsValid(left_cuff) then return end
		left_cuff:SetNoDraw(true)
	end
	local right_cuff = self.cmdl_RightCuff
	if !IsValid(right_cuff) then
		self.cmdl_RightCuff = ClientsideModel(CuffMdl)
		right_cuff = self.cmdl_RightCuff
		if !IsValid(right_cuff) then return end
		right_cuff:SetNoDraw(true)
	end
	local lpos, lang = self:GetBonePos(RenderPos.left.bone, vm)
	local rpos, rang = self:GetBonePos(RenderPos.right.bone, vm)
	if !(lpos and rpos and lang and rang) then return end
	left_cuff:SetPos(lpos + (lang:Forward() * RenderPos.left.pos.x) + (lang:Right() * RenderPos.left.pos.y) + (lang:Up() * RenderPos.left.pos.z))
	local u, r, f = lang:Up(), lang:Right(), lang:Forward()
	lang:RotateAroundAxis(u, RenderPos.left.ang.y)
	lang:RotateAroundAxis(r, RenderPos.left.ang.p)
	lang:RotateAroundAxis(f, RenderPos.left.ang.r)
	left_cuff:SetAngles(lang)
	local matrix = Matrix()
	matrix:Scale(RenderPos.left.scale)
	left_cuff:EnableMatrix("RenderMultiply", matrix)
	left_cuff:SetMaterial(self:GetCuffMaterial())
	left_cuff:DrawModel()
	right_cuff:SetPos(rpos + (rang:Forward() * RenderPos.right.pos.x) + (rang:Right() * RenderPos.right.pos.y) + (rang:Up() * RenderPos.right.pos.z))
	local u, r, f = rang:Up(), rang:Right(), rang:Forward()
	rang:RotateAroundAxis(u, RenderPos.right.ang.y)
	rang:RotateAroundAxis(r, RenderPos.right.ang.p)
	rang:RotateAroundAxis(f, RenderPos.right.ang.r)
	self.cmdl_RightCuff:SetAngles(rang)
	local matrix = Matrix()
	matrix:Scale(RenderPos.right.scale)
	right_cuff:EnableMatrix("RenderMultiply", matrix)
	right_cuff:SetMaterial(self:GetCuffMaterial())
	right_cuff:DrawModel()
	local rope_mat = self:GetRopeMaterial()
	if rope_mat != self.LastMatStr then
		local mat = Material(rope_mat)
		self.RopeMat = mat
		self.LastMatStr = mat
	end
	if !self.RopeMat then
		self.RopeMat = DefaultRope
	end
	render.SetMaterial(self.RopeMat)
	render.DrawBeam(lpos + (lang:Forward() * RenderPos.rope.l.x) + (lang:Right() * RenderPos.rope.l.y) + (lang:Up() * RenderPos.rope.l.z), rpos + (rang:Forward() * RenderPos.rope.r.x) + (rang:Right() * RenderPos.rope.r.y) + (rang:Up() * RenderPos.rope.r.z), 0.7, 0, 5, RopeCol)
end

local wrender = {
	collar = {bone = "Bip01 Neck1", pos = Vector(7, -0.5, 0), ang = Angle(95, 90, 90), scale = Vector(0.13, 0.15, 0.1)},
	left = {bone = "ValveBiped.Bip01_L_Hand", pos = Vector(0, 0.5, 0.2), ang = Angle(90, 0, 0), scale = Vector(0.055, 0.048, 0.047)},
	right = {bone = "ValveBiped.Bip01_R_Hand", pos = Vector(0, 0.5, -0.2), ang = Angle(90, 0, 0), scale = Vector(0.055, 0.048, 0.047)}, rope = {l = Vector(-0.2, 2.6, -0.25), r = Vector(-0.4, 2.7, -0.2)}
}
function SWEP:DrawWorldModel()
	if !IsValid(self.Owner) then return end
	local is_collar = self:GetIsCollar()
	local left = is_collar and wrender.collar or wrender.left
	local left_cuff = self.cmdl_LeftCuff
	if !IsValid(left_cuff) then
		self.cmdl_LeftCuff = ClientsideModel(CuffMdl)
		left_cuff = self.cmdl_LeftCuff
		if !IsValid(left_cuff) then return end
		left_cuff:SetNoDraw(true)
	end
	local right_cuff = self.cmdl_RightCuff
	if !is_collar then
		if !IsValid(right_cuff) then
			self.cmdl_RightCuff = ClientsideModel(CuffMdl)
			right_cuff = self.cmdl_RightCuff
			if !IsValid(right_cuff) then return end
			right_cuff:SetNoDraw(true)
		end
	end
	local lpos, lang = self:GetBonePos(left.bone, self.Owner)
	local rpos, rang
	if !is_collar then
		rpos, rang = self:GetBonePos(wrender.right.bone, self.Owner)
	end
	if !lpos or !lang or !is_collar and (!rpos or !rang) then return end
	left_cuff:SetPos(lpos + (lang:Forward() * left.pos.x) + (lang:Right() * left.pos.y) + (lang:Up() * left.pos.z))
	local u, r, f = lang:Up(), lang:Right(), lang:Forward()
	lang:RotateAroundAxis(u, left.ang.y)
	lang:RotateAroundAxis(r, left.ang.p)
	lang:RotateAroundAxis(f, left.ang.r)
	left_cuff:SetAngles(lang)
	local matrix = Matrix()
	matrix:Scale(left.scale)
	left_cuff:EnableMatrix("RenderMultiply", matrix)
	left_cuff:SetMaterial(self:GetCuffMaterial())
	left_cuff:SetupBones()
	left_cuff:DrawModel()
	if !is_collar then
		right_cuff:SetPos(rpos + (rang:Forward() * wrender.right.pos.x) + (rang:Right() * wrender.right.pos.y) + (rang:Up() * wrender.right.pos.z))
		local u, r, f = rang:Up(), rang:Right(), rang:Forward()
		rang:RotateAroundAxis(u, wrender.right.ang.y)
		rang:RotateAroundAxis(r, wrender.right.ang.p)
		rang:RotateAroundAxis(f, wrender.right.ang.r)
		right_cuff:SetAngles(rang)
		local matrix = Matrix()
		matrix:Scale(wrender.right.scale)
		right_cuff:EnableMatrix("RenderMultiply", matrix)
		right_cuff:SetMaterial(self:GetCuffMaterial())
		right_cuff:SetupBones()
		right_cuff:DrawModel()
	end
	if is_collar then return end
	if (lpos.x == 0 and lpos.y == 0 and lpos.z == 0) or (rpos.x == 0 and rpos.y == 0 and rpos.z == 0) then return end
	local rope_mat = self:GetRopeMaterial()
	if rope_mat != self.LastMatStr then
		local mat = Material(rope_mat)
		self.RopeMat = mat
		self.LastMatStr = mat
	end
	if !self.RopeMat then
		self.RopeMat = DefaultRope
	end
	render.SetMaterial(self.RopeMat)
	render.DrawBeam(lpos + (lang:Forward() * wrender.rope.l.x) + (lang:Right() * wrender.rope.l.y) + (lang:Up() * wrender.rope.l.z), rpos + (rang:Forward() * wrender.rope.r.x) + (rang:Right() * wrender.rope.r.y) + (rang:Up() * wrender.rope.r.z), 0.7, 0, 5, RopeCol)
end

function SWEP:GetBonePos(bonename, vm)
	local bone = vm:LookupBone(bonename)
	if !bone then return end
	local pos, ang = Vector(0, 0, 0), Angle(0, 0, 0)
	local matrix = vm:GetBoneMatrix(bone)
	if matrix then
		pos = matrix:GetTranslation()
		ang = matrix:GetAngles()
	end
	if self.ViewModelFlip then
		ang.r = -ang.r
	end
	return pos, ang
end