-- "gamemodes\\sandbox\\gamemode\\gui\\iconeditor.lua"
-- Retrieved by https://github.com/lewisclark/glua-steal

local PANEL = {}

AccessorFunc( PANEL, "m_strModel", "Model" )
AccessorFunc( PANEL, "m_pOrigin", "Origin" )
AccessorFunc( PANEL, "m_bCustomIcon", "CustomIcon" )

function PANEL:Init()

	self:SetSize( 762, 502 )
	self:SetTitle( "#smwidget.icon_editor" )

	local left = self:Add( "Panel" )
	left:Dock( LEFT )
	left:SetWide( 400 )
	self.LeftPanel = left

		local bg = left:Add( "DPanel" )
		bg:Dock( FILL )
		bg:DockMargin( 0, 0, 0, 4 )
		bg.Paint = function( self, w, h ) draw.RoundedBox( 0, 0, 0, w, h, Color( 0, 0, 0, 128 ) ) end

		self.SpawnIcon = bg:Add( "SpawnIcon" )
		--self.SpawnIcon.DoClick = function() self:RenderIcon() end

		self.ModelPanel = bg:Add( "DAdjustableModelPanel" )
		self.ModelPanel:Dock( FILL )
		self.ModelPanel.FarZ = 32768

		local mat_wireframe = Material( "models/wireframe" )
		function self.ModelPanel.PostDrawModel( mdlpnl, ent )
			if ( self.ShowOrigin ) then
				render.DrawLine( vector_origin, Vector( 0, 0, 100 ), Color( 0, 0, 255 ) )
				render.DrawLine( vector_origin, Vector( 0, 100, 0 ), Color( 0, 255, 0 ) )
				render.DrawLine( vector_origin, Vector( 100, 0, 0 ), Color( 255, 0, 0 ) )
			end

			if ( self.ShowBBox ) then
				local mins, maxs = ent:GetRenderBounds()
				local scale = 1
				mat_wireframe:SetVector( "$color", Vector( 1, 1, 1 ) )
				render.SetMaterial( mat_wireframe )

				render.DrawBox( ent:GetPos(), ent:GetAngles(), mins * scale, maxs * scale )
			end

		end

	local controls = left:Add( "Panel" )
	controls:SetTall( 64 )
	controls:Dock( BOTTOM )

		local controls_anim = controls:Add( "Panel" )
		controls_anim:SetTall( 20 )
		controls_anim:Dock( TOP )
		controls_anim:DockMargin( 0, 0, 0, 4 )
		controls_anim:MoveToBack()

			self.AnimTrack = controls_anim:Add( "DSlider" )
			self.AnimTrack:Dock( FILL )
			self.AnimTrack:SetNotches( 100 )
			self.AnimTrack:SetTrapInside( true )
			self.AnimTrack:SetLockY( 0.5 )

			self.AnimPause = controls_anim:Add( "DImageButton" )
			self.AnimPause:SetImage( "icon16/control_pause_blue.png" )
			self.AnimPause:SetStretchToFit( false )
			self.AnimPause:SetPaintBackground( true )
			self.AnimPause:SetIsToggle( true )
			self.AnimPause:SetToggle( false )
			self.AnimPause:Dock( LEFT )
			self.AnimPause:SetWide( 32 )

		local BestGuess = controls:Add( "DImageButton" )
		BestGuess:SetImage( "icon32/wand.png" )
		BestGuess:SetStretchToFit( false )
		BestGuess:SetPaintBackground( true )
		BestGuess.DoClick = function() self:BestGuessLayout() end
		BestGuess:Dock( LEFT )
		BestGuess:DockMargin( 0, 0, 0, 0 )
		BestGuess:SetWide( 50 )
		BestGuess:SetTooltip( "Best Guess" )

		local FullFrontal = controls:Add( "DImageButton" )
		FullFrontal:SetImage( "icon32/hand_point_090.png" )
		FullFrontal:SetStretchToFit( false )
		FullFrontal:SetPaintBackground( true )
		FullFrontal.DoClick = function() self:FullFrontalLayout() end
		FullFrontal:Dock( LEFT )
		FullFrontal:DockMargin( 2, 0, 0, 0 )
		FullFrontal:SetWide( 50 )
		FullFrontal:SetTooltip( "Front" )

		local Above = controls:Add( "DImageButton" )
		Above:SetImage( "icon32/hand_property.png" )
		Above:SetStretchToFit( false )
		Above:SetPaintBackground( true )
		Above.DoClick = function() self:AboveLayout() end
		Above:Dock( LEFT )
		Above:DockMargin( 2, 0, 0, 0 )
		Above:SetWide( 50 )
		Above:SetTooltip( "Above" )

		local Right = controls:Add( "DImageButton" )
		Right:SetImage( "icon32/hand_point_180.png" )
		Right:SetStretchToFit( false )
		Right:SetPaintBackground( true )
		Right.DoClick = function() self:RightLayout() end
		Right:Dock( LEFT )
		Right:DockMargin( 2, 0, 0, 0 )
		Right:SetWide( 50 )
		Right:SetTooltip( "Right" )

		local Origin = controls:Add( "DImageButton" )
		Origin:SetImage( "icon32/hand_point_090.png" )
		Origin:SetStretchToFit( false )
		Origin:SetPaintBackground( true )
		Origin.DoClick = function() self:OriginLayout() end
		Origin:Dock( LEFT )
		Origin:DockMargin( 2, 0, 0, 0 )
		Origin:SetWide( 50 )
		Origin:SetTooltip( "Center" )

		local Render = controls:Add( "DButton" )
		Render:SetText( "RENDER" )
		Render.DoClick = function() self:RenderIcon() end
		Render:Dock( RIGHT )
		Render:DockMargin( 2, 0, 0, 0 )
		Render:SetWide( 50 )
		Render:SetTooltip( "Render Icon" )

		local Picker = controls:Add( "DImageButton" )
		Picker:SetImage( "icon32/color_picker.png" )
		Picker:SetStretchToFit( false )
		Picker:SetPaintBackground( true )
		Picker:Dock( RIGHT )
		Picker:DockMargin( 2, 0, 0, 0 )
		Picker:SetWide( 50 )
		Picker.DoClick = function()

			self:SetVisible( false )

			util.worldpicker.Start( function( tr )

				self:SetVisible( true )

				if ( !IsValid( tr.Entity ) ) then return end

				self:SetFromEntity( tr.Entity )

			end )
		end

	local right = self:Add( "DPropertySheet" )
	right:Dock( FILL )
	right:SetPadding( 0 )
	right:DockMargin( 4, 0, 0, 0 )
	self.PropertySheet = right

	-- Animations

	local anims = right:Add( "Panel" )
	anims:Dock( FILL )
	anims:DockPadding( 2, 0, 2, 2 )
	right:AddSheet( "#smwidget.animations", anims, "icon16/monkey.png" )

		self.AnimList = anims:Add( "DListView" )
		self.AnimList:AddColumn( "name" )
		self.AnimList:Dock( FILL )
		self.AnimList:SetMultiSelect( false )
		self.AnimList:SetHideHeaders( true )

	-- Bodygroups

	local pnl = right:Add( "Panel" )
	pnl:Dock( FILL )
	pnl:DockPadding( 7, 0, 7, 7 )

	self.BodygroupTab = right:AddSheet( "#smwidget.bodygroups", pnl, "icon16/brick.png" )

		self.BodyList = pnl:Add( "DScrollPanel" )
		self.BodyList:Dock( FILL )

			--This kind of works but they don't move their stupid mouths. So fuck off.
			--[[
			self.Scenes = pnl:Add( "DTree" )
			self.Scenes:Dock( BOTTOM )
			self.Scenes:SetSize( 200, 200 )
			self.Scenes.DoClick = function( _, node )

				if ( !node.FileName ) then return end
				local ext = string.GetExtensionFromFilename( node.FileName )
				if( ext != "vcd" ) then return end

				self.ModelPanel:StartScene( node.FileName )
				MsgN( node.FileName )

			end

			local materials = self.Scenes.RootNode:AddFolder( "Scenes", "scenes/", true )
			materials:SetIcon( "icon16/photos.png" )--]]

	-- Settings

	local settings = right:Add( "Panel" )
	settings:Dock( FILL )
	settings:DockPadding( 7, 0, 7, 7 )
	right:AddSheet( "#smwidget.settings", settings, "icon16/cog.png" )

		local bbox = settings:Add( "DCheckBoxLabel" )
		bbox:SetText( "Show Bounding Box" )
		bbox:Dock( TOP )
		bbox:DockMargin( 0, 0, 0, 3 )
		bbox:SetDark( true )
		bbox.OnChange = function( p, b )
			self.ShowBBox = b
			p:SetCookie( "checkbox_checked", b && 1 or 0 )
		end
		bbox.LoadCookies = function( p ) local b = p:GetCookie( "checkbox_checked" ) p:SetChecked( b ) p:OnChange( tobool( b ) ) end
		bbox:SetCookieName( "model_editor_bbox" )

		local origin = settings:Add( "DCheckBoxLabel" )
		origin:SetText( "Show Origin" )
		origin:Dock( TOP )
		origin:DockMargin( 0, 0, 0, 3 )
		origin:SetDark( true )
		origin.OnChange = function( p, b )
			self.ShowOrigin = b
			p:SetCookie( "checkbox_checked", b && 1 or 0 )
		end
		origin.LoadCookies = function( p ) local b = p:GetCookie( "checkbox_checked" ) p:SetChecked( b ) p:OnChange( tobool( b ) ) end
		origin:SetCookieName( "model_editor_origin" )

		local angle = settings:Add( "DTextEntry" )
		angle:SetTooltip( "Entity Angles" )
		angle:Dock( TOP )
		angle:DockMargin( 0, 0, 0, 3 )
		angle:SetZPos( 100 )
		angle.OnChange = function( p, b )
			self.ModelPanel:GetEntity():SetAngles( Angle( angle:GetText() ) )
		end
		self.TargetAnglePanel = angle

		local cam_angle = settings:Add( "DTextEntry" )
		cam_angle:SetTooltip( "Camera Angles" )
		cam_angle:Dock( TOP )
		cam_angle:DockMargin( 0, 0, 0, 3 )
		cam_angle:SetZPos( 101 )
		cam_angle.OnChange = function( p, b )
			self.ModelPanel:SetLookAng( Angle( cam_angle:GetText() ) )
		end
		self.TargetCamAnglePanel = cam_angle

		local cam_pos = settings:Add( "DTextEntry" )
		cam_pos:SetTooltip( "Camera Position" )
		cam_pos:Dock( TOP )
		cam_pos:DockMargin( 0, 0, 0, 3 )
		cam_pos:SetZPos( 102 )
		cam_pos.OnChange = function( p, b )
			self.ModelPanel:SetCamPos( Vector( cam_pos:GetText() ) )
		end
		self.TargetCamPosPanel = cam_pos

		local playSpeed = settings:Add( "DNumSlider" )
		playSpeed:SetText( "Playback Speed" )
		playSpeed:Dock( TOP )
		playSpeed:DockMargin( 0, 0, 0, 3 )
		playSpeed:SetMin( -1 )
		playSpeed:SetDark( true )
		playSpeed:SetMax( 2 )
		playSpeed.OnValueChanged = function( s, value )
			self.ModelPanel:GetEntity():SetPlaybackRate( value )
		end

