' RoomView.vb

Imports System
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Windows.Forms
Imports System.Collections.Generic
Imports System.Linq
Imports System.IO
Imports System.Xml.Serialization

Public Class RoomView
    Inherits Form

    ' Constants for grid dimensions and indentation
    Private Const INDENT As Integer = 20
    Private Const SQCOUNTX As Integer = 15
    Private Const SQCOUNTY As Integer = 11
    Private Const WALL_THICKNESS As Integer = 10

    ' Instance of GridRenderer
    Private gridRenderer As New GridRenderer()

    ' Properties to hold game data
    Private GameObjects As New List(Of GameObject)()

    ' Mouse state variables
    Private isRightMouseDown As Boolean = False
    Private isLeftMouseDown As Boolean = False
    Private isMouseInsideGrid As Boolean = False

    ' Variables for highlighting
    Private highlightedX As Integer
    Private highlightedY As Integer
    Private highlightedWallX As Boolean = False
    Private highlightedWallY As Boolean = False
    Private highlightColor As Color = Color.Black
    Private highlightTimer As Timer

    ' Variable to track the cell being hovered over during drag-and-drop
    Private dragOverCell As Point? = Nothing

    ' List to hold animated images
    Private animatedImages As New List(Of Image)()

    ' Constructor
    Public Sub New()
        ' This call is required by the designer.
        InitializeComponent()

        ' Initialize the highlight timer
        highlightTimer = New Timer()
        highlightTimer.Interval = 500 ' Flash every 500 milliseconds
        AddHandler highlightTimer.Tick, AddressOf HighlightTimer_Tick
        highlightTimer.Start()

        ' Use Application.Idle event to update frames
        AddHandler Application.Idle, AddressOf OnApplicationIdle

        ' Ensure double buffering to reduce flickering
        Me.DoubleBuffered = True

        ' Attach event handlers to PicGame
        AddHandler Me.PicGame.Paint, AddressOf PicGame_Paint
        AddHandler Me.PicGame.MouseMove, AddressOf PicGame_MouseMove
        AddHandler Me.PicGame.MouseDown, AddressOf PicGame_MouseDown
        AddHandler Me.PicGame.MouseUp, AddressOf PicGame_MouseUp
        AddHandler Me.PicGame.DragEnter, AddressOf PicGame_DragEnter
        AddHandler Me.PicGame.DragOver, AddressOf PicGame_DragOver
        AddHandler Me.PicGame.DragDrop, AddressOf PicGame_DragDrop
        AddHandler Me.PicGame.DragLeave, AddressOf PicGame_DragLeave
        Me.PicGame.AllowDrop = True

        ' Event handlers for menu items
        AddHandler btnRandom.Click, AddressOf btnRandom_Click
        AddHandler mnuNew.Click, AddressOf btnNew_Click
        AddHandler mnuSave.Click, AddressOf btnSave_Click
        AddHandler mnuSaveAs.Click, AddressOf btnSaveAs_Click
        AddHandler mnuLoad.Click, AddressOf btnLoad_Click

        ' Event handlers for other controls
        AddHandler lstHatchstyles.SelectedIndexChanged, AddressOf lstHatchStyle_SelectedIndexChanged
        AddHandler lstPremades.SelectedIndexChanged, AddressOf lstPremades_SelectedIndexChanged
        AddHandler picBaddy1.MouseDown, AddressOf picBaddy1_MouseDown

        ' Set the form's properties
        Me.Text = "Room View"
        Me.KeyPreview = True ' To capture keyboard events at the form level

        ' Additional initialization
        InitializeHatchStyles()
        LoadPremades()

        ' Initialize color boxes event handlers
        InitializeColorBoxes()
    End Sub

    ' Initialize hatch styles in lstHatchstyles
    Private Sub InitializeHatchStyles()
        lstHatchstyles.Items.Clear()
        For Each styleName In [Enum].GetNames(GetType(HatchStyle))
            lstHatchstyles.Items.Add(styleName)
        Next
        lstHatchstyles.SelectedItem = gridRenderer.wallsHatchStyle.ToString()
    End Sub

    ' Load premade layouts
    Private Sub LoadPremades()
        Dim premadesDirectory As String = Path.Combine(Application.StartupPath, "Premades")
        If Directory.Exists(premadesDirectory) Then
            Dim files = Directory.GetFiles(premadesDirectory, "*.layout") ' Assuming .layout extension
            lstPremades.Items.Clear()
            For Each file In files
                lstPremades.Items.Add(Path.GetFileNameWithoutExtension(file))
            Next
        End If
    End Sub

    ' Initialize color boxes event handlers
    Private Sub InitializeColorBoxes()
        ' Attach Click event handler to color boxes col1 to col98
        For i As Integer = 1 To 98
            Dim controlName As String = "col" & i.ToString()
            Dim colorBoxes As Control() = Me.Controls.Find(controlName, True)
            If colorBoxes.Length > 0 Then
                Dim colorBox As Control = colorBoxes(0)
                AddHandler colorBox.Click, AddressOf ColorBox_Click
            End If
        Next
    End Sub

    ' Event handler for color box clicks
    Private Sub ColorBox_Click(sender As Object, e As EventArgs)
        Dim colorBox As Control = DirectCast(sender, Control)
        Dim selectedColor As Color = colorBox.BackColor

        Dim boxNumber As Integer
        If Integer.TryParse(colorBox.Name.Substring(3), boxNumber) Then
            If boxNumber >= 1 AndAlso boxNumber <= 48 Then
                ' Handle hatch style color 1
                gridRenderer.wallsColor1 = selectedColor
            ElseIf boxNumber >= 51 AndAlso boxNumber <= 98 Then
                ' Handle hatch style color 2
                gridRenderer.wallsColor2 = selectedColor
            End If
            Me.PicGame.Invalidate()
        End If
    End Sub

    ' Event handler for the highlight timer tick
    Private Sub HighlightTimer_Tick(sender As Object, e As EventArgs)
        ' Toggle the highlight color between black and white
        If highlightColor = Color.Black Then
            highlightColor = Color.White
        Else
            highlightColor = Color.Black
        End If
        Me.PicGame.Invalidate()
    End Sub

    ' Event handler for Application.Idle event
    Private Sub OnApplicationIdle(sender As Object, e As EventArgs)
        For Each img In animatedImages
            ImageAnimator.UpdateFrames(img)
        Next
        Me.PicGame.Invalidate()
    End Sub

    ' The Paint event handler for PicGame
    Private Sub PicGame_Paint(sender As Object, e As PaintEventArgs)
        ' Calculate the square size based on the size of the PictureBox
        gridRenderer.CalculateSquareSizes(Me.PicGame.ClientSize.Width, Me.PicGame.ClientSize.Height, SQCOUNTX, SQCOUNTY, WALL_THICKNESS)

        ' Set SmoothingMode to None to prevent gaps due to anti-aliasing
        e.Graphics.SmoothingMode = SmoothingMode.None

        ' Draw the grid
        gridRenderer.DrawGrid(e.Graphics, Me.PicGame.ClientSize.Width, Me.PicGame.ClientSize.Height, INDENT, SQCOUNTX, SQCOUNTY, WALL_THICKNESS)

        ' Draw game objects
        If GameObjects IsNot Nothing Then
            For Each obj In GameObjects
                DrawGameObject(e.Graphics, obj)
            Next
        End If

        ' Draw highlights
        DrawHighlight(e.Graphics)

        ' Draw drag-over highlight
        If dragOverCell.HasValue Then
            DrawDragOverHighlight(e.Graphics, dragOverCell.Value)
        End If
    End Sub

    ' Method to draw a game object on the grid
    Private Sub DrawGameObject(g As Graphics, obj As GameObject)
        ' Update the frame if the image is animated
        If ImageAnimator.CanAnimate(obj.Image) Then
            ImageAnimator.UpdateFrames(obj.Image)
        End If

        Dim x As Integer = INDENT + obj.CellX * (gridRenderer.SQSizeX + WALL_THICKNESS) + WALL_THICKNESS \ 2
        Dim y As Integer = INDENT + obj.CellY * (gridRenderer.SQSizeY + WALL_THICKNESS) + WALL_THICKNESS \ 2

        Dim destRect As New Rectangle(x, y, gridRenderer.SQSizeX, gridRenderer.SQSizeY)
        g.DrawImage(obj.Image, destRect)
    End Sub

    ' Method to draw the highlight
    Private Sub DrawHighlight(g As Graphics)
        If Not isMouseInsideGrid Then
            Return
        End If

        Using highlightPen As New Pen(highlightColor, 2)
            highlightPen.DashStyle = DashStyle.Dash

            If highlightedWallX Then
                ' Vertical wall
                Dim x As Integer = INDENT + highlightedX * (gridRenderer.SQSizeX + WALL_THICKNESS) - WALL_THICKNESS \ 2
                Dim y As Integer = INDENT + highlightedY * (gridRenderer.SQSizeY + WALL_THICKNESS) + WALL_THICKNESS \ 2
                Dim highlightRect As New Rectangle(x, y, WALL_THICKNESS, gridRenderer.SQSizeY)
                g.DrawRectangle(highlightPen, highlightRect)
            ElseIf highlightedWallY Then
                ' Horizontal wall
                Dim x As Integer = INDENT + highlightedX * (gridRenderer.SQSizeX + WALL_THICKNESS) + WALL_THICKNESS \ 2
                Dim y As Integer = INDENT + highlightedY * (gridRenderer.SQSizeY + WALL_THICKNESS) - WALL_THICKNESS \ 2
                Dim highlightRect As New Rectangle(x, y, gridRenderer.SQSizeX, WALL_THICKNESS)
                g.DrawRectangle(highlightPen, highlightRect)
            Else
                ' Square
                Dim x As Integer = INDENT + highlightedX * (gridRenderer.SQSizeX + WALL_THICKNESS) + WALL_THICKNESS \ 2
                Dim y As Integer = INDENT + highlightedY * (gridRenderer.SQSizeY + WALL_THICKNESS) + WALL_THICKNESS \ 2
                Dim highlightRect As New Rectangle(x, y, gridRenderer.SQSizeX, gridRenderer.SQSizeY)
                g.DrawRectangle(highlightPen, highlightRect)
            End If
        End Using
    End Sub

    ' Method to draw drag-over highlight
    Private Sub DrawDragOverHighlight(g As Graphics, cell As Point)
        Dim x As Integer = INDENT + cell.X * (gridRenderer.SQSizeX + WALL_THICKNESS) + WALL_THICKNESS \ 2
        Dim y As Integer = INDENT + cell.Y * (gridRenderer.SQSizeY + WALL_THICKNESS) + WALL_THICKNESS \ 2

        Dim highlightRect As New Rectangle(x, y, gridRenderer.SQSizeX, gridRenderer.SQSizeY)

        Using highlightPen As New Pen(Color.Red, 2)
            highlightPen.DashStyle = DashStyle.Dash
            g.DrawRectangle(highlightPen, highlightRect)
        End Using
    End Sub

    ' Mouse event handlers
    Private Sub PicGame_MouseMove(sender As Object, e As MouseEventArgs)
        ' Initialize as False at the start of the method
        isMouseInsideGrid = False

        ' Adjust for indentation
        Dim mouseX As Integer = e.X - INDENT
        Dim mouseY As Integer = e.Y - INDENT

        ' Early exit if the mouse is outside the grid area
        If mouseX < 0 OrElse mouseY < 0 Then
            Exit Sub
        End If

        Dim cellSizeX As Integer = gridRenderer.SQSizeX + WALL_THICKNESS
        Dim cellSizeY As Integer = gridRenderer.SQSizeY + WALL_THICKNESS

        Dim cellX As Integer = mouseX \ cellSizeX
        Dim cellY As Integer = mouseY \ cellSizeY

        If cellX >= SQCOUNTX OrElse cellY >= SQCOUNTY Then
            Exit Sub
        End If

        Dim offsetX As Integer = mouseX Mod cellSizeX
        Dim offsetY As Integer = mouseY Mod cellSizeY

        highlightedWallX = False
        highlightedWallY = False

        If offsetX < WALL_THICKNESS Then
            ' Vertical wall
            highlightedWallX = True
            highlightedX = cellX
            highlightedY = cellY
            isMouseInsideGrid = True

            ' Wall modification code
            If isRightMouseDown OrElse isLeftMouseDown Then
                If isRightMouseDown Then
                    If gridRenderer.WallX(cellX, cellY) Then
                        gridRenderer.WallX(cellX, cellY) = False
                        Me.PicGame.Invalidate()
                    End If
                ElseIf isLeftMouseDown Then
                    If Not gridRenderer.WallX(cellX, cellY) Then
                        gridRenderer.WallX(cellX, cellY) = True
                        Me.PicGame.Invalidate()
                    End If
                End If
            End If

        ElseIf offsetY < WALL_THICKNESS Then
            ' Horizontal wall
            highlightedWallY = True
            highlightedX = cellX
            highlightedY = cellY
            isMouseInsideGrid = True

            ' Wall modification code
            If isRightMouseDown OrElse isLeftMouseDown Then
                If isRightMouseDown Then
                    If gridRenderer.WallY(cellX, cellY) Then
                        gridRenderer.WallY(cellX, cellY) = False
                        Me.PicGame.Invalidate()
                    End If
                ElseIf isLeftMouseDown Then
                    If Not gridRenderer.WallY(cellX, cellY) Then
                        gridRenderer.WallY(cellX, cellY) = True
                        Me.PicGame.Invalidate()
                    End If
                End If
            End If

        ElseIf offsetX >= WALL_THICKNESS AndAlso offsetX < cellSizeX AndAlso offsetY >= WALL_THICKNESS AndAlso offsetY < cellSizeY Then
            ' Inside the square
            highlightedX = cellX
            highlightedY = cellY
            isMouseInsideGrid = True

            ' Handle right-click dragging over game objects to remove them
            If isRightMouseDown Then
                ' Use a simple For Each loop if FirstOrDefault is not available
                Dim objToRemove As GameObject = Nothing
                For Each obj In GameObjects
                    If obj.CellX = cellX AndAlso obj.CellY = cellY Then
                        objToRemove = obj
                        Exit For
                    End If
                Next

                If objToRemove IsNot Nothing Then
                    ' Remove the object from the GameObjects list
                    GameObjects.Remove(objToRemove)

                    ' Remove from animatedImages if necessary
                    If animatedImages.Contains(objToRemove.Image) Then
                        animatedImages.Remove(objToRemove.Image)
                        ImageAnimator.StopAnimate(objToRemove.Image, AddressOf OnFrameChanged)
                    End If

                    Me.PicGame.Invalidate()
                End If
            End If

        Else
            Exit Sub
        End If

        ' Redraw to update the highlight
        Me.PicGame.Invalidate()
    End Sub

    Private Sub PicGame_MouseDown(sender As Object, e As MouseEventArgs)
        If e.Button = MouseButtons.Right Then
            isRightMouseDown = True
        ElseIf e.Button = MouseButtons.Left Then
            isLeftMouseDown = True
        End If
    End Sub

    Private Sub PicGame_MouseUp(sender As Object, e As MouseEventArgs)
        If e.Button = MouseButtons.Right Then
            isRightMouseDown = False
        ElseIf e.Button = MouseButtons.Left Then
            isLeftMouseDown = False
        End If
    End Sub

    ' Drag-and-drop event handlers
    Private Sub PicGame_DragEnter(sender As Object, e As DragEventArgs)
        If e.Data.GetDataPresent(GetType(Bitmap)) OrElse e.Data.GetDataPresent(GetType(Image)) Then
            e.Effect = DragDropEffects.Copy
        Else
            e.Effect = DragDropEffects.None
        End If
    End Sub

    Private Sub PicGame_DragOver(sender As Object, e As DragEventArgs)
        Dim clientPoint As Point = Me.PicGame.PointToClient(New Point(e.X, e.Y))
        Dim cell = GetCellFromPoint(clientPoint)
        If cell.HasValue AndAlso IsFloorTile(cell.Value.X, cell.Value.Y) Then
            dragOverCell = cell
            e.Effect = DragDropEffects.Copy
        Else
            dragOverCell = Nothing
            e.Effect = DragDropEffects.None
        End If
        Me.PicGame.Invalidate()
    End Sub

    Private Sub PicGame_DragDrop(sender As Object, e As DragEventArgs)
        Dim clientPoint As Point = Me.PicGame.PointToClient(New Point(e.X, e.Y))
        Dim cell = GetCellFromPoint(clientPoint)
        If cell.HasValue AndAlso IsFloorTile(cell.Value.X, cell.Value.Y) Then
            If Not IsCellOccupied(cell.Value.X, cell.Value.Y) Then
                Dim img As Image = CType(e.Data.GetData(GetType(Bitmap)), Image)
                AddGameObject(img, cell.Value.X, cell.Value.Y)
                Me.PicGame.Invalidate()
            Else
                MessageBox.Show("This tile is already occupied.")
            End If
        Else
            MessageBox.Show("You can only place objects on floor tiles.")
        End If
        dragOverCell = Nothing
    End Sub

    Private Sub PicGame_DragLeave(sender As Object, e As EventArgs)
        dragOverCell = Nothing
        Me.PicGame.Invalidate()
    End Sub

    ' Helper methods
    Private Function GetCellFromPoint(point As Point) As Point?
        Dim mouseX As Integer = point.X - INDENT
        Dim mouseY As Integer = point.Y - INDENT

        If mouseX < 0 OrElse mouseY < 0 Then Return Nothing

        Dim cellSizeX As Integer = gridRenderer.SQSizeX + WALL_THICKNESS
        Dim cellSizeY As Integer = gridRenderer.SQSizeY + WALL_THICKNESS

        Dim cellX As Integer = mouseX \ cellSizeX
        Dim cellY As Integer = mouseY \ cellSizeY

        If cellX >= SQCOUNTX OrElse cellY >= SQCOUNTY Then Return Nothing

        Dim offsetX As Integer = mouseX Mod cellSizeX
        Dim offsetY As Integer = mouseY Mod cellSizeY

        If offsetX >= WALL_THICKNESS AndAlso offsetY >= WALL_THICKNESS Then
            Return New Point(cellX, cellY)
        End If

        Return Nothing
    End Function

    Private Function IsFloorTile(cellX As Integer, cellY As Integer) As Boolean
        ' Since we don't have a GameMap, assume tiles without walls are floor
        Return Not gridRenderer.IsCellBlocked(cellX, cellY)
    End Function

    Private Function IsCellOccupied(cellX As Integer, cellY As Integer) As Boolean
        For Each obj As GameObject In GameObjects
            If obj.CellX = cellX AndAlso obj.CellY = cellY Then
                Return True
            End If
        Next
        Return False
    End Function

    Private Sub AddGameObject(img As Image, cellX As Integer, cellY As Integer)
        Dim imageTag As String = If(img.Tag IsNot Nothing, img.Tag.ToString(), "Unknown")
        Dim obj As New GameObject(img, cellX, cellY, imageTag)
        GameObjects.Add(obj)

        ' If the image is animated, and not already being animated
        If ImageAnimator.CanAnimate(img) AndAlso Not animatedImages.Contains(img) Then
            animatedImages.Add(img)
            ImageAnimator.Animate(img, AddressOf OnFrameChanged)
        End If
    End Sub

    ' Event handler for animation frame changes
    Private Sub OnFrameChanged(sender As Object, e As EventArgs)
        Me.PicGame.Invalidate()
    End Sub

    ' Optional: Override OnResize to handle form resizing
    Protected Overrides Sub OnResize(e As EventArgs)
        MyBase.OnResize(e)
        Me.PicGame.Invalidate()
    End Sub

    ' Button event handlers

    Private Sub btnRandom_Click(sender As Object, e As EventArgs)
        ' Example: Randomize walls
        Dim rnd As New Random()
        For x As Integer = 0 To gridRenderer.WallX.GetLength(0) - 1
            For y As Integer = 0 To gridRenderer.WallX.GetLength(1) - 1
                gridRenderer.WallX(x, y) = rnd.NextDouble() >= 0.5
            Next
        Next
        For x As Integer = 0 To gridRenderer.WallY.GetLength(0) - 1
            For y As Integer = 0 To gridRenderer.WallY.GetLength(1) - 1
                gridRenderer.WallY(x, y) = rnd.NextDouble() >= 0.5
            Next
        Next
        Me.PicGame.Invalidate()
    End Sub

    Private Sub btnNew_Click(sender As Object, e As EventArgs)
        ' Reset the grid and game objects
        gridRenderer = New GridRenderer()
        GameObjects.Clear()
        Me.PicGame.Invalidate()
    End Sub

    Private Sub btnSave_Click(sender As Object, e As EventArgs)
        ' Save the current grid and game objects
        SaveLayout("default.layout")
    End Sub

    Private Sub btnSaveAs_Click(sender As Object, e As EventArgs)
        ' Save the layout with a specified name
        Using saveDlg As New SaveFileDialog()
            saveDlg.Filter = "Layout Files (*.layout)|*.layout"
            If saveDlg.ShowDialog() = DialogResult.OK Then
                SaveLayout(saveDlg.FileName)
            End If
        End Using
    End Sub

    Private Sub btnLoad_Click(sender As Object, e As EventArgs)
        ' Load a layout from file
        Using openDlg As New OpenFileDialog()
            openDlg.Filter = "Layout Files (*.layout)|*.layout"
            If openDlg.ShowDialog() = DialogResult.OK Then
                LoadLayout(openDlg.FileName)
            End If
        End Using
    End Sub

    Private Sub SaveLayout(fileName As String)
        ' Implement your serialization logic here
        ' For simplicity, let's serialize the wall arrays and game objects
        Dim layout As New LayoutData With {
            .WallX = gridRenderer.WallX,
            .WallY = gridRenderer.WallY,
            .GameObjects = GameObjects
        }
        Dim serializer As New XmlSerializer(GetType(LayoutData))
        Using fs As New FileStream(fileName, FileMode.Create)
            serializer.Serialize(fs, layout)
        End Using
    End Sub

    Private Sub LoadLayout(fileName As String)
        ' Implement your deserialization logic here
        Dim serializer As New XmlSerializer(GetType(LayoutData))
        Using fs As New FileStream(fileName, FileMode.Open)
            Dim layout As LayoutData = CType(serializer.Deserialize(fs), LayoutData)
            gridRenderer.WallX = layout.WallX
            gridRenderer.WallY = layout.WallY
            GameObjects = layout.GameObjects

            ' Load images for GameObjects
            For Each obj In GameObjects
                If Not String.IsNullOrEmpty(obj.ImageFilePath) AndAlso File.Exists(obj.ImageFilePath) Then
                    obj.Image = Image.FromFile(obj.ImageFilePath)
                    obj.Image.Tag = obj.ImageFilePath
                End If
            Next

            Me.PicGame.Invalidate()
        End Using
    End Sub

    ' Class to hold layout data
    <Serializable>
    Public Class LayoutData
        Public WallX(,) As Boolean
        Public WallY(,) As Boolean
        Public GameObjects As List(Of GameObject)

        Public Sub New()
            ' Parameterless constructor needed for deserialization
        End Sub
    End Class

    ' lstHatchstyles event handler
    Private Sub lstHatchStyle_SelectedIndexChanged(sender As Object, e As EventArgs)
        Dim selectedStyleName As String = lstHatchstyles.SelectedItem.ToString()
        Dim selectedStyle As HatchStyle = CType([Enum].Parse(GetType(HatchStyle), selectedStyleName), HatchStyle)
        gridRenderer.wallsHatchStyle = selectedStyle
        Me.PicGame.Invalidate()
    End Sub

    ' lstPremades event handler
    Private Sub lstPremades_SelectedIndexChanged(sender As Object, e As EventArgs)
        Dim selectedPremade As String = lstPremades.SelectedItem.ToString()
        Dim fileName As String = Path.Combine(Application.StartupPath, "Premades", selectedPremade & ".layout")
        If File.Exists(fileName) Then
            LoadLayout(fileName)
        End If
    End Sub

    ' picBaddy1 MouseDown event handler for drag-and-drop
    Private Sub picBaddy1_MouseDown(sender As Object, e As MouseEventArgs)
        If e.Button = MouseButtons.Left Then
            picBaddy1.DoDragDrop(picBaddy1.Image, DragDropEffects.Copy)
        End If
    End Sub

