' D. de Haas
' Amsterdam, Netherlands
' 29 October 2002
' ddhadam@yahoo.com

Option Explicit On 
Option Strict On

Imports System
Imports System.Drawing

Namespace Graphics

    Public Class PlayField
        ' Graphical PlayField, that is actually a collection of lines

        Private mX, mY, mWidth, mHeight, mBlockSize As Integer
        Private mLines As Graphics.LineCollection

        '==== Events

        Public Event LinesCleared(ByVal count As Integer)

        '==== Constructors

        Public Sub New(ByVal x As Integer, ByVal y As Integer, ByVal blockSize As Integer, ByVal widthBlocks As Integer, ByVal heightBlocks As Integer)
            ' Create a new PlayField on postition (x,y) and (blocksize) in pixels and width (widthBlocks, heightBlocks) in blocks

            mX = x
            mY = y
            mBlockSize = blockSize
            mWidth = widthBlocks
            mHeight = heightBlocks

            ' Lines from Bottom to Top
            ' Bottom: index = 0
            ' Top:    index = Height-1
            mLines = New Graphics.LineCollection()

            Dim n As Integer

            ' Add lines to the playfield
            For n = 0 To mHeight - 1
                mLines.Add(New Graphics.Line(mX, mY + ((mHeight - 1 - n) * mBlockSize), mBlockSize, mWidth))
            Next
        End Sub

        '==== Private Methods/Functions

        Private Sub SortLines()
            ' Remove all empty lines from the playfield

            ' Create a new line collection
            Dim tmpLines As New Graphics.LineCollection()

            Dim l As Graphics.Line
            Dim n, m As Integer

            ' Check all lines 
            For n = 0 To mLines.Count - 1
                l = mLines.Item(n)

                ' Lines that aren't empty are added to the new collection
                If Not (l.Status = Line.StatusType.Empty) Then
                    Dim lc As Graphics.Line

                    lc = l.Clone
                    lc.SetPos(lc.X, mY + ((mHeight - 1 - m) * mBlockSize))

                    tmpLines.Insert(m, lc)

                    m += 1
                End If
            Next

            ' For all lines that are skipped, add an empty one the top
            If m > 0 Then
                For n = m To mHeight - 1
                    tmpLines.Insert(n, New Line(mX, mY + ((mHeight - 1 - n) * mBlockSize), mBlockSize, mWidth))
                Next
            End If

            ' Set the playfield lines to the new collection
            mLines = tmpLines
        End Sub

        '==== Public Functions

        Public Function Validate(ByVal shape As Shape) As Boolean
            ' Checks if a Shape is inside the playfield boundaries
            ' and not in collesion with another block

            Dim bl As Graphics.Block
            Dim indexLine, indexBlock, n As Integer

            ' Check all blocks in the shape
            For n = 0 To shape.Count - 1
                bl = shape.Item(n)

                ' Calculate the position of the block
                indexBlock = (bl.X - mX) \ mBlockSize
                indexLine = mHeight - 1 - ((bl.Y - mY) \ mBlockSize)

                ' Check if shape is inside the playfield
                If indexBlock < 0 Then Return False
                If indexLine < 0 Then Return False
                If indexBlock >= mWidth Then Return False
                If indexLine >= mHeight Then Return False

                ' Check for collision with another block
                If Not (mLines.Item(indexLine).Item(indexBlock) Is Nothing) Then Return False
            Next

            ' Shape is valide
            Return True
        End Function

        '==== Public Methodes

        Public Sub Draw(ByRef graph As System.Drawing.Graphics)
            ' Draws the playfield

            Dim l As Graphics.Line
            Dim n As Integer

            ' Draw the playfield boundaries
            graph.DrawRectangle(New Pen(Color.Gray), mX, mY, mWidth * mBlockSize, mHeight * mBlockSize)

            ' Draw all lines in the playfield
            For n = 0 To mLines.Count - 1
                l = mLines.Item(n)
                If Not (l Is Nothing) Then l.Draw(graph)
            Next
        End Sub

        Public Sub AddShape(ByVal shape As Graphics.Shape)
            ' Add a all blocks of the shape to the playfield

            Dim bl As Graphics.Block
            Dim ln As Graphics.Line
            Dim indexLine, indexBlock, n, m As Integer

            ' Add shape to the playfield
            For n = 0 To shape.Count - 1
                bl = shape.Item(n)

                ' Calculate the position of the block
                indexBlock = (bl.X - mX) \ mBlockSize
                indexLine = mHeight - 1 - ((bl.Y - mY) \ mBlockSize)

                ' Set Line
                ln = mLines.Item(indexLine)

                ' Add Block to the line
                ln.Insert(indexBlock, bl)

                ' Check if line is full, if so, clear them
                If ln.Status = Line.StatusType.Full Then
                    ln.Clear()
                    m += 1
                End If
            Next

            ' Check if the were lines full, if so, remove them from the playfield
            If m > 0 Then
                SortLines()

                ' Raise event, that there were (m) lines cleared
                RaiseEvent LinesCleared(m)
            End If
        End Sub

        '==== Properties

    End Class

End Namespace