end

function PANEL:SetDefaultLighting()

	self.ModelPanel:SetAmbientLight( Color( 255 * 0.3, 255 * 0.3, 255 * 0.3 ) )

	self.ModelPanel:SetDirectionalLight( BOX_FRONT, Color( 255 * 1.3, 255 * 1.3, 255 * 1.3 ) )
	self.ModelPanel:SetDirectionalLight( BOX_BACK, Color( 255 * 0.2, 255 * 0.2, 255 * 0.2 ) )
	self.ModelPanel:SetDirectionalLight( BOX_RIGHT, Color( 255 * 0.2, 255 * 0.2, 255 * 0.2 ) )
	self.ModelPanel:SetDirectionalLight( BOX_LEFT, Color( 255 * 0.2, 255 * 0.2, 255 * 0.2 ) )
	self.ModelPanel:SetDirectionalLight( BOX_TOP, Color( 255 * 2.3, 255 * 2.3, 255 * 2.3 ) )
	self.ModelPanel:SetDirectionalLight( BOX_BOTTOM, Color( 255 * 0.1, 255 * 0.1, 255 * 0.1 ) )

end

function PANEL:BestGuessLayout()

	local ent = self.ModelPanel:GetEntity()
	local pos = ent:GetPos()
	local ang = ent:GetAngles()

	local tab = PositionSpawnIcon( ent, pos, true )

	ent:SetAngles( ang )
	if ( tab ) then
		self.ModelPanel:SetCamPos( tab.origin )
		self.ModelPanel:SetFOV( tab.fov )
		self.ModelPanel:SetLookAng( tab.angles )
	end