End Class

' Supporting Enums and Classes

<Serializable>
Public Class GameObject
    ' Exclude the Image property from serialization
    <XmlIgnore>
    Public Property Image As Image

    Public Property ImageFilePath As String
    Public Property CellX As Integer
    Public Property CellY As Integer
    Public Property ImageTag As String

    Public Sub New()
        ' Parameterless constructor needed for deserialization
    End Sub

    Public Sub New(img As Image, x As Integer, y As Integer, imgTag As String)
        Me.Image = img
        Me.CellX = x
        Me.CellY = y
        Me.ImageTag = imgTag
        ' Store image file path
        If img.Tag IsNot Nothing Then
            Me.ImageFilePath = img.Tag.ToString()
        Else
            Me.ImageFilePath = String.Empty
        End If
    End Sub
End Class

<Serializable>
Public Class GridRenderer
    ' Fields for wall arrays
    Public WallX(,) As Boolean
    Public WallY(,) As Boolean

    ' Properties for hatch styles and colors
    Public Property wallsHatchStyle As HatchStyle = HatchStyle.Cross
    Public Property wallsColor1 As Color = Color.Gray
    Public Property wallsColor2 As Color = Color.DarkGray
    Public Property floorsHatchStyle As HatchStyle = HatchStyle.SmallCheckerBoard
    Public Property floorsColor1 As Color = Color.LightGray
    Public Property floorsColor2 As Color = Color.White

    ' Calculated square sizes
    Public SQSizeX As Integer
    Public SQSizeY As Integer

    ' Constructor
    Public Sub New()
        ' Initialize the wall arrays
        WallX = New Boolean(15, 11) {}
        WallY = New Boolean(15, 11) {}

        ' Set all walls to true (walls exist everywhere by default)
        For i As Integer = 0 To WallX.GetLength(0) - 1
            For j As Integer = 0 To WallX.GetLength(1) - 1
                WallX(i, j) = True
            Next
        Next

        For i As Integer = 0 To WallY.GetLength(0) - 1
            For j As Integer = 0 To WallY.GetLength(1) - 1
                WallY(i, j) = True
            Next
        Next
    End Sub

    ' Method to calculate square sizes
    Public Sub CalculateSquareSizes(clientWidth As Integer, clientHeight As Integer, SQCOUNTX As Integer, SQCOUNTY As Integer, WALL_THICKNESS As Integer)
        SQSizeX = (clientWidth - 2 * 20 - (SQCOUNTX + 1) * WALL_THICKNESS) \ SQCOUNTX
        SQSizeY = (clientHeight - 2 * 20 - (SQCOUNTY + 1) * WALL_THICKNESS) \ SQCOUNTY
    End Sub

    ' Method to draw the grid
    Public Sub DrawGrid(g As Graphics, clientWidth As Integer, clientHeight As Integer, INDENT As Integer, SQCOUNTX As Integer, SQCOUNTY As Integer, WALL_THICKNESS As Integer)
        ' Drawing logic for walls and floors
        Dim xOrigin As Integer = INDENT
        Dim yOrigin As Integer = INDENT

        ' Draw floors
        For x As Integer = 0 To SQCOUNTX - 1
            For y As Integer = 0 To SQCOUNTY - 1
                Dim floorRect As New Rectangle(xOrigin + x * (SQSizeX + WALL_THICKNESS) + WALL_THICKNESS \ 2,
                                               yOrigin + y * (SQSizeY + WALL_THICKNESS) + WALL_THICKNESS \ 2,
                                               SQSizeX,
                                               SQSizeY)

                Using floorBrush As New HatchBrush(floorsHatchStyle, floorsColor1, floorsColor2)
                    g.FillRectangle(floorBrush, floorRect)
                End Using
            Next
        Next

        ' Draw walls (vertical)
        For x As Integer = 0 To SQCOUNTX
            For y As Integer = 0 To SQCOUNTY - 1
                If WallX(x, y) Then
                    Dim wallRect As New Rectangle(xOrigin + x * (SQSizeX + WALL_THICKNESS) - WALL_THICKNESS \ 2,
                                                  yOrigin + y * (SQSizeY + WALL_THICKNESS) + WALL_THICKNESS \ 2,
                                                  WALL_THICKNESS,
                                                  SQSizeY)

                    Using wallBrush As New HatchBrush(wallsHatchStyle, wallsColor1, wallsColor2)
                        g.FillRectangle(wallBrush, wallRect)
                    End Using
                End If
            Next
        Next

        ' Draw walls (horizontal)
        For x As Integer = 0 To SQCOUNTX - 1
            For y As Integer = 0 To SQCOUNTY
                If WallY(x, y) Then
                    Dim wallRect As New Rectangle(xOrigin + x * (SQSizeX + WALL_THICKNESS) + WALL_THICKNESS \ 2,
                                                  yOrigin + y * (SQSizeY + WALL_THICKNESS) - WALL_THICKNESS \ 2,
                                                  SQSizeX,
                                                  WALL_THICKNESS)

                    Using wallBrush As New HatchBrush(wallsHatchStyle, wallsColor1, wallsColor2)
                        g.FillRectangle(wallBrush, wallRect)
                    End Using
                End If
            Next
        Next
    End Sub

    ' Method to determine if a cell is blocked
    Public Function IsCellBlocked(x As Integer, y As Integer) As Boolean
        If WallX(x, y) OrElse WallX(x + 1, y) OrElse WallY(x, y) OrElse WallY(x, y + 1) Then
            Return True
        End If
        Return False
    End Function
