' 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 Shape
        ' Graphical Shape, that is actually a collection of blocks

        ' All the shapes
        Public Enum ShapeType
            Blok
            Line
            LeftL
            RightL
            LeftS
            RightS
            T
        End Enum

        ' Directions to move
        Public Enum ShapeMove
            Up
            Down
            Left
            Right
        End Enum

        ' Directions to rotate
        Public Enum ShapeRotate
            ClockWise
            CounterClockWise
        End Enum

        ' All steps a rotation can be, before it's back in it's original position
        Public Enum ShapeRotateStep
            Step1
            Step2
            Step3
            Step4
        End Enum

        Private mX, mY, mWidth, mHeight, mBlockSize As Integer
        Private mColor As Color
        Private mShape As ShapeType
        Private mRotatingStep As ShapeRotateStep

        Private ShapeX(3) As Collections.Specialized.StringCollection
        Private ShapeB(3) As Graphics.BlockCollection

        '==== Events

        '==== Constructors

        Public Sub New(ByVal shape As ShapeType, ByVal blockSize As Integer)
            ' Create a new Shape and with size (blocksize) in pixels

            mShape = shape
            mBlockSize = blockSize

            ' I use strings to draw the shape,
            ' it was easier than calculation each block manualy.
            ' And also I draw them for all rotating steps.
            ' So each shape, are actually 4 shapes.

            ShapeX(0) = New Collections.Specialized.StringCollection()
            ShapeX(1) = New Collections.Specialized.StringCollection()
            ShapeX(2) = New Collections.Specialized.StringCollection()
            ShapeX(3) = New Collections.Specialized.StringCollection()

            Select Case mShape
                Case ShapeType.Line
                    mColor = Color.Cyan

                    ShapeX(0).Add("XXXX")
                    ShapeX(0).Add("    ")
                    ShapeX(0).Add("    ")
                    ShapeX(0).Add("    ")

                    ShapeX(1).Add("   X")
                    ShapeX(1).Add("   X")
                    ShapeX(1).Add("   X")
                    ShapeX(1).Add("   X")

                    ShapeX(2).Add("    ")
                    ShapeX(2).Add("    ")
                    ShapeX(2).Add("    ")
                    ShapeX(2).Add("XXXX")

                    ShapeX(3).Add("X   ")
                    ShapeX(3).Add("X   ")
                    ShapeX(3).Add("X   ")
                    ShapeX(3).Add("X   ")

                Case ShapeType.Blok
                    mColor = Color.Yellow

                    ShapeX(0).Add("XX")
                    ShapeX(0).Add("XX")

                    ShapeX(1).Add("XX")
                    ShapeX(1).Add("XX")

                    ShapeX(2).Add("XX")
                    ShapeX(2).Add("XX")

                    ShapeX(3).Add("XX")
                    ShapeX(3).Add("XX")

                Case ShapeType.RightL
                    mColor = Color.Orange

                    ShapeX(0).Add("XXX")
                    ShapeX(0).Add("  X")
                    ShapeX(0).Add("   ")

                    ShapeX(1).Add("  X")
                    ShapeX(1).Add("  X")
                    ShapeX(1).Add(" XX")

                    ShapeX(2).Add("   ")
                    ShapeX(2).Add("X  ")
                    ShapeX(2).Add("XXX")

                    ShapeX(3).Add("XX ")
                    ShapeX(3).Add("X  ")
                    ShapeX(3).Add("X  ")

                Case ShapeType.LeftL
                    mColor = Color.Blue

                    ShapeX(0).Add("XXX")
                    ShapeX(0).Add("X  ")
                    ShapeX(0).Add("   ")

                    ShapeX(1).Add(" XX")
                    ShapeX(1).Add("  X")
                    ShapeX(1).Add("  X")

                    ShapeX(2).Add("   ")
                    ShapeX(2).Add("  X")
                    ShapeX(2).Add("XXX")

                    ShapeX(3).Add("X  ")
                    ShapeX(3).Add("X  ")
                    ShapeX(3).Add("XX ")

                Case ShapeType.T
                    mColor = Color.Purple

                    ShapeX(0).Add("XXX")
                    ShapeX(0).Add(" X ")
                    ShapeX(0).Add("   ")

                    ShapeX(1).Add("  X")
                    ShapeX(1).Add(" XX")
                    ShapeX(1).Add("  X")

                    ShapeX(2).Add("   ")
                    ShapeX(2).Add(" X ")
                    ShapeX(2).Add("XXX")

                    ShapeX(3).Add("X  ")
                    ShapeX(3).Add("XX ")
                    ShapeX(3).Add("X  ")

                Case ShapeType.RightS
                    mColor = Color.Red

                    ShapeX(0).Add("XX ")
                    ShapeX(0).Add(" XX")
                    ShapeX(0).Add("   ")

                    ShapeX(1).Add("  X")
                    ShapeX(1).Add(" XX")
                    ShapeX(1).Add(" X ")

                    ShapeX(2).Add("   ")
                    ShapeX(2).Add("XX ")
                    ShapeX(2).Add(" XX")

                    ShapeX(3).Add(" X ")
                    ShapeX(3).Add("XX ")
                    ShapeX(3).Add("X  ")

                Case ShapeType.LeftS
                    mColor = Color.Green

                    ShapeX(0).Add(" XX")
                    ShapeX(0).Add("XX ")
                    ShapeX(0).Add("   ")

                    ShapeX(1).Add(" X ")
                    ShapeX(1).Add(" XX")
                    ShapeX(1).Add("  X")

                    ShapeX(2).Add("   ")
                    ShapeX(2).Add(" XX")
                    ShapeX(2).Add("XX ")

                    ShapeX(3).Add("X  ")
                    ShapeX(3).Add("XX ")
                    ShapeX(3).Add(" X ")

            End Select

            ' Create the shape with blocks instat of strings
            CreateShape()
        End Sub

        '==== Private Methods/Functions

        Private Sub CreateShape()
            ' Uses the StringCollections to create the Shapes in blocks

            Dim x, y, n As Integer
            Dim s As String

            ' Set width en height for the shape
            mWidth = ShapeX(0).Item(0).Length
            mHeight = ShapeX(0).Count

            ' Do the Shape building
            For n = 0 To 3
                ShapeB(n) = New Graphics.BlockCollection()

                For y = 0 To mHeight - 1
                    s = ShapeX(n).Item(y)

                    If s.Trim.Length > 0 Then
                        For x = 0 To mWidth - 1
                            If s.Substring(x, 1).ToUpper = "X" Then
                                ShapeB(n).Add(New Block(mX + (x * mBlockSize), mY + (y * mBlockSize), mBlockSize, mColor))
                            End If
                        Next
                    End If
                Next
            Next
        End Sub

        '==== Public Functions

        Public Function Clone() As Graphics.Shape
            ' Creates a copy

            Dim shc As New Graphics.Shape(mShape, mBlockSize)

            shc.SetPos(mX, mY)
            shc.RotatingStep = mRotatingStep

            Return shc
        End Function

        '==== Public Methodes

        Public Sub SetPos(ByVal x As Integer, ByVal y As Integer)
            ' Set the shape to the give position (x,y) in pixels

            Dim dX, dY, n, m As Integer

            ' Calculate the difference between the old and new position
            dX = x - mX
            dY = y - mY

            mX = x
            mY = y

            Dim bl As Graphics.Block
            Dim sh As Graphics.BlockCollection

            ' Move all blocks in the shapes to the new position
            For n = 0 To 3
                sh = ShapeB(n)

                For m = 0 To sh.Count - 1
                    bl = sh.Item(m)
                    If Not (bl Is Nothing) Then bl.SetPos(bl.X + dX, bl.Y + dY)
                Next
            Next
        End Sub

        Public Sub Move(ByVal direction As ShapeMove)
            ' Move the shape

            Select Case direction
                Case ShapeMove.Up
                    SetPos(mX, mY - mBlockSize)

                Case ShapeMove.Down
                    SetPos(mX, mY + mBlockSize)

                Case ShapeMove.Left
                    SetPos(mX - mBlockSize, mY)

                Case ShapeMove.Right
                    SetPos(mX + mBlockSize, mY)

            End Select
        End Sub

        Public Sub Rotate(ByVal direction As ShapeRotate)
            ' Rotate the shape

            Select Case direction
                Case ShapeRotate.CounterClockWise
                    Select Case mRotatingStep
                        Case ShapeRotateStep.Step1
                            mRotatingStep = ShapeRotateStep.Step4

                        Case ShapeRotateStep.Step2
                            mRotatingStep = ShapeRotateStep.Step1

                        Case ShapeRotateStep.Step3
                            mRotatingStep = ShapeRotateStep.Step2

                        Case ShapeRotateStep.Step4
                            mRotatingStep = ShapeRotateStep.Step3

                    End Select

                Case ShapeRotate.ClockWise
                    Select Case mRotatingStep
                        Case ShapeRotateStep.Step1
                            mRotatingStep = ShapeRotateStep.Step2

                        Case ShapeRotateStep.Step2
                            mRotatingStep = ShapeRotateStep.Step3

                        Case ShapeRotateStep.Step3
                            mRotatingStep = ShapeRotateStep.Step4

                        Case ShapeRotateStep.Step4
                            mRotatingStep = ShapeRotateStep.Step1

                    End Select
            End Select
        End Sub

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

            Dim sh As Graphics.BlockCollection
            Dim bl As Graphics.Block
            Dim n As Integer

            ' Draw all blocks in the shape
            sh = ShapeB(mRotatingStep)
            For n = 0 To sh.Count - 1
                bl = sh.Item(n)
                If Not (bl Is Nothing) Then bl.Draw(graph)
            Next
        End Sub

        '==== Properties

        Public Property RotatingStep() As ShapeRotateStep
            Get
                Return mRotatingStep
            End Get
            Set(ByVal Value As ShapeRotateStep)
                mRotatingStep = Value
            End Set
        End Property

        Public ReadOnly Property Shape() As ShapeType
            Get
                Return mShape
            End Get
        End Property

        Public ReadOnly Property Item(ByVal index As Integer) As Graphics.Block
            Get
                Return ShapeB(mRotatingStep).Item(index)
            End Get
        End Property

        Public ReadOnly Property Count() As Integer
            Get
                If ShapeB Is Nothing Then
                    Return 0
                Else
                    Return ShapeB(mRotatingStep).Count
                End If
            End Get
        End Property

        Public ReadOnly Property Width() As Integer
            Get
                Return mWidth
            End Get
        End Property

        Public ReadOnly Property Height() As Integer
            Get
                Return mHeight
            End Get
        End Property

        Public ReadOnly Property X() As Integer
            Get
                Return mX
            End Get
        End Property

        Public ReadOnly Property Y() As Integer
            Get
                Return mY
            End Get
        End Property

        Public ReadOnly Property BlockColor() As Color
            Get
                Return mColor
            End Get
        End Property

        Public ReadOnly Property BlockSize() As Integer
            Get
                Return mBlockSize
            End Get
        End Property

    End Class

End Namespace