end

function PANEL:FullFrontalLayout()

	local ent = self.ModelPanel:GetEntity()
	local pos = ent:GetPos()
	local campos = pos + Vector( -200, 0, 0 )

	self.ModelPanel:SetCamPos( campos )
	self.ModelPanel:SetFOV( 45 )
	self.ModelPanel:SetLookAng( ( campos * -1 ):Angle() )

end

function PANEL:AboveLayout()

	local ent = self.ModelPanel:GetEntity()
	local pos = ent:GetPos()
	local campos = pos + Vector( 0, 0, 200 )

	self.ModelPanel:SetCamPos( campos )
	self.ModelPanel:SetFOV( 45 )
	self.ModelPanel:SetLookAng( ( campos * -1 ):Angle() )

end

function PANEL:RightLayout()

	local ent = self.ModelPanel:GetEntity()
	local pos = ent:GetPos()
	local campos = pos + Vector( 0, 200, 0 )

	self.ModelPanel:SetCamPos( campos )
	self.ModelPanel:SetFOV( 45 )
	self.ModelPanel:SetLookAng( ( campos * -1 ):Angle() )

end

function PANEL:OriginLayout()

	local ent = self.ModelPanel:GetEntity()
	local pos = ent:GetPos()
	local campos = pos + vector_origin

	self.ModelPanel:SetCamPos( campos )
	self.ModelPanel:SetFOV( 45 )
	self.ModelPanel:SetLookAng( Angle( 0, -180, 0 ) )