End Class

Module DataPath
    Public Function Path() As String
        Path = Application.StartupPath.ToLower().Replace("\enigma\bin\debug\net8.0-windows", "\data\")
        Return path
    End Function
End Module


Severity	Code	Description	Project	File	Line	Suppression State
Error (active)	BC30456	'Combine' is not a member of 'String'.	Enigma	D:\01 - Grags\Visual Studio\Enigma\Enigma\RoomView.vb	109	
Error (active)	BC30456	'Combine' is not a member of 'String'.	Enigma	D:\01 - Grags\Visual Studio\Enigma\Enigma\RoomView.vb	109	
Error (active)	BC30456	'GetFileNameWithoutExtension' is not a member of 'String'.	Enigma	D:\01 - Grags\Visual Studio\Enigma\Enigma\RoomView.vb	114	
Error (active)	BC30456	'GetFileNameWithoutExtension' is not a member of 'String'.	Enigma	D:\01 - Grags\Visual Studio\Enigma\Enigma\RoomView.vb	114	
Error (active)	BC30456	'Combine' is not a member of 'String'.	Enigma	D:\01 - Grags\Visual Studio\Enigma\Enigma\RoomView.vb	597	
Error (active)	BC30456	'Combine' is not a member of 'String'.	Enigma	D:\01 - Grags\Visual Studio\Enigma\Enigma\RoomView.vb	597	

Can you fix these errors?