--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| 	Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]


local PANEL = {}

AccessorFunc( PANEL, "m_iSpaceX",		"SpaceX" )
AccessorFunc( PANEL, "m_iSpaceY",		"SpaceY" )
AccessorFunc( PANEL, "m_iBorder",		"Border" )
AccessorFunc( PANEL, "m_iBaseSize",		"BaseSize" )
AccessorFunc( PANEL, "m_iMinHeight",	"MinHeight" )

function PANEL:Init()

	self:SetDropPos( "46" )
	self:SetMinHeight( 1 )

	self:SetSpaceX( 0 )
	self:SetSpaceY( 0 )
	self:SetBorder( 0 )
	self:SetBaseSize( 64 )

	self.LastW = 0
	self.LastH = 0

	self.Tiles = {}

end

function PANEL:Layout()

	self.LastW = 0
	self.LastH = 0
	self:InvalidateLayout()

end

function PANEL:FitsInTile( x, y, w, h )

	for a = x, x + ( w - 1 ) do
		for b = y, y + ( h - 1 ) do

			if ( self:GetTile( a, b ) == 1 ) then
				return false
			end

		end
	end

	return true

end

function PANEL:FindFreeTile( x, y, w, h )

	x = x or 1
	y = y or 1

	local span = math.floor( ( self:GetWide() - self:GetBorder() * 2 + self:GetSpaceX() ) / ( self:GetBaseSize() + self:GetSpaceX() ) )
	if ( span < 1 ) then span = 1 end

	for i = 1, span do

		-- Too long to fit on this line
		if ( ( i + ( w - 1 ) ) > span ) then

			-- If we're on the first part
			-- and the line is empty
			-- add it. It might be too long to fit on anyway
			if ( i == 1 && self:FitsInTile( i, y, w, h ) ) then
				return i, y
			end

			break
		end

		if ( self:FitsInTile( i, y, w, h ) ) then
			return i, y
		end

	end

	return self:FindFreeTile( 1, y + 1, w, h )

end

function PANEL:ClearTiles()

	self.Tiles = {}

end

function PANEL:GetTile( x, y )

	if ( !self.Tiles[y] ) then
		return nil
	end

	return self.Tiles[y][x]

end

function PANEL:SetTile( x, y, val )

	if ( !self.Tiles[y] ) then
		self.Tiles[y] = {}
	end

	self.Tiles[y][x] = val

end

function PANEL:ConsumeTiles( x, y, w, h )

	for a = x, x + ( w - 1 ) do
		for b = y, y + ( h - 1 ) do
			self:SetTile( a, b, 1 )
		end
	end

end

function PANEL:LayoutTiles()

	local StartLine = 1
	local tilesize = self:GetBaseSize()
	local MaxWidth = math.floor( ( self:GetWide() - self:GetBorder() * 2 + self:GetSpaceX() ) / ( tilesize + self:GetSpaceX() ) )

	self:ClearTiles()

	for k, v in ipairs( self:GetChildren() ) do

		if ( !v:IsVisible() ) then continue end

		local w = math.ceil( v:GetWide() / ( tilesize + self:GetSpaceX() ) )
		local h = math.ceil( v:GetTall() / ( tilesize + self:GetSpaceY() ) )

		if ( v.OwnLine ) then
			w = MaxWidth
		end

		local x, y = self:FindFreeTile( 1, StartLine, w, h )

		v:SetPos( self:GetBorder() + ( x - 1 ) * ( tilesize + self:GetSpaceX() ), self:GetBorder() + ( y - 1 ) * ( tilesize + self:GetSpaceY() ) )

		self:ConsumeTiles( x, y, w, h )

		if ( v.OwnLine ) then
			StartLine = y + 1
		end

		LastX = x

	end

end

function PANEL:PerformLayout()

	local ShouldLayout = false

	if ( self.LastW != self:GetWide() ) then ShouldLayout = true end
	if ( self.LastH != self:GetTall() ) then ShouldLayout = true end

	self.LastW = self:GetWide()
	self.LastH = self:GetTall()

	if ( ShouldLayout ) then
		self:LayoutTiles()
	end

	local w, h = self:ChildrenSize()
	h = math.max( h + self:GetBorder(), self:GetMinHeight() )

	self:SetHeight( h )

end

function PANEL:OnModified()

	-- Override me

end

function PANEL:OnChildRemoved()

	-- A panel got removed, we gotta recompress z positions
	for k, v in pairs( self:GetChildren() ) do
		v:SetZPos( k )
	end

	self:Layout()

end

function PANEL:OnChildAdded( child )

	-- Set the Z position for child ordering. Without this self:GetChildren() might return unpredictable results
	child:SetZPos( self:ChildCount() )

	local dn = self:GetDnD()
	if ( dn ) then
		child:Droppable( self:GetDnD() )
	end

	if ( self:IsSelectionCanvas() ) then
		child:SetSelectable( true )
	end

	self:Layout()

end

function PANEL:Copy()

	local copy = vgui.Create( "DTileLayout", self:GetParent() )
	copy:CopyBase( self )
	copy:SetSortable( self:GetSortable() )
	copy:SetDnD( self:GetDnD() )
	copy:SetSpaceX( self:GetSpaceX() )
	copy:SetSpaceY( self:GetSpaceY() )
	copy:SetBorder( self:GetBorder() )
	copy:SetSelectionCanvas( self:GetSelectionCanvas() )
	copy.OnModified = self.OnModified

	copy:CopyContents( self )

	return copy

end

function PANEL:CopyContents( from )

	for k, v in ipairs( from:GetChildren() ) do

		v:Copy():SetParent( self )

	end

end

function PANEL:GenerateExample( ClassName, PropertySheet, Width, Height )

	local pnl = vgui.Create( ClassName )
	pnl:MakeDroppable( "ExampleDraggable", false )
	pnl:SetWide( 196 )
	pnl:SetUseLiveDrag( true )
	pnl:SetSelectionCanvas( true )
	pnl:SetSpaceX( 4 )
	pnl:SetSpaceY( 8 )
	pnl:SetBorder( 10 )
	pnl:SetBaseSize( 32 )

	for i = 1, 10 do

		local btn = pnl:Add( "DButton" )
		btn:SetSize( 32, 32 )
		btn:SetText( i )

	end

	local btn_br = pnl:Add( "DButton" )
	btn_br:SetSize( 32, 32 )
	btn_br:SetText( "<br>" )
	btn_br.OwnLine = true

	for i = 1, 10 do

		local btn = pnl:Add( "DButton" )
		btn:SetSize( 32, 32 )
		btn:SetText( 10 + i )

	end

	PropertySheet:AddSheet( ClassName, pnl, nil, true, true )

end

derma.DefineControl( "DTileLayout", "", PANEL, "DDragBase" )