end

function PANEL:UpdateEntity( ent )

	ent:SetEyeTarget( self.ModelPanel:GetCamPos() )

	if ( IsValid( self.TargetAnglePanel ) && !self.TargetAnglePanel:IsEditing() ) then
		self.TargetAnglePanel:SetText( tostring( ent:GetAngles() ) )
	end
	if ( IsValid( self.TargetCamAnglePanel ) && !self.TargetCamAnglePanel:IsEditing() ) then
		self.TargetCamAnglePanel:SetText( tostring( self.ModelPanel:GetLookAng() ) )
	end
	if ( IsValid( self.TargetCamPosPanel ) && !self.TargetCamPosPanel:IsEditing() ) then
		self.TargetCamPosPanel:SetText( tostring( self.ModelPanel:GetCamPos() ) )
	end

	if ( self.AnimTrack:GetDragging() ) then

		ent:SetCycle( self.AnimTrack:GetSlideX() )
		self.AnimPause:SetToggle( true )

	elseif ( ent:GetCycle() != self.AnimTrack:GetSlideX() ) then

		local cyc = ent:GetCycle()
		if ( cyc < 0 ) then cyc = cyc + 1 end
		self.AnimTrack:SetSlideX( cyc )

	end

	if ( !self.AnimPause:GetToggle() ) then
		ent:FrameAdvance( FrameTime() )
	end

end

function PANEL:RenderIcon()

	local tab = {}
	tab.ent = self.ModelPanel:GetEntity()
	tab.cam_pos = self.ModelPanel:GetCamPos()
	tab.cam_ang = self.ModelPanel:GetLookAng()
	tab.cam_fov = self.ModelPanel:GetFOV()

	self.SpawnIcon:RebuildSpawnIconEx( tab )

end

function PANEL:SetIcon( icon )

	if ( !IsValid( icon ) ) then return end

	local model = icon:GetModelName()
	self:SetOrigin( icon )

	self.SpawnIcon:SetSize( icon:GetSize() )
	self.SpawnIcon:InvalidateLayout( true )

	local w, h = icon:GetSize()
	if ( w / h < 1 ) then
		self:SetSize( 700, 502 + 400 )
		self.LeftPanel:SetWide( 400 )
	elseif ( w / h > 1 ) then
		self:SetSize( 900, 502 - 100 )
		self.LeftPanel:SetWide( 600 )
	else
		self:SetSize( 700, 502 )
		self.LeftPanel:SetWide( 400 )
	end

	if ( !model or model == "" ) then

		self:SetModel( "error.mdl" )
		self.SpawnIcon:SetSpawnIcon( icon:GetIconName() )
		self:SetCustomIcon( true )

	else

		self:SetModel( model )
		self.SpawnIcon:SetModel( model, icon:GetSkinID(), icon:GetBodyGroup() )
		self:SetCustomIcon( false )

	end

end

