local vector_origin = Vector()

local att, angpos, attname, elemname, targetent
local col = Color(255, 0, 0, 255)
local pc
local laserline
local laserdot
local laserFOV = 1.5
local traceres

local render = render
local Material = Material
local ProjectedTexture = ProjectedTexture
local math = math

SWEP.LaserDistance = 12 * 50 -- default 50 feet
SWEP.LaserDistanceVisual = 12 * 4 --default 4 feet

local function IsHolstering(wep)
	if IsValid(wep) and TFA.Enum.HolsterStatus[wep:GetStatus()] then return true end

	return false
end

function SWEP:DrawLaser(is_vm)
	local self2 = self:GetTable()

	if not laserline then
		laserline = Material(self2.LaserLine or "cable/smoke")
	end

	if not laserdot then
		laserdot = Material(self2.LaserDot or "effects/tfalaserdot")
	end

	local ply = self:GetOwner()
	if not IsValid(ply) then return end

	if ply:IsPlayer() then
		local f = ply.GetNW2Vector or ply.GetNWVector
		pc = f(ply, "TFALaserColor", vector_origin)
		col.r = pc.x
		col.g = pc.y
		col.b = pc.z
	else
		col.r = 255
		col.g = 0
		col.b = 0
	end

	if is_vm then
		if not self2.VMIV(self) then
			self:CleanLaser()

			return
		end

		targetent = self2.OwnerViewModel
		elemname = self2.GetStatL(self, "LaserSight_VElement", self2.GetStatL(self, "LaserSight_Element"))

		local ViewModelElements = self:GetStatRaw("ViewModelElements", TFA.LatestDataVersion)

		if elemname and ViewModelElements[elemname] and IsValid(ViewModelElements[elemname].curmodel) then
			targetent = ViewModelElements[elemname].curmodel
		end

		att = self2.GetStatL(self, "LaserSightAttachment")
		attname = self2.GetStatL(self, "LaserSightAttachmentName")

		if attname then
			att = targetent:LookupAttachment(attname)
		end

		if (not att) or att <= 0 then
			self:CleanLaser()

			return
		end

		angpos = targetent:GetAttachment(att)

		if not angpos then
			self:CleanLaser()

			return
		end

		if self2.LaserDotISMovement and self2.CLIronSightsProgress > 0 then
			local isang = self2.GetStatL(self, "IronSightsAngle")
			angpos.Ang:RotateAroundAxis(angpos.Ang:Right(), isang.y * (self2.ViewModelFlip and -1 or 1) * self2.CLIronSightsProgress)
			angpos.Ang:RotateAroundAxis(angpos.Ang:Up(), -isang.x * self2.CLIronSightsProgress)
		end

		local localProjAng = select(2, WorldToLocal(vector_origin, angpos.Ang, vector_origin, EyeAngles()))
		localProjAng.p = localProjAng.p * ply:GetFOV() / self2.ViewModelFOV
		localProjAng.y = localProjAng.y * ply:GetFOV() / self2.ViewModelFOV
		local wsProjAng = select(2, LocalToWorld(vector_origin, localProjAng, vector_origin, EyeAngles())) --reprojection for trace angle
		traceres = util.QuickTrace(ply:GetShootPos(), wsProjAng:Forward() * 999999, ply)

		if not IsValid(ply.TFALaserDot) and not IsHolstering(self) then
			local lamp = ProjectedTexture()
			ply.TFALaserDot = lamp
			lamp:SetTexture(laserdot:GetString("$basetexture"))
			lamp:SetFarZ(self2.LaserDistance) -- How far the light should shine
			lamp:SetFOV(laserFOV)
			lamp:SetPos(angpos.Pos)
			lamp:SetAngles(angpos.Ang)
			lamp:SetBrightness(5)
			lamp:SetNearZ(1)
			lamp:SetEnableShadows(false)
			lamp:Update()
		end

		local lamp = ply.TFALaserDot

		if IsValid(lamp) then
			local lamppos = EyePos() + EyeAngles():Up() * 4
			local ang = (traceres.HitPos - lamppos):Angle()
			self2.laserpos_old = traceres.HitPos
			ang:RotateAroundAxis(ang:Forward(), math.Rand(-180, 180))
			lamp:SetPos(lamppos)
			lamp:SetAngles(ang)
			lamp:SetColor(col)
			lamp:SetFOV(laserFOV * math.Rand(0.9, 1.1))
			lamp:Update()
		end

		return
	end

	targetent = self

	elemname = self2.GetStatL(self, "LaserSight_WElement", self2.GetStatL(self, "LaserSight_Element"))

	local WorldModelElements = self:GetStatRaw("WorldModelElements", TFA.LatestDataVersion)

	if elemname and WorldModelElements[elemname] and IsValid(WorldModelElements[elemname].curmodel) then
		targetent = WorldModelElements[elemname].curmodel
	end

	att = self2.GetStatL(self, "LaserSightAttachmentWorld", self2.GetStatL(self, "LaserSightAttachment"))

	attname = self2.GetStatL(self, "LaserSightAttachmentWorldName", self2.GetStatL(self, "LaserSightAttachmentName"))

	if attname then
		att = targetent:LookupAttachment(attname)
	end

	if (not att) or att <= 0 then
		self:CleanLaser()

		return
	end

	angpos = targetent:GetAttachment(att)

	if not angpos then
		angpos = targetent:GetAttachment(1)
	end

	if not angpos then
		self:CleanLaser()

		return
	end

	if not IsValid(ply.TFALaserDot) and not IsHolstering(self) then
		local lamp = ProjectedTexture()
		ply.TFALaserDot = lamp
		lamp:SetTexture(laserdot:GetString("$basetexture"))
		lamp:SetFarZ(self2.LaserDistance) -- How far the light should shine
		lamp:SetFOV(laserFOV)
		lamp:SetPos(angpos.Pos)
		lamp:SetAngles(angpos.Ang)
		lamp:SetBrightness(5)
		lamp:SetNearZ(1)
		lamp:SetEnableShadows(false)
		lamp:Update()
	end

	local lamp = ply.TFALaserDot

	if IsValid(lamp) then
		local ang = angpos.Ang
		ang:RotateAroundAxis(ang:Forward(), math.Rand(-180, 180))
		lamp:SetPos(angpos.Pos)
		lamp:SetAngles(ang)
		lamp:SetColor(col)
		lamp:SetFOV(laserFOV * math.Rand(0.9, 1.1))
		lamp:Update()
	end

	traceres = util.QuickTrace(angpos.Pos, angpos.Ang:Forward() * self2.LaserDistance, ply)
	local hpos = traceres.StartPos + angpos.Ang:Forward() * math.min(traceres.HitPos:Distance(angpos.Pos), self2.LaserDistanceVisual )
	render.SetMaterial(laserline)
	render.SetColorModulation(1, 1, 1)
	render.StartBeam(2)
	col.r = math.sqrt(col.r / 255) * 255
	col.g = math.sqrt(col.g / 255) * 255
	col.b = math.sqrt(col.b / 255) * 255
	render.AddBeam(angpos.Pos, self2.LaserBeamWidth or 0.25, 0, col)
	col.a = 0
	render.AddBeam(hpos, 0, 0, col)
	render.EndBeam()
end

function SWEP:CleanLaser()
	local ply = self:GetOwner()

	if IsValid(ply) and IsValid(ply.TFALaserDot) then
		ply.TFALaserDot:Remove()
	end
end
