% "edit.t"
%
% University of Toronto
% CSC148s, 1996
% Solution to Assignment 2
%
% This file contains code for graphically creating a well-formed
% rectangular maze (see the handout)



% Import the interface module
import Interface in "iface.tu" 

% The following is irrelevant when running on PCs; needed on 
% X-windows systems only:
%     import Event in "%oot/lib/Event"
%     include "fakebtn.t"

% Include the support routines for manipulating mazes.
include "supt.t"



% Default entrance coordinate.
const defaultEntranceX := 0
const defaultEntranceY := 0



% getWidthHeight(width, height)
%     - Implements the first stage in the edit session:
%        Specifying the height and width of the maze.

procedure getWidthHeight (var width, height : int)

    loop
        put "Enter desired height (between 1 and ", Interface.maxMazeHeight, "): " ..
        get height
        exit when (height > 0) and (height <= Interface.maxMazeHeight)
        put "Invalid Height. Please re-enter."
    end loop

    loop
        put "Enter desired width (between 1 and ", Interface.maxMazeWidth, "): " ..
        get width
        exit when (width > 0) and (width <= Interface.maxMazeWidth)
        put "Invalid Width. Please re-enter."
    end loop

end getWidthHeight



% setupScreen(width, height)
%     - Initialize the display by making calls to the interface
% module.

procedure setupScreen (width, height : int)

    var error : boolean
    const message : string :=
        "Use the mouse to flip the colour of maze elements.
Click on Done to specify an exit."

    cls

    Interface.displayInitialMaze (width, height, error)
    assert not error

    Interface.displayButton ("Done", White, Blue)
    Interface.displayMessage (message, White, Blue)

end setupScreen



% userTogglesElements(M)
%     - This procedure implements the second stage of the edit session:
%        Specifying the elements of the maze.

procedure userTogglesElements (var M : array 1 .. *, 1 .. * of boolean)

    var x, y, buttonNum, buttonUpDown : int

    % Initialize the mouse

    buttonchoose ("onebutton")

    % Process mouse clicks until the button is clicked.

    loop
        buttonwait ("downup", x, y, buttonNum, buttonUpDown)
        exit when Interface.inButton (x, y)

        % Determine if the mouse was clicked on a maze element.

        var mazeX, mazeY : int
        Interface.findMazeCoordinate (x, y, mazeX, mazeY)

        if mazeX > 0 and mazeY > 0 then

            % carry out the toggle.
            if M (mazeX, mazeY) = space then
                Interface.displayMazeElement (mazeX, mazeY,
                    Interface.solidColour)
                M (mazeX, mazeY) := solid
            else
                Interface.displayMazeElement (mazeX, mazeY,
                    Interface.spaceColour)
                M (mazeX, mazeY) := space
            end if
            Interface.displayMessage ("Toggle", White, Blue)
        else
            Interface.displayMessage ("Error: Please click on a maze
element or the button.", White, Red)
        end if

    end loop

end userTogglesElements


% userSpecifiesEntrance(M, entX, entY)
%     - This procedure implements stage 3 of the edit session:
%        Specifying the entrance of the maze.

procedure userSpecifiesEntrance (var M : array 1 .. *, 1 .. * of boolean,
        var entX, entY : int)

    var x, y, buttonNum, buttonUpDown : int

    Interface.displayButton ("Exit", White, Red)
    Interface.displayMessage ("Specify an entrance and then click on Exit.",
        White, Blue)

    entX := defaultEntranceX
    entY := defaultEntranceY

    var hasChosenEntrance : boolean := false

    % Process mouse clicks until the button is clicked. It is
    % assumed the mouse has already been initialized.

    loop
        buttonwait ("downup", x, y, buttonNum, buttonUpDown)
        exit when Interface.inButton (x, y)

        % Determine if the mouse was clicked in a maze element.

        var mazeX, mazeY : int
        Interface.findMazeCoordinate (x, y, mazeX, mazeY)

        if mazeX > 0 and mazeY > 0 then

            % Must redisplay old entrance appropriately.

            if hasChosenEntrance then
                if M (entX, entY) = solid then
                    Interface.displayMazeElement (entX, entY,
                        Interface.solidColour)
                else
                    Interface.displayMazeElement (entX, entY,
                        Interface.spaceColour)
                end if
            end if

            % Display new entrance in green.

            hasChosenEntrance := true
            Interface.displayMazeElement (mazeX, mazeY,Interface.entranceColour)
            entX := mazeX
            entY := mazeY

            % Output a nice status message.

            const coords : string :=
                "(" + intstr (mazeX) + "," + intstr (mazeY) + ")"
            Interface.displayMessage ("Setting Entrance to " + coords,
                White, Blue)
        else
            Interface.displayMessage ("Error: Please click on a maze element
or the button.", White, Red)
        end if

    end loop

end userSpecifiesEntrance



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Main program

% Stage 1: Specifying the height and width of the maze.

var width, height : int
getWidthHeight (width, height)

var M : array 1 .. width, 1 .. height of boolean

initializeMaze (M)

setupScreen (width, height)

% Stage 2: Specifying the elements of the maze.

userTogglesElements (M)

% Stage 3: Specifying the entrance of the maze.

var entX, entY : int
userSpecifiesEntrance (M, entX, entY)

% Stage 4: Checking the maze.

cls
if not isValidMaze (M, entX, entY) then
    put "This is not a well formed rectangular maze."
else
    put "This is a well formed rectangular maze."
end if

% Stage 5: Outputting the file.

var outputFileName : string

put "Output file? " ..
get outputFileName

writeMaze (M, entX, entY, outputFileName)

% Done!
put "Goodbye."
