Imports System.Drawing.Drawing2D
Imports System.IO ' Needed for file operations
Imports System.Text.Json ' For JSON 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

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

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

    ' 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

    ' Arrays to store wall presence
    Friend verticalWalls(SQCOUNTX, SQCOUNTY - 1) As Boolean ' Vertical walls
    Friend horizontalWalls(SQCOUNTX - 1, SQCOUNTY) As Boolean ' Horizontal walls

    ' Random number generator
    Private rand As New Random()

    ' Path to premades folder
    Private premadesFolder As String = "D:\01 - Grags\Visual Studio\Enigma\Data\Premades"
    Private savesFolder As String = "D:\01 - Grags\Visual Studio\Enigma\Data\Saves"

    ' Undo/Redo stacks
    Private undoStack As New Stack(Of RoomState)
    Private redoStack As New Stack(Of RoomState)

    ' Current file path
    Private currentFilePath As String = ""

    ' Constructor
    Public Sub New()
        ' Initialize the form components (assumes you have a PictureBox named 'PicGame')
        InitializeComponent()

        ' Initialize walls (e.g., set all walls to present)
        InitializeWalls()

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

        ' Attach event handlers to picture boxes
        AddColorPictureBoxHandlers(Me)

        ' Initialize Undo stack with the initial state
        SaveStateForUndo()
    End Sub

    ' Initialize walls with default values
    Private Sub InitializeWalls()
        For x As Integer = 0 To SQCOUNTX
            For y As Integer = 0 To SQCOUNTY - 1
                verticalWalls(x, y) = True
            Next
        Next
        For x As Integer = 0 To SQCOUNTX - 1
            For y As Integer = 0 To SQCOUNTY
                horizontalWalls(x, y) = True
            Next
        Next

        ' Ensure border walls are always present
        ' Vertical walls at x=0 and x=SQCOUNTX
        For y As Integer = 0 To SQCOUNTY - 1
            verticalWalls(0, y) = True
            verticalWalls(SQCOUNTX, y) = True
        Next

        ' Horizontal walls at y=0 and y=SQCOUNTY
        For x As Integer = 0 To SQCOUNTX - 1
            horizontalWalls(x, 0) = True
            horizontalWalls(x, SQCOUNTY) = True
        Next
    End Sub

    ' Form Load event handler
    Private Sub RoomView_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        LoadPremades()
    End Sub

    ' Load premades into lstPremades
    Private Sub LoadPremades()
        If Not Directory.Exists(premadesFolder) Then
            ' Create the directory if it does not exist
            Directory.CreateDirectory(premadesFolder)
        End If

        lstPremades.Items.Clear()
        Dim files = Directory.GetFiles(premadesFolder, "*.Premade")
        For Each file As String In files
            lstPremades.Items.Add(Path.GetFileNameWithoutExtension(file))
        Next
    End Sub

    ' When a premade is selected from the list
    Private Sub lstPremades_SelectedIndexChanged(sender As Object, e As EventArgs) Handles lstPremades.SelectedIndexChanged
        If lstPremades.SelectedIndex >= 0 Then
            ' Save current state for Undo before changing
            SaveStateForUndo()

            Dim selectedPremade As String = lstPremades.SelectedItem.ToString()
            Dim filePath As String = Path.Combine(premadesFolder, selectedPremade & ".Premade")
            LoadSettingsFromFile(filePath)
            PicGame.Invalidate()

            ' Clear Redo stack
            redoStack.Clear()
        End If
    End Sub

    ' Method to load settings from a file
    Private Sub LoadSettingsFromFile(filePath As String)
        Try
            If Not File.Exists(filePath) Then
                MessageBox.Show("File not found: " & filePath)
                Return
            End If

            Dim lines As String() = File.ReadAllLines(filePath)
            Dim section As String = ""
            For Each line As String In lines
                line = line.Trim()
                If String.IsNullOrEmpty(line) OrElse line.StartsWith(";") Then
                    Continue For
                End If
                If line.StartsWith("[") AndAlso line.EndsWith("]") Then
                    section = line.Substring(1, line.Length - 2)
                Else
                    Dim parts() As String = line.Split(New Char() {":"c}, 2)
                    If parts.Length = 2 Then
                        Dim key As String = parts(0).Trim()
                        Dim value As String = parts(1).Trim()
                        Select Case section
                            Case "Walls"
                                LoadProperty(key, value, True)
                            Case "Floors"
                                LoadProperty(key, value, False)
                        End Select
                    End If
                End If
            Next
        Catch ex As Exception
            MessageBox.Show("Error loading settings: " & ex.Message)
        End Try
    End Sub

    ' Helper method to load properties
    Private Sub LoadProperty(key As String, value As String, isWall As Boolean)
        Select Case key
            Case "HatchStyle"
                Dim hatchStyle As HatchStyle
                If [Enum].TryParse(value, hatchStyle) Then
                    If isWall Then
                        wallsHatchStyle = hatchStyle
                    Else
                        floorsHatchStyle = hatchStyle
                    End If
                End If
            Case "Color1"
                Dim color As Color = ParseColor(value)
                If isWall Then
                    wallsColor1 = color
                Else
                    floorsColor1 = color
                End If
            Case "Color2"
                Dim color As Color = ParseColor(value)
                If isWall Then
                    wallsColor2 = color
                Else
                    floorsColor2 = color
                End If
        End Select
    End Sub

    ' Helper method to parse color from string "A,R,G,B"
    Private Function ParseColor(colorString As String) As Color
        Dim parts() As String = colorString.Split(","c)
        If parts.Length = 4 Then
            Dim a, r, g, b As Integer
            If Integer.TryParse(parts(0), a) AndAlso Integer.TryParse(parts(1), r) AndAlso
               Integer.TryParse(parts(2), g) AndAlso Integer.TryParse(parts(3), b) Then
                Return Color.FromArgb(a, r, g, b)
            End If
        End If
        Return Color.Black
    End Function

    ' Save premade settings to a file
    Private Sub btnSavePremade_Click(sender As Object, e As EventArgs) Handles btnSavePremade.Click
        Dim saveDialog As New SaveFileDialog()
        saveDialog.InitialDirectory = premadesFolder
        saveDialog.Filter = "Premade Files (*.Premade)|*.Premade"
        saveDialog.DefaultExt = "Premade"
        saveDialog.AddExtension = True
        saveDialog.Title = "Save Premade"

        If saveDialog.ShowDialog() = DialogResult.OK Then
            SaveSettingsToFile(saveDialog.FileName)
            ' Reload premades list
            LoadPremades()
        End If
    End Sub

    ' Method to save settings to a file
    Private Sub SaveSettingsToFile(filePath As String)
        Try
            Using sw As New StreamWriter(filePath)
                sw.WriteLine("[Walls]")
                sw.WriteLine("HatchStyle: " & wallsHatchStyle.ToString())
                sw.WriteLine("Color1: " & ColorToString(wallsColor1))
                sw.WriteLine("Color2: " & ColorToString(wallsColor2))
                sw.WriteLine()
                sw.WriteLine("[Floors]")
                sw.WriteLine("HatchStyle: " & floorsHatchStyle.ToString())
                sw.WriteLine("Color1: " & ColorToString(floorsColor1))
                sw.WriteLine("Color2: " & ColorToString(floorsColor2))
            End Using
        Catch ex As Exception
            MessageBox.Show("Error saving settings: " & ex.Message)
        End Try
    End Sub

    ' Helper method to convert a Color to "A,R,G,B" string
    Private Function ColorToString(color As Color) As String
        Return String.Format("{0},{1},{2},{3}", color.A, color.R, color.G, color.B)
    End Function

    ' Event handler for mnuNew click
    Private Sub mnuNew_Click(sender As Object, e As EventArgs) Handles mnuNew.Click
        ' Save current state for Undo
        SaveStateForUndo()

        ' Reset to default state
        wallsHatchStyle = HatchStyle.Cross
        wallsColor1 = Color.Gray
        wallsColor2 = Color.DarkGray
        floorsHatchStyle = HatchStyle.SmallCheckerBoard
        floorsColor1 = Color.LightGray
        floorsColor2 = Color.White
        InitializeWalls()

        ' Clear Redo stack
        redoStack.Clear()

        ' Reset current file path
        currentFilePath = ""

        ' Redraw the grid
        PicGame.Invalidate()
    End Sub

    ' Event handler for mnuSave click
    Private Sub mnuSave_Click(sender As Object, e As EventArgs) Handles mnuSave.Click
        If String.IsNullOrEmpty(currentFilePath) Then
            mnuSaveAs_Click(sender, e)
        Else
            SaveRoomToFile(currentFilePath)
        End If
    End Sub

    ' Event handler for mnuLoad click
    Private Sub mnuLoad_Click(sender As Object, e As EventArgs) Handles mnuLoad.Click
        Dim openDialog As New OpenFileDialog()
        openDialog.Filter = "Room Files (*.room)|*.room"
        openDialog.DefaultExt = "room"
        openDialog.AddExtension = True
        openDialog.Title = "Load Room"

        If openDialog.ShowDialog() = DialogResult.OK Then
            ' Save current state for Undo
            SaveStateForUndo()

            LoadRoomFromFile(openDialog.FileName)
            currentFilePath = openDialog.FileName

            ' Clear Redo stack
            redoStack.Clear()
        End If
    End Sub

    ' Event handler for mnuSaveAs click
    Private Sub mnuSaveAs_Click(sender As Object, e As EventArgs) Handles mnuSaveAs.Click
        Dim saveDialog As New SaveFileDialog()
        saveDialog.Filter = "Room Files (*.room)|*.room"
        saveDialog.DefaultExt = "room"
        saveDialog.AddExtension = True
        saveDialog.Title = "Save Room As"

        If saveDialog.ShowDialog() = DialogResult.OK Then
            SaveRoomToFile(saveDialog.FileName)
            currentFilePath = saveDialog.FileName
        End If
    End Sub

    ' Method to save the entire room to a file using JSON serialization
    Private Sub SaveRoomToFile(filePath As String)
        Try
            Dim roomState As New RoomState(Me)
            Dim options As New JsonSerializerOptions With {
                .WriteIndented = True,
                .IncludeFields = True
            }
            Dim jsonString As String = JsonSerializer.Serialize(roomState, options)
            File.WriteAllText(filePath, jsonString)
        Catch ex As Exception
            MessageBox.Show("Error saving room: " & ex.Message)
        End Try
    End Sub

    ' Method to load the entire room from a file using JSON deserialization
    Private Sub LoadRoomFromFile(filePath As String)
        Try
            If Not File.Exists(filePath) Then
                MessageBox.Show("File not found: " & filePath)
                Return
            End If

            Dim jsonString As String = File.ReadAllText(filePath)
            Dim options As New JsonSerializerOptions With {
                .IncludeFields = True
            }
            Dim roomState As RoomState = JsonSerializer.Deserialize(Of RoomState)(jsonString, options)
            roomState.RestoreState(Me)
            PicGame.Invalidate()
        Catch ex As Exception
            MessageBox.Show("Error loading room: " & ex.Message)
        End Try
    End Sub

    ' Undo functionality
    Private Sub btnUndo_Click(sender As Object, e As EventArgs) Handles btnUndo.Click
        If undoStack.Count > 1 Then
            ' Save current state to Redo stack
            SaveStateForRedo()

            ' Pop the last state from the Undo stack
            undoStack.Pop()
            Dim previousState As RoomState = undoStack.Peek()
            previousState.RestoreState(Me)

            ' Redraw the grid
            PicGame.Invalidate()
        End If
    End Sub

    ' Redo functionality
    Private Sub btnRedo_Click(sender As Object, e As EventArgs) Handles btnRedo.Click
        If redoStack.Count > 0 Then
            ' Save current state to Undo stack
            SaveStateForUndo()

            ' Pop the state from the Redo stack
            Dim redoState As RoomState = redoStack.Pop()
            redoState.RestoreState(Me)

            ' Redraw the grid
            PicGame.Invalidate()
        End If
    End Sub

    ' Save current state to Undo stack
    Private Sub SaveStateForUndo()
        Dim currentState As New RoomState(Me)
        undoStack.Push(currentState)

        ' Limit the stack size if necessary
        If undoStack.Count > 50 Then
            undoStack = New Stack(Of RoomState)(undoStack.Reverse().Take(50))
        End If
    End Sub

    ' Save current state to Redo stack
    Private Sub SaveStateForRedo()
        Dim currentState As New RoomState(Me)
        redoStack.Push(currentState)
    End Sub

    ' Existing methods below...

    ' Recursively add event handlers to picture boxes
    Private Sub AddColorPictureBoxHandlers(parent As Control)
        For Each ctrl As Control In parent.Controls
            If TypeOf ctrl Is PictureBox AndAlso ctrl.Name.StartsWith("col") Then
                AddHandler ctrl.Click, AddressOf ColorPictureBox_Click
            End If
            If ctrl.HasChildren Then
                AddColorPictureBoxHandlers(ctrl)
            End If
        Next
    End Sub

    ' Event handler for picture boxes
    Private Sub ColorPictureBox_Click(sender As Object, e As EventArgs)
        ' Save current state for Undo
        SaveStateForUndo()

        Dim pb As PictureBox = CType(sender, PictureBox)
        ' Get the color of the clicked picture box
        Dim selectedColor As Color = pb.BackColor

        If rdoFloors.Checked Then
            If pb.Name.StartsWith("col") Then
                Dim numStr As String = pb.Name.Substring(3)
                Dim num As Integer
                If Integer.TryParse(numStr, num) Then
                    If num >= 1 AndAlso num <= 48 Then
                        ' Change floorsColor1
                        floorsColor1 = selectedColor
                    ElseIf num >= 51 AndAlso num <= 98 Then
                        ' Change floorsColor2
                        floorsColor2 = selectedColor
                    End If
                End If
            End If
        ElseIf rdoWalls.Checked Then
            If pb.Name.StartsWith("col") Then
                Dim numStr As String = pb.Name.Substring(3)
                Dim num As Integer
                If Integer.TryParse(numStr, num) Then
                    If num >= 1 AndAlso num <= 48 Then
                        ' Change wallsColor1
                        wallsColor1 = selectedColor
                    ElseIf num >= 51 AndAlso num <= 98 Then
                        ' Change wallsColor2
                        wallsColor2 = selectedColor
                    End If
                End If
            End If
        End If

        ' Clear Redo stack
        redoStack.Clear()

        ' Redraw the grid to update colors
        PicGame.Invalidate()
    End Sub

    ' Event handler for lstHatchStyles
    Private Sub lstHatchStyles_SelectedIndexChanged(sender As Object, e As EventArgs) Handles lstHatchstyles.SelectedIndexChanged
        ' Save current state for Undo
        SaveStateForUndo()

        ' Get the selected HatchStyle
        Dim selectedHatchStyleName As String = lstHatchstyles.SelectedItem.ToString()
        Dim selectedHatchStyle As HatchStyle = CType([Enum].Parse(GetType(HatchStyle), selectedHatchStyleName), HatchStyle)

        If rdoFloors.Checked Then
            floorsHatchStyle = selectedHatchStyle
        ElseIf rdoWalls.Checked Then
            wallsHatchStyle = selectedHatchStyle
        End If

        ' Clear Redo stack
        redoStack.Clear()

        ' Redraw the grid to update hatch styles
        PicGame.Invalidate()
    End Sub

    ' Event handler for btnRandom click
    Private Sub btnRandom_Click(sender As Object, e As EventArgs) Handles btnRandom.Click
        ' Save current state for Undo
        SaveStateForUndo()

        ' Randomize floor colors
        floorsColor1 = Color.FromArgb(rand.Next(256), rand.Next(256), rand.Next(256))
        floorsColor2 = Color.FromArgb(rand.Next(256), rand.Next(256), rand.Next(256))

        ' Randomize wall colors
        wallsColor1 = Color.FromArgb(rand.Next(256), rand.Next(256), rand.Next(256))
        wallsColor2 = Color.FromArgb(rand.Next(256), rand.Next(256), rand.Next(256))

        ' Randomize hatch styles
        Dim hatchStyles As Array = [Enum].GetValues(GetType(HatchStyle))
        floorsHatchStyle = CType(hatchStyles.GetValue(rand.Next(hatchStyles.Length)), HatchStyle)
        wallsHatchStyle = CType(hatchStyles.GetValue(rand.Next(hatchStyles.Length)), HatchStyle)

        ' Clear Redo stack
        redoStack.Clear()

        ' Redraw the grid
        PicGame.Invalidate()
    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
        PicGame.Invalidate() ' Trigger a redraw on the PictureBox
    End Sub

    ' PicGame event handlers, assuming the PictureBox name is 'PicGame'
    Private Sub PicGame_Paint(sender As Object, e As PaintEventArgs) Handles PicGame.Paint
        ' Calculate square size and draw the grid
        CalculateSquareSizes(PicGame.ClientSize.Width, PicGame.ClientSize.Height)
        e.Graphics.SmoothingMode = SmoothingMode.None
        DrawGrid(e.Graphics)
        DrawHighlight(e.Graphics)
    End Sub

    Private Sub PicGame_MouseMove(sender As Object, e As MouseEventArgs) Handles PicGame.MouseMove
        ' Logic for mouse movement within the grid
        HandleMouseMove(e)
    End Sub

    Private Sub PicGame_MouseDown(sender As Object, e As MouseEventArgs) Handles PicGame.MouseDown
        ' Set mouse button states
        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) Handles PicGame.MouseUp
        ' Save current state for Undo
        SaveStateForUndo()

        ' Reset mouse button states
        If e.Button = MouseButtons.Right Then
            isRightMouseDown = False
        ElseIf e.Button = MouseButtons.Left Then
            isLeftMouseDown = False
        End If

        ' Clear Redo stack
        redoStack.Clear()
    End Sub

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

    ' Method to draw the grid
    Private Sub DrawGrid(g As Graphics)
        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 wall intersections to fill gaps with wall pattern
        For x As Integer = 0 To SQCOUNTX
            For y As Integer = 0 To SQCOUNTY
                Dim intersectionRect As New Rectangle(xOrigin + x * (SQSizeX + WALL_THICKNESS) - WALL_THICKNESS \ 2,
                                                      yOrigin + y * (SQSizeY + WALL_THICKNESS) - WALL_THICKNESS \ 2,
                                                      WALL_THICKNESS,
                                                      WALL_THICKNESS)
                Using wallBrush As New HatchBrush(wallsHatchStyle, wallsColor1, wallsColor2)
                    g.FillRectangle(wallBrush, intersectionRect)
                End Using
            Next
        Next

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

                If verticalWalls(x, y) Then
                    Using wallBrush As New HatchBrush(wallsHatchStyle, wallsColor1, wallsColor2)
                        g.FillRectangle(wallBrush, wallRect)
                    End Using
                Else
                    ' Draw floor pattern where wall is removed
                    Using floorBrush As New HatchBrush(floorsHatchStyle, floorsColor1, floorsColor2)
                        g.FillRectangle(floorBrush, wallRect)
                    End Using
                End If
            Next
        Next

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

                If horizontalWalls(x, y) Then
                    Using wallBrush As New HatchBrush(wallsHatchStyle, wallsColor1, wallsColor2)
                        g.FillRectangle(wallBrush, wallRect)
                    End Using
                Else
                    ' Draw floor pattern where wall is removed
                    Using floorBrush As New HatchBrush(floorsHatchStyle, floorsColor1, floorsColor2)
                        g.FillRectangle(floorBrush, wallRect)
                    End Using
                End If
            Next
        Next
    End Sub

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

        ' Check if it's a border wall
        If highlightedWallX Then
            If highlightedX = 0 OrElse highlightedX = SQCOUNTX Then
                ' Border wall, do not highlight
                Return
            End If
        ElseIf highlightedWallY Then
            If highlightedY = 0 OrElse highlightedY = SQCOUNTY Then
                ' Border wall, do not highlight
                Return
            End If
        End If

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

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

    ' Method to handle mouse movement within the grid
    Private Sub HandleMouseMove(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 = SQSizeX + WALL_THICKNESS
        Dim cellSizeY As Integer = 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

            ' Check if it's a border wall
            If highlightedX = 0 OrElse highlightedX = SQCOUNTX Then
                ' It's a border wall, do not highlight
                Exit Sub
            End If

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

            ' Check if it's a border wall
            If highlightedY = 0 OrElse highlightedY = SQCOUNTY Then
                ' It's a border wall, do not highlight
                Exit Sub
            End If

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

        ' If mouse button is down and over a wall, add/remove wall
        If isLeftMouseDown OrElse isRightMouseDown Then
            If highlightedWallX Then
                ' Vertical wall
                ' Check if it's not a border wall
                If highlightedX > 0 AndAlso highlightedX < SQCOUNTX Then
                    If isLeftMouseDown Then
                        verticalWalls(highlightedX, highlightedY) = True
                    ElseIf isRightMouseDown Then
                        verticalWalls(highlightedX, highlightedY) = False
                    End If
                End If
            ElseIf highlightedWallY Then
                ' Horizontal wall
                ' Check if it's not a border wall
                If highlightedY > 0 AndAlso highlightedY < SQCOUNTY Then
                    If isLeftMouseDown Then
                        horizontalWalls(highlightedX, highlightedY) = True
                    ElseIf isRightMouseDown Then
                        horizontalWalls(highlightedX, highlightedY) = False
                    End If
                End If
            End If
            ' Redraw to update the wall
            PicGame.Invalidate()
        End If

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

End Class

' Serializable class to store the state of the room
Public Class RoomState
    Public wallsHatchStyle As HatchStyle
    Public wallsColor1 As Color
    Public wallsColor2 As Color
    Public floorsHatchStyle As HatchStyle
    Public floorsColor1 As Color
    Public floorsColor2 As Color

    Public verticalWalls(,) As Boolean
    Public horizontalWalls(,) As Boolean

    ' Constructor: captures the state from the RoomView instance
    Public Sub New(roomView As RoomView)
        Me.wallsHatchStyle = roomView.wallsHatchStyle
        Me.wallsColor1 = roomView.wallsColor1
        Me.wallsColor2 = roomView.wallsColor2
        Me.floorsHatchStyle = roomView.floorsHatchStyle
        Me.floorsColor1 = roomView.floorsColor1
        Me.floorsColor2 = roomView.floorsColor2

        ' Clone the wall arrays
        Me.verticalWalls = roomView.verticalWalls.Clone()
        Me.horizontalWalls = roomView.horizontalWalls.Clone()
    End Sub

    ' Restores the state to the RoomView instance
    Public Sub RestoreState(roomView As RoomView)
        roomView.wallsHatchStyle = Me.wallsHatchStyle
        roomView.wallsColor1 = Me.wallsColor1
        roomView.wallsColor2 = Me.wallsColor2
        roomView.floorsHatchStyle = Me.floorsHatchStyle
        roomView.floorsColor1 = Me.floorsColor1
        roomView.floorsColor2 = Me.floorsColor2

        ' Restore the wall arrays
        roomView.verticalWalls = Me.verticalWalls.Clone()
        roomView.horizontalWalls = Me.horizontalWalls.Clone()
    End Sub
End Class

Can you see to it that mnuSaveAs And mnuLoad (NOT Save or Load Premade) opendialogue path is set to the string "savesFolder"

Can you look at undo, it seems to be missing steps. Not updating after every action.

On the form I have a collection of PictureBoxes. For the now, I would like you to concentrate on 2. picBlock1 and picBaddy1. picBlock1 is loaded with a png and picBaddy1 is loaded with an animated Gif. I would like you to add the ability to drag and drop these onto the grid (floor sections only, NOT on the wall). You will most likely have to make changes to Save, SaveAs and Load (Not Premades) to adjust this change.