function PANEL:Refresh()

	if ( !self:GetModel() ) then return end

	self.ModelPanel:SetModel( self:GetModel() )
	self.ModelPanel.LayoutEntity = function() self:UpdateEntity( self.ModelPanel:GetEntity() )  end

	local ent = self.ModelPanel:GetEntity()

	ent:SetSkin( self.SpawnIcon:GetSkinID() )
	ent:SetBodyGroups( self.SpawnIcon:GetBodyGroup() )

	self:BestGuessLayout()
	self:FillAnimations( ent )
	self:SetDefaultLighting()

end

function PANEL:FillAnimations( ent )

	self.AnimList:Clear()

	for k, v in SortedPairsByValue( ent:GetSequenceList() or {} ) do

		local line = self.AnimList:AddLine( string.lower( v ) )

		line.OnSelect = function()

			local speed = ent:GetPlaybackRate()
			ent:ResetSequence( v )
			ent:SetCycle( 0 )
			ent:SetPlaybackRate( speed )
			if ( speed < 0 ) then ent:SetCycle( 1 ) end

		end

	end

	self.BodyList:Clear()
	local newItems = 0

	if ( ent:SkinCount() > 1 ) then

		local skinSlider = self.BodyList:Add( "DNumSlider" )
		skinSlider:Dock( TOP )
		skinSlider:DockMargin( 0, 0, 0, 3 )
		skinSlider:SetText( "Skin" )
		skinSlider:SetDark( true )
		skinSlider:SetDecimals( 0 )
		skinSlider:SetMinMax( 0, ent:SkinCount() - 1 )
		skinSlider:SetValue( ent:GetSkin() )
		skinSlider.OnValueChanged = function( s, newVal )
			newVal = math.Round( newVal )

			ent:SetSkin( newVal )

			if ( IsValid( self:GetOrigin() ) ) then self:GetOrigin():SkinChanged( newVal ) end

			-- If we're not using a custom, change our spawnicon
			-- so we save the new skin in the right place...
			if ( !self:GetCustomIcon() ) then
				self.SpawnIcon:SetModel( self.SpawnIcon:GetModelName(), newVal, self.SpawnIcon:GetBodyGroup() )
			end
		end
		newItems = newItems + 1

	end

	for k = 0, ent:GetNumBodyGroups() - 1 do

		if ( ent:GetBodygroupCount( k ) <= 1 ) then continue end

		local bgSlider = self.BodyList:Add( "DNumSlider" )
		bgSlider:Dock( TOP )
		bgSlider:DockMargin( 0, 0, 0, 3 )
		bgSlider:SetDark( true )
		bgSlider:SetDecimals( 0 )
		bgSlider:SetText( ent:GetBodygroupName( k ) )
		bgSlider:SetMinMax( 0, ent:GetBodygroupCount( k ) - 1 )
		bgSlider:SetValue( ent:GetBodygroup( k ) )
		bgSlider.BodyGroupID = k
		bgSlider.OnValueChanged = function( s, newVal )
			newVal = math.Round( newVal )

			ent:SetBodygroup( s.BodyGroupID, newVal )

			if ( IsValid( self:GetOrigin() ) ) then self:GetOrigin():BodyGroupChanged( s.BodyGroupID, newVal ) end

			-- If we're not using a custom, change our spawnicon
			-- so we save the new skin in the right place...
			if ( !self:GetCustomIcon() ) then
				self.SpawnIcon:SetBodyGroup( s.BodyGroupID, newVal )
				self.SpawnIcon:SetModel( self.SpawnIcon:GetModelName(), self.SpawnIcon:GetSkinID(), self.SpawnIcon:GetBodyGroup() )
			end
		end
		newItems = newItems + 1

	end

	if ( newItems > 0 ) then
		self.BodygroupTab.Tab:SetVisible( true )
	else
		self.BodygroupTab.Tab:SetVisible( false )
	end
	local propertySheet = self.PropertySheet
	propertySheet.tabScroller:InvalidateLayout()

end

function PANEL:SetFromEntity( ent )

	if ( !IsValid( ent ) ) then return end

	local bodyStr = ""
	for i = 0, 8 do
		bodyStr = bodyStr .. math.min( ent:GetBodygroup( i ) or 0, 9 )
	end

	self.SpawnIcon:SetModel( ent:GetModel(), ent:GetSkin(), bodyStr )
	self:SetModel( ent:GetModel() )
	self:Refresh()

end

vgui.Register( "IconEditor", PANEL, "DFrame" )
