% ----------------------------------------------------------------
% Sample solution to Assignment 5.

% Import the lexicons for both English and Ruritanian.

import English in "eng.tu",
    Ruritanian in "rur.tu"


% ----------------------------------------------------------------
% isLower()
%       This function returns true if 'c' is a lower case alphabetic
% character and false otherwise.

function isLower (c : string (1)) : boolean
    if c >= "a" and c <= "z" then
        result true
    else
        result false
    end if
end isLower


% ----------------------------------------------------------------
% isUpper()
%       This function returns true if 'c' is an upper case alphabetic
% character and false otherwise.

function isUpper (c : string (1)) : boolean
    if c >= "A" and c <= "Z" then
        result true
    else
        result false
    end if
end isUpper


% ----------------------------------------------------------------
% toLower()
%       This function returns a string containing the lower
% case equivalent of 'c'. 'c' must be an upper case letter.

function toLower (c : string (1)) : string (1)
    assert isUpper (c)

    const delta := ord ("a") - ord ("A")

    result chr (ord (c) + delta)
end toLower


% ----------------------------------------------------------------
% canonicalForm()
%       This function converts a token into canonical form by removing
% all non-alphabetic characters and converting upper case to lower case.

function canonicalForm (token : string) : string
    var canon := ""

    % Loop through token. Take each character and add it to the result
    % provided it's alphabetic; ignore other chars.  Convert upper case to
    % lower case.

    for i : 1 .. length (token)
        const character := token (i)
        if isLower (character) then
            canon += character
        elsif isUpper (character) then
            canon += toLower (character)
            % Ignore other characters
        end if
    end for

    result canon
end canonicalForm


% ---------------------------------------------------------------
% checkFile()
%       This procedure counts the words in a file and checks them
% for spelling errors against an English lexicon and/or a Ruritanian
% lexicon. The boolean parameters 'checkEnglish' and 'checkRuritanian'
% determine which lexicons will be checked. If both are false, this
% procedure will just counts the words in the file.

procedure checkFile (filename : string, checkEnglish, checkRuritanian : 
    boolean)

    % Open the file
    var fileNo : int
    open : fileNo, filename, get
    if fileNo = 0 then
        put "No such file: ", filename
        return
    end if

    % Prepare to check the file
    var nextToken : string
    var wordCount := 0
    var errorCount := 0

    % Check each token in the file.
    loop
        % Are we finished?
        get : fileNo, skip
        exit when eof (fileNo)

        % Get next word.
        get : fileNo, nextToken
        wordCount += 1

        if checkEnglish or checkRuritanian then
            nextToken := canonicalForm (nextToken)

            var inALexicon : boolean := false
            inALexicon :=
                (checkEnglish and English.IsAWord (nextToken)) or
                (checkRuritanian and Ruritanian.IsAWord (nextToken))

            if not inALexicon then
                errorCount += 1

                % Print heading if first error.
                if errorCount = 1 then
                    put "Possible spelling errors:"
                end if
                put "\t", nextToken
            end if
        end if

    end loop

    % File has been checked.  Close it and print a summary.
    close : fileNo
    put skip, "File \"", filename, "\" has ", wordCount, " words.  "
    if checkEnglish or checkRuritanian then
        if errorCount = 0 then
            put "No possible errors were found."
        elsif errorCount = 1 then
            put "1 possible error was found."
        else
            put errorCount, " possible errors were found."
        end if
    end if

end checkFile


% ---------------------------------------------------------------
% Main program

% Ask for the file to check

var filename : string
put "File name?  " ..
get filename

% Determine the option.

var checkEnglish, checkRuritanian : boolean := false

loop
    var option : int
    put "Options:"
    put "  1: Check English"
    put "  2: Check Ruritanian"
    put "  3: Check both"
    put "  4: Just count words"
    put "Option?  " ..
    get option


    case option of
        label 1 :
            checkEnglish := true
            exit
        label 2 :
            checkRuritanian := true
            exit
        label 3 :
            checkEnglish := true
            checkRuritanian := true
            exit
        label 4 :
            % neither lexicon should be checked.
            exit
        label :
            put "Invalid option. Please re-enter"
    end case
end loop

checkFile (filename, checkEnglish, checkRuritanian)
