#===========================================================================
#                         tutorial()
#==========================================================================
#  
#  This program is to provide a on-line tutorial of Maple for the user.
#  The tutorial has a number of sections and normal startup is done by
#
#  tutorial();
#
#  To startup directly into a specific section the tutorial can be called by
#
#  tutorial(SectionNumber);
#
#  The actual text etc. for the tutorial sections exists in a separate file
#  for each section. A list of the files and of the menu items must be in
#  the files "tutfile.src" and "tutmenu.src", respectively. (See below for
#  more information on these files and their formats.)
# 
tutorial := proc()
  local Tutorial_Loop, Print_Menu, KCounter, Resp1_Loop, Resp2_Loop, RESP,
        EntireTutorial, ExitFlag, URESP, RESP2, savedprompt, NumTopics;
  option `Copyright 1994 by Waterloo Maple Software`;
# 
# The tutorial has been invoked. First print the prelude/introduction to the
# tutorial then present the user with a menu giving the contents of the 
# tutorial. The user is then queried to determine the action to be taken next.
# The main menu consists of a list of the topics addressed in this tutorial
# plus two other options - "Do the entire tutorial" and "Quit".
# The menu items are the topics arranged in numerical order from 1 to NUMTOPICS
# with remaining two options following the tutorial topic items.
# NOTE: The user is queried for a numerical response that corresponds to the
#       numbered menu item the user wishes selected.
# Two global flags - EntireTutorial and ExitFlag - are used 
# locally to represent
# the numerical values for the last two menu items. The assignment 
# used here is:
#
#     EntireTutorial : Indicates the user wants to do the entire tutorial 
#                      starting at the first topic listed. (= NUMTOPICS+1) 
#                      
#     ExitFlag       : Indicates the user want te exit from the tutorial
#                      (= NUMTOPICS+2)
#
# CONDITIONS: This tutorial is arranged such that the user must return to the
#             main menu to exit. At the end of each topic, the user may select 
#             one of Continue With Next Topic or Return to 
#             Main `tutorial/menu`.
# A number of files are used and required for the tutorial to run.
#
#     welcome.txt - The prelude file containing instructions, etc. which is
#                   printed before the user starts into the tutorial.
#     tutmenu.src - This is a setup file that contains the list of the
#                   menu topics as they are to be printed to the screen.
#                   This file is read in and should be set up as a valid Maple
#                   statement to assign the list of strings to the variable
#                   `tutorial/menu`.
#     tutfile.src - This is a setup file that contains the list of the
#                   an associated list of text file names - one for each topic.
#                   This file is read in and should be set up as a valid Maple
#                   statement to assign the list of strings being 
#						  the file names
#                   to the variable `tutorial/chapters`.
#
#==============================================================================
# NOTE: tutmenu.src will contain something of the sort
#
#   `tutorial/menu` := [` 1.  Introduction: What is Maple?`,
#            ` 2.  Numbers and Constants, Strings and Names`,  ...
#            ...
#            `16.  Run Entire Tutorial`,
#            `17.  Exit tutorial`] ;
#                   
# and tutfile.src will contain something of the sort
#
#   `tutorial/chapters` := [`intro.txt`,
#                       `name.txt`, ...
#                       ...
#                       `express.txt`];
#==============================================================================
# Save the state of the current Maple session for restoration at the end of the 
# tutorial.

    savedprompt := interface(prompt,prompt=``);
# 
# GLOBAL Variable setup

    readlib('search');
   
    # Read in the text of the menu.
    read(cat(`tutorial/find`(),`tutmenu.src`));

    # Read in the files used for each section.
    read(cat(`tutorial/find`(),`tutfile.src`));

    NumTopics := nops(`tutorial/chapters`);

    if nops(`tutorial/menu`) = NumTopics +2
     then
       EntireTutorial := NumTopics +1;
       ExitFlag := NumTopics +2;

       Tutorial_Loop := true;           # Initialize flags.
     else
          # If the size of the two lists do not agree then something was setup
          # wrong. Inform the user and leave the tutorial.


       printf(`SETUP ERROR: The menu in the file "tutmenu.src" or the list\n`);
       printf(`             of text files in the file "tutfile.src" are not\n`);
       printf(`             properly set up.  Exiting tutorial.\n`);
 
       Tutorial_Loop := false;
     fi;

   # The invocation of the tutorial may include a parameter. The parameter
   # is to allow the user to proceed directly with the section indicated by
   # the number given as the parameter. 
   # Here we check to see if a parameter was given and if there is, that the 
   # parameter is an integer within the range 1 to NUMTOPICS.  If the given
   # parameter is not in this range then print an error message and begin the
   # tutorial at the beginning (the first topic) otherwise proceed directly to
   # the requested section. Two actions are not taken for a valid parameter,
   # i.e., the prelude is not printed and the main menu is skipped at the
   # startup. 
   # 

    if nargs > 0 
     then
       if (type(args[1],integer) and ( args[1] > 0 ) 
       and ( args[1] <= NumTopics ) )
        then
          Print_Menu := false;
          KCounter := args[1];
        else
          printf(`PARAMETER ERROR: Parameter does not correspond to an\n`);
          printf(`                 existing section number.  Starting\n`);
          printf(`                 tutorial from the beginning.\n\n`);
          `tutorial/prelude`();
          Print_Menu := true;
          KCounter := 1;
       fi;
     else
       `tutorial/prelude`();
       Print_Menu := true;
       KCounter := 1;
     fi;
 

    while Tutorial_Loop do

        # The tutorial loop has been entered. If the menu is to be 
        # printed to the screnn then do so and then query the
        # user for a numerical response indicating their selection.
        # Note that the user is queried only when the menu is printed.
        # The response must be verified as a valid selection. If the
        # response is invalid, print an appropriate message to the effect
        # the response was invalid and loop to allow the user to select
        # an appropriate menu item. The initialization prior to entering
        # this loop determines if the menu printing and selection is 
        # is done. For each valid selection by a user, perform the
        # appropriate action. Valid selections here are:
        # 
        # 1 - NUMTOPICS : tutorial topics,
        # ENTIRETUTORIAL: Flag to iterate through the entire tutorial. 
        # EXITFLAG      : Flag to exit the tutorial.
        # 
        # Note that within the loop we assume the response is invalid
        # until verified. 
        #  
                  
      if Print_Menu
       then 

         Resp1_Loop := true;

         while Resp1_Loop do

           `tutorial/mainmenu`(NumTopics,`tutorial/menu`);
           printf(`  Please make a selection.\n`);

           URESP := `tutorial/readline`();
           if length(URESP) = 0                          #Was there a response?
            then 
              printf(`  Invalid selection.  Please re-enter selection.\n`);
            else
              RESP := sscanf(URESP,`%d`);              
              if nops(RESP) = 0                #Was the response an integer?
               then
                 printf(`  Invalid Selection.  Please re-enter selection.\n`);
               else
                                               #Was it within the range?
                 if (( RESP[1] < 1 ) or ( RESP[1] > (NumTopics +2) ) )
                  then
                    printf(
			`  Invalid Selection.  Please re-enter selection.\n`);
                  else 
                    if (RESP[1] = ExitFlag)       #Stop if its the Exit flag.
                     then Tutorial_Loop := false
                     else
                       if (RESP[1] = EntireTutorial)     #Start at 1 if the user is doing
                        then KCounter := 1;              #the entire tutorial, or at the
                        else KCounter := RESP[1];        #topic the user selected.
                       fi;
                    fi;
                    Resp1_Loop := false;                  # Response is valid, exit the loop.
                 fi;
              fi;
           fi;
         od;
      fi;

# If the TUTORIAL_LOOP flag is set then the user has not opted to
# exit the tutorial. Therefore, go through the tutorial topic indicated 
# by the KCOUNTER variable. KCOUNTER contains the index for any topic 
# selected by the user. KCOUNTER defaults to the next topic in
# numerical order should the user opt to continue the tutorial rather
# than select a specific topic.
# The procedure PRINTMODULE() handles the printing and various other
# aspects of the tutorial.
# Upon completion of this section of the tutorial, query the user to
# determine the action to be taken next. At this stage, the options are:
#
# Continue : <return> continue the tutorial by proceeding to the next topic
#          : in numerical order. If this response is indicated 
#          : after the last topic in numerical order has been
#          : presented, print an appropriate message and return to
#          : the main menu.
#
#Exit to   : <x> Return to the main menu and allow the user to select 
#Main Menu : the next topic or the action to be taken.
#
# This level of the tutorial begins by looping until we get a valid response
# from the user.  We start the loop by assuming that we have received a
# valid response. An exit response <x> will result in a return to the
# main menu with the next topic pointer reset to the first topic. The 
# user can only exit the tutorial from the main menu.  If the response is to
# continue, then all that is required is to increment the topic counter 
# KCOUNTER. The response is considered invalid if it is neither of the
# choices. In this case, print an appropriate comment to the effect
# that the response was invalid and set the loop control to re-issue the
# query and repeat the response verification.


      if Tutorial_Loop
       then 

         `tutorial/module`(cat(`tutorial/find`(),`tutorial/chapters`[KCounter]));
         Resp2_Loop := true;

         while Resp2_Loop do

           printf(`  Press <RETURN> to continue with next section, or <X> to exit to the menu.\n`);
           RESP2 := `tutorial/readline`();
               
           Resp2_Loop := false;

           if RESP2 = 'x' or RESP2 = 'X'
            then 
              Print_Menu := true;
              KCounter := 1;
            else                                      #The continue response is an empty
              if length(RESP2) <> 0                   #string. Any other is invalid.
                then
                  printf(`  Invalid response.\n`);
                  Resp2_Loop := true;
                else
                  if KCounter < NumTopics             #Can we continue to the next topic
                   then                               #or are the topics depleted?
                     KCounter := KCounter +1;
                     Print_Menu := false;
                   else
                     printf(`  This is the last topic.  Please select another topic.\n`);
                     Print_Menu := true;
                     KCounter := 1;
                  fi;
              fi;
           fi;

         od;                                          #End of loop to verify RESP2.
      fi;                                             #End of section to do individual
                                                      #tutorial topic.
    od;                                               #End of tutorial loop.

    `tutorial/goodbye`();
    lprint();
    #Do any necessary cleanup and print out any trailing 
    #information deemed necessary.
    #This cleanup includes a restart and restoration of the 
    #original Maple session.
    
    interface(prompt=savedprompt);
end:
#======================================================================
#              End of main procedure TUTORIAL()
#
#      Following are the procedures used by this program.
#======================================================================

#================== `tutorial/prelude` ======================================
# 
# The tutorial has been invoked. This procedure is to print the prelude
# file to the user screen. The procedure PRINTMODULE() is used to do
# actual printing. The text for the prelude is in the file "welcome.txt".
#
#======================================================================

`tutorial/prelude` := proc()
    `tutorial/module`(cat(`tutorial/find`(),`welcome.txt`));
end:

#================== `tutorial/goodbye`======================================
# 
# The tutorial has been exited. This procedure is to print the goodbye 
# file to the user screen. The procedure PRINTMODULE() is used to do
# actual printing. The text for the prelude is in the file "goodbye.txt".
#
#======================================================================

`tutorial/goodbye`:= proc()
    `tutorial/module`(cat(`tutorial/find`(),`goodbye.txt`));
end:

#================== `tutorial/mainmenu` =====================================
# 
# Here all we do is print the main menu stored in lines in the list
# MENU. There are NUMTOPICS + 2 entries in the menu.
#
#======================================================================

`tutorial/mainmenu` := proc(NumTopics:integer, `tutorial/menu`:list(name)) 
    local i;

    lprint();
    for i from 1 to NumTopics+2 do printf(`      %s\n`,`tutorial/menu`[i]) od;
    lprint();
end:

#================== `tutorial/module` ======================================
# 
# This procedure is to  print the module file specified by the
# parameter MODULEFILE to the user screen. Each line in the file 
# is preceded by a flag indicating how the line is to be interpeted
# by the program. The flag may be one or more characters long but will
# be terminated by the ">" character.
# This procedure is intended to print out the separate modules of the
# tutorial but is also useable for printing out the prelude, etc.
# 
# This procedure uses the procedure DETERMINE to determine and handle
# the actions specified by the individual flags.
#
#=====================================================================

`tutorial/module` := proc(ModuleFile)
  local Flag, TLine, TxtStart, TxtEnd, TxtLine;
       
     # Get the first line of the text file and initialize the loop 
     # to perform the tutorial module.

    TLine := readline(ModuleFile);
    `tutorial/continue` := true;
    `tutorial/doquestion` := true;
    
     # Readline returns a 0 if the line read is empty. In this case,
     # the requested file is empty.

    if TLine = 0 
      then
        printf(`ERROR: The file "%s" does not exist or is empty.\n`,ModuleFile);
      else
          # Until the user quits or finishes the tutorial, read each 
          # line of the module file and verify the line. Two conditions
          # are checked here: a) that the text line is not too short to
          # contain a useful line and b) that the flag delimiter ">"
          # exists in the line. Verification of flags, valid or invalid,
          # is done by the procedure DETERMINE.
          # Within this loop the inputted line is separated into FLAG -
          # the flag portion and TXTLINE - the remaining text portion. 

       while ((TLine <> 0 ) and ( `tutorial/continue`)) do
    
         if length(TLine) < 2                    #Is there enough on the line?
          then
            printf(`ERROR: Line begins with an unrecognized flag.\n`);
            printf(`       Too few characters.\n`);
          else
            if  search(TLine,`>`)                #Is there a flag delimiter?
             then                                  #Seperate out the flag (first
               Flag :=  sscanf(TLine,`%s`)[1];   #string) from anything else
               TxtStart := length(Flag)+1;       #on the line.
               TxtEnd   := length(TLine);
               if TxtStart < TxtEnd
                then
                  TxtLine := substring(TLine,TxtStart..TxtEnd);
                else
                  TxtLine := ``;
               fi;
                  #Proceed to DETERMINE to determine the action specified by the
                  #flag (if valid) and to perform the action requested.

               `tutorial/determine`(Flag,TxtLine);

             else
               printf(`ERROR: Line begins with an unrecognized flag.\n`);
               printf(`       No flag delimiter.\n`);
            fi;
         fi;

         TLine := readline(ModuleFile);          # Read in the next line.
       od;
    fi;

    # Ensure the file is closed before leaving this routine. (Opening the
    # file is done automatically by the first readline.) Seems we need to 
    # do this loop as the close command didn't work. A read following a 
    # close picked up where we left off from a previous time. <BUG?>

    while TLine <> 0 do
      TLine := readline(ModuleFile);
    od;
end:

#================== `tutorial/determine` ========================================
#
# This procedure is to determine and execute the action to be taken
# based on the sequence of flags and text lines currently being read
# by the calling routine. The global variables FLAG and TXTLINE contain
# the flag (from the beginning of the text line) and the remaining text
# from the line read in, respectively. The recognized flags are:
# t - text line, q - question text, a - answer to question, b - blank
# line, x - example command (to be executed), h - hidden command (to be
# executed but hidden from the user), c1 - flow choice 1, c2 - flow
# choice 2, eoq - end-of-questions and eof - end-of-file.
#
# Text, blank lines, questions and answers are printed as is.
# However, if the user opts to skip questions in response to a c2 query;
# questions, answers, c2 queries and any intervening blank lines 
# are not printed from that response until an eoq flag is encountered.
#
#====================================================================

`tutorial/determine` := proc(Flag:name,TxtLine:name)
   local FlagSet, FlagProcs, ProcLine, FIndex, MaxFIndex;

   FlagSet := [`t>`,`n>`,`q>`,`a>`,`b>`,`x>`,`h>`,`c1>`,`c2>`,`eoq>`,`eof>`];

   FlagProcs := [`tutorial/doflagt`, `tutorial/doflagt`, `tutorial/doflagq`,
     `tutorial/doflaga`, `tutorial/doflagq`, `tutorial/doflagx`,
     `tutorial/doflagh`, `tutorial/doflagc1`, `tutorial/doflagc2`,
     `tutorial/doflageoq`, `tutorial/doflageof`];

   MaxFIndex := nops(FlagSet) +1 ;

   FIndex := 1;
   
   while ( (FIndex < MaxFIndex) and (FlagSet[FIndex] <> Flag ) ) do
     FIndex := FIndex +1;
   od;
   
   if FIndex = MaxFIndex
    then 
      printf(`ERROR: unrecognized flag.\n`);
    else
     ProcLine := (FlagProcs[FIndex])(TxtLine);
     ProcLine;
    fi;

end:

#====================================================================
#
# Following are procedures for each of the flag types.
# Single character flags are: t - text, b - blank line, q - question,
# a - answer, x - example, and h - hidden command.
# The multi-character flags are: c1 - flowchoice 1, c2 - flowchoice 2,
# eoq - end-of-questions and eof - end-of-file.
# Text, blank lines, questions and answers are printed as is.
# However, if the user opts to skip questions in response to a c2 query;
# questions, answers, c2 commands and any intervening blank
# lines are not printed from that response until an eoq flag is
# encountered. When the boolean DOQUESTION is true, the questions are
# printed. When false, the question section is skipped.
# Note that the same procedure is used for the flags b and q.
#
#=====================================================================

#================== `tutorial/doflagt` =========================================
#
#   DoFLagt: This procedure is for the t flag in the tutorial files.
#            The t flag indicates that a line of text follows. The 
#            action taken is to print the line stored in TXTLINE 
#            to the screen with a newline.
#   
#====================================================================

`tutorial/doflagt` := proc(TxtLine:name) printf(`  %s\n`,TxtLine) end:

#================== `tutorial/doflagq` =========================================
#
#   DoFLagq: This procedure is for the q flag in the tutorial files.
#            The q flag is used to have the tutorial print a question.
#            The questions are printed in the same manner as the
#            text of the tutorial, i.e, the text of the line is stored 
#            in the variable TXTLINE and the printed text is followed
#            by a newline. The user however has the option of skipping 
#            questions. The boolean DOQUESTION stores the user's 
#            decision on skipping. 
#
#            This procedure doubles as the procedure for the b flag.
#            This flag is used to print a blank line. Note that blank
#            lines in the question sections are skipped along with the
#            questions.
#   
#====================================================================

`tutorial/doflagq` := proc(TxtLine:name) 
    if `tutorial/doquestion` then printf(`  %s\n`,TxtLine) fi;
  end:

#================== `tutorial/doflaga` =========================================
#
# In this procedure, an answer is prompted from the user (normally
# in response to a question). If the user responds with a string,
# then the string is parsed to see if the string is a valid Maple
# command. If valid, the command is compared against the sample answer
# read in from the file (in the string TXTLINE). This comparison is 
# done in the procedure COMPAREANSWER. The comparison is primitive.
# Equality is restricted only to an actual string equality between the
# user's answer and the sample answer.
# If equality can not be determined then both the user's answer and the
# sample answer are parsed and executed to allow the user to compare
# the results visually.
#
# If invalid, then the user is informed the command was invalid and
# a loop is entered to prompt for a valid command. At any point during
# this prompting, the user may opt to have the sample answer 
# displayed by entering a <return>.
# By design, the first prompt for an answer does not inform the
# user of the "?" option. However, this print-example-answer response
# will be honored whenever given by the user. All prompts aftr a user 
# enters an invalid command will present the user with sample answer
# option.
#
# In this procedure some care must be taken to ensure that the tutorial
# user not be able to easily escape out of the tutorial. (I don't believe
# that all cases can be trapped.) # The checks done here are not sophisticated.
# We # only check to ensure the first non-blank string is not restricted.
# Note however that the parse command can not parse multiple statements
# unless they are part of a loop or procedure or such. Thus, the user
# can not simply enter two Maple statements with the second being a
# restricted command. We accomplish this in the following manner.
# 
# The list CHECKSTR contains the list of strings that can be Maple
# commands and need special consideration. A particular structure is used
# for CHECKSTR in that the first two - ? and help(..) - are responses that
# we would like the user to have access to. The remaining strings are 
# commands that could disrupt the sequence of the tutorial if allowed
# to be executed. So to this end, the tutorial traps all cases where the
# first non-blank string that the user responses with corresponds to any
# of the strings in CHECKSTR. The first cases are treated specially and 
# are labelled as VTYPE =1 and =2, respectively. If, in the remaining cases,
# the user's response begins with any of the commands in CHECKSTR[3] to 
# CHECKSTR[NOCHECKSTR], the response is considered restricted and is not
# executed. 
#
#====================================================================

`tutorial/doflaga` := proc(TxtLine:name) 
 local CheckStr, NoCheckStr, NotAnswered, VType, FirstStr, ChLen,
       ScannStr, ValidCheck, StrInd, Flagy, Respa;

  if `tutorial/doquestion`
   then
        # If we are not skipping questions, then query the user for an answer
        # (the normal usage is that an a-flag follows a question given by a 
        # sequence of q-flags).

     printf(`\n  Your answer is?\n`);
    
        # This list of restricted strings is assigned here and is kept local
        # to ensure that the user can not easily change it in one command and
        # then be able to circumvent the restricted strings at another command.
        # By keeping it local, any changes the user might be able to effect
        # will not be in effect for the next time the procedure is used.

     CheckStr := [ `?`, `!`, '`done`', `help(`, help, '`quit`',
		   restart, '`stop`' ];

     NoCheckStr := nops(CheckStr);

     NotAnswered := true;

     while NotAnswered do
          # First determine whether the user wants the answer or has attempted 
          # to input a command. At the same time, ensure that the string entered
          # does not have unathorized characters. Once again assume the string
          # is invalid until otherwise determined.

       Respa := `tutorial/readline`();
       
       if length(Respa) = 0
        then
             # The entered string was just a return. This is taken to be a request
             # by the user to print the sample answer and continue through the tutorial.

          printf(`\n  Our answer is:\n`);
          printf(`> %s\n\n`,TxtLine);
          Flagy := parse(TxtLine, statement);
          print(Flagy);
          NotAnswered := false;

        else
             #Here we search the inputted string to ensure that the command entered
             #does not begin in a restricted command. A few tricks are used here.
             #The restricted character strings are in the list CHECKSTR.
             #The search command tells us whether the string exists in the inputted.
             #string. If so, then the first non-blank string is scanned from the
             #inputted string and that compared against the restricted string.
             #The sscanf command first skips all leading blanks (using %*[ ]) then 
             #until the next blank, colon, semi-colon or period (using %[^:;. ]).

          ValidCheck := true;
          StrInd := 0;
          VType := 0;

          # Loop until either the string is found to be invalid or all the
          # restricted strings have been checked.

          while ( ValidCheck and ( StrInd < NoCheckStr ) ) do
            StrInd := StrInd + 1;
            if search(Respa,CheckStr[StrInd])
             then
               ScannStr := sscanf(cat(` `,Respa,`.`),`%*[ ]%[^;:. ]`);
               if nops(ScannStr) <> 0 
                then
                  FirstStr := ScannStr[1];
                  ChLen := length(CheckStr[StrInd]);

                     # Here we have that the string length matches that of the current
                     # restricted string. If the strings are the same then it is
                     # restricted. Special note is taken if it is either of the first
                     # two restricted strings "?" or "help(". In either case, the
                     # flag VTYPE is set (from 0) to the index for use later.

                  if length(FirstStr) = ChLen
                   then
                     if (FirstStr = CheckStr[StrInd] )
                      then
                        ValidCheck := false;
                        if ((StrInd = 1) or (StrInd = 2))
                         then
                           VType := StrInd;
                        fi;
                     fi;
                   else
                        # Here we have that the string length is longer than that of
                        # the current restricted string.  The only cases we are 
                        # interested in when this occurs is for the two restricted
                        # strings "?" or "help(" as the extra chararcters may be topics
                        # for the help commands (which we allow). In either case, the
                        # flag VTYPE is set (from 0) to the index for use later.

                     if ((length(FirstStr) > ChLen) and (substring(FirstStr,1..ChLen) = CheckStr[StrInd] ) )
                      then
                        if ((StrInd = 1) or (StrInd = 2))
                         then
                           ValidCheck := false;
                           VType := StrInd;
                        fi;
                     fi;
                  fi;
               fi;
             fi;
          od;
  
          if ValidCheck or (VType =2)
           then
                # At this point we have a string that has been checked for illegal strings
                # and for a return. The decision to attempt the parse has been made in the
                # logic above. Here we attempt the parse. Note that special care is taken
                # when the command begins with `help(` as the parse(string,statement) command
                # evaluates statements whereas parse(string) returns an expression. In the
                # case of the help command, evaluation results in the output being put to
                # the screen beyond our control. 
             
             if VType = 2
              then 
                Flagy :=  traperror(parse(Respa)):
              else 
                Flagy :=  traperror(parse(Respa, statement)):
             fi;
             
                # Any error reported by the parse command results in us printing the
                # invalid Maple statement message and looping for a valid response.

             if Flagy = lasterror
              then
                printf(`\n  Invalid Maple statement.  Re-enter or press <RETURN> for sample answer.\n`);
              else 
                   # For the help() command we want the user to see the result but then
                   # we loop to allow the user to attempt the answer again. Otherwise,
                   # the answer is passed to COMPAREANSWER to attempt to determine the
                   # equality. 

                if VType = 2
                 then
                   Flagy := parse(Respa, statement);
                   printf(`\n\n  Re-enter or press <RETURN> for sample answer.\n`);
                 else
                   `tutorial/compare`(Respa,TxtLine);
                   NotAnswered := false;
                fi;
             fi:
           else
                # For the ? syntax, we want the same result as help. If the string is only
                # one character then only "?" was entered. If longer, then extract the 
                # remainder of the string and pass it to help as a parameter (topic).
 
             if VType = 1
              then
                if length(FirstStr) = 1
                 then
                   print(help());
                 else
                   print(help(substring(FirstStr,2..length(FirstStr))));
                fi;
              else
                   # Any error reported to this point results in us printing the
                   # invalid Maple statement message and looping for a valid response.

                printf(`\n  Maple statement begins with an invalid string or restricted command.\n`);
             fi;
             printf(`  Re-enter or press <RETURN> for sample answer.\n`);
          fi;
       fi;
     od; 
  fi;
end:

#================== `tutorial/compare` ======================================
#
# This procedure is used by the DOFLAGA procedure to compare the user's
# response in the string RESPA to the answer from the tutorial file. 
# The only time that we will say that the user's answer is definitely
# correct is if the strings match exactly with the exception of trailing
# blanks. Otherwise, we can not be sure the answers are correct. In the
# latter case, we execute both possible solutions and display the results
# of each and let the user determine their equality. The procedure uses
# the parse command extensively.
#
#=======================================================================

`tutorial/compare` := proc(Respa:name,TxtLine:name)
   local Respab, AResp, ARLen, Flagy,
         TxtLa,ATxtLa, ATLen, Pb, Pa, SameAnswer;

   # We assume that the answer read in from the tutorial file 
   # will not be a blank line. Such an assumption is not made 
   # about the user's response thus we need to check for this 
   # condition.
   
   Respab := sscanf(cat(` `,Respa),`%*[ ]%s`);
   if nops(Respab) <> 0
    then
         # Get the user's response (in RESPA) and the answer from the 
         # tutorial file (in TXTLINE) in the form of strings without
         # leading blanks.
        
      search(Respa,Respab[1],'Pa');
      AResp := substring(Respa,Pa..length(Respa));
      ARLen := length(AResp);
   
      TxtLa := sscanf(cat(` `,TxtLine),`%*[ ]%s`)[1];
      search(TxtLine,TxtLa,'Pb');
      ATxtLa := substring(TxtLine,Pb..length(TxtLine));
      ATLen  := length(ATxtLa);
      
      # Here we have two non-blank strings ARESP (from user) and
      # ATXTLA (from tutorial file) to compare.
      # In the following cases, we look to see which string - the
      # user's or the one from the tutorial input file is the longest.
      # The strings are compared up to the length of the shortest.
      # If equal then the longer one is checked for trailing blanks.
      #
   
      if ATLen < ARLen                         #First check when the user's
       then                                    #line is the longer of the two.
        if ATxtLa = substring(AResp,1..ATLen)
         then 
           if nops(sscanf(cat(` `,substring(AResp,ATLen+1..ARLen)),
			  `%*[ ]%s`)) = 0
            then 
              SameAnswer := true;              #If only trailing blanks left.
            else
              SameAnswer := false;             #Otherwise, there are other chars.
           fi;
         else
           SameAnswer := false;                #Not same substrings.
        fi;
       else
         if ATLen > ARLen                      #Now check as abover when
          then                                 #the user's line is the shorter.
            if substring(ATxtLa,1..ARLen) = AResp
              then 
               if nops(sscanf(cat(` `,substring(TxtLa,ARLen+1..ATLen)),
			      `%*[ ]%s`)) = 0
                then 
                  SameAnswer := true;
                else
                  SameAnswer := false;
               fi;
             else
               SameAnswer := false;
            fi;
          else  
            if ATxtLa = AResp                 #If the lines are the same length
             then                             #they are either:
               SameAnswer := true;            # Identical, or
             else
               SameAnswer := false;           # not.
            fi;
         fi;
      fi;
    else
      SameAnswer := false;	              #This case is when a blank line is 
   fi;                                        #entered by the user.
   
   # Based on the comparisons above we either print the message from the
   # executed command and a congratulatory message (when the answers are the 
   # same) or execute both the user's command and the answer from the 
   # tutorial input file.
   
   lprint();
   Flagy := parse(Respa, statement);          #The user's valid response.
   print(Flagy);

   if SameAnswer
    then 
      printf(`  Correct!!\n`);            #The answer is correct.
    else
      printf(`  Our answer is:\n`);       #or we are unsure so print
      printf(`> %s\n\n`,TxtLine);
      Flagy := parse(TxtLine, statement);
      print(Flagy);
   fi;
   
   
end:

#================== `tutorial/doflagx` =========================================
#
#   DoFLagx: This procedure is for the x flag in the tutorial files.
#            The purpose of this flag is to indicate that the text line
#            is to be executed by Maple such that both the text line
#            and the output produced by Maple be printed for the user
#            to see. An assumption made here is that the Maple command
#            is a single line and that its syntax is correct. Note
#            the command line is part of the tutorial text so the 
#            the syntax should be correct. Note that it is not easy
#            to display incorrect syntax using the parse command.
#            The response from parse will be that the command syntax
#            is incorrect but the command cannot be passed to Maple
#            to get the maple error message.
#   
#====================================================================

`tutorial/doflagx` := proc(TxtLine:name) 
   local Flagy ;
    if `tutorial/doquestion`
     then
       printf(`> %s\n\n`,TxtLine);
       Flagy := parse(TxtLine, statement);
       print(Flagy);
    fi;
   end:

#================== `tutorial/doflagh` =========================================
#
#   DoFLagh: This procedure is for the h flag in the tutorial files.
#            The purpose of this flag is to provide the writer of the 
#            tutorial a means to clean up after using the x flag. 
#            The commands lines in TXTLINE are executed by Maple but
#            this execution is hidden from the user. Once again the 
#            syntax is assumed to be correct as the origin of these
#            commands is the text files provided for the tutorial.
#   
#====================================================================

`tutorial/doflagh` := proc(TxtLine:name) 
   local Flagy ;
       Flagy := parse(TxtLine,statement);
       Flagy;
   end:

#================== `tutorial/doflagc1` ========================================
#
#   DoFLagc1: This procedure is for the c1 flag in the tutorial files.
#             This flag results in the user being queried to either
#             continue (indicated by a <return>) or exit to the main 
#             menu (indicated by an "x"). The intent is to provide a
#             pause at this point in the tutorial and to allow the user
#             exit out to the main menu for further action. Note that 
#             readline returns a zero length string for a <return>.
#             This procedure loops until one of the valid responses
#             is returned. The only global flag used here is 
#             CONTINUETUTORIAL which is set to false when the user
#             selects to exit to the main menu.
#   
#====================================================================

`tutorial/doflagc1` := proc() 
   local c1ReqLoop, C1RESP;

   c1ReqLoop := true;

   while c1ReqLoop do

     printf(`  Press <RETURN> to continue, or <X> to exit to the menu.\n`);
     C1RESP := `tutorial/readline`();

     c1ReqLoop := false;        #Assume the response is valid and loop
                                #only if the input is not one of the 
                                #valid possibities. Note that a <return>
                                #(for continue) does not alter the flow
                                #of the tutorial module. In this case
                                #nothing need to be done.

     if C1RESP = 'x' or C1RESP = 'X'          # Exit to main menu or ....
      then
        `tutorial/continue` := false;
      else
        if length(C1RESP) <> 0         # continue with the tutorial (=0) or ...
         then
           printf(`  Invalid response.\n`);
           c1ReqLoop := true;          # loop for valid response.
        fi;
     fi;
   od;                         #End of loop to verify C1RESP.

end:

#================== `tutorial/doflagc2` ========================================
#
#   DoFLagc2: This procedure is for the c2 flag in the tutorial files.
#             This flag results in the user being queried to continue 
#             (indicated by a <return>), skip the questions (indicated
#             by an "s") or exit to the main menu (indicated by an "x"). 
#             The intent is to provide a pause at this point in the
#             questions and to allow the user to skip the questions or
#             to exit out to the main menu for further action.
#             This procedure loops until one of the valid responses
#             is returned. Note that readline returns a zero length string
#             for a <return>. The global flags used here are DOQUESTION 
#             and CONTINUETUTORIAL. The latter is used as in DOFLAGC1
#             with the boolean DOQUESTION being true initially and 
#             set false only when the user decides to skip the questions.
#             Note that when the user decides to skip questions that
#             all lines flagged with "b", "q", "a" or "c2" are skipped
#             until an "eoq" flag is encountered.
#   
#====================================================================

`tutorial/doflagc2` := proc() 
   local c2ReqLoop, C2RESP;

    if `tutorial/doquestion`
     then
       c2ReqLoop := true;

       while c2ReqLoop do
    
         printf(`  Press <RETURN> to continue, <S> to skip to end of questions,\n`);
	 printf(`  or <X> to exit section.\n`);
         C2RESP := `tutorial/readline`();

         c2ReqLoop := false;    #Assume the response is valid and loop
                                #only if the input is not one of the 
                                #valid possibities. Note that a <return>
                                #(for continue) does not alter the flow
                                #of the tutorial module. In that case
                                #nothing need to be done.


         if C2RESP = 'x' or C2RESP = 'X'
          then
            `tutorial/continue` := false;          #Exit from the module....
          else
            if C2RESP = 's' or C2RESP = 'S'
             then
               `tutorial/doquestion` := false;             #Skip the questions, or ....
             else
               if length(C2RESP) <> 0           #continue from the current point (=0)  
                then
                  printf(`  Invalid response.\n`);
                  c2ReqLoop := true;            #loop for valid response.
               fi;
            fi;
         fi;
       od;       #End of loop to verify C2RESP.
    fi;
    
   end:

#================== `tutorial/doflageoq` ========================================
#
#   DoFLageoq: This procedure is for the eof flag in the tutorial files.
#              This flag normally indicates that the end of a set of
#              questions has been reached. The only consequence of this
#              flag arises when the user has opted to skip questions (in 
#              response to a c2 query). This flag results in the
#              boolean DOQUESTION being reset. The user will then be
#              able to be prompted (using a c2 flag) about viewing a 
#              subsequent question set.
#   
#====================================================================

`tutorial/doflageoq` := proc() ;
     `tutorial/doquestion` := true;
   end:

#================== `tutorial/doflageof` ========================================
#
#   DoFLageof: This procedure is for the eof flag in the tutorial files.
#              The flag indicates that the end of the tutorial file has
#              been reached. The boolean `tutorial/continue` is set to 
#              false resulting in the tutorial falling out to the main
#              menu from which the next user selection can be handled.
#   
#====================================================================

`tutorial/doflageof` := proc() ;
     `tutorial/continue` := false;
   end:


# This procedure is a wrapper for readline() which will allow the help
# browser to continue to work.
`tutorial/readline` := proc()
    local line;
    do
	line := readline(terminal);
	if length(line) >= 2 and substring(line,1..1) = `?` then
	    parse(line,statement)
	else RETURN(line) fi
    od
end:


# This procedure is used to find the tutorial based on the location of
# the library. This is similar to the code used by the share library to
# find itself
`tutorial/find` := proc()
    local t,n,location;
    option remember,system;
    for t in [libname] do
	if type(t,string) then
	    n := length(t);
	    if n < 3 or substring(t,n-2 .. n) <> 'lib' then next fi;
	    location := substring(t,1 .. n-3);
	    location := cat(location,`tutorial/`);
	    RETURN(location)
	fi
    od;
    FAIL
end:

save tutorial, `tutorial/prelude`, `tutorial/goodbye`, `tutorial/mainmenu`,
    `tutorial/module`, `tutorial/determine`, `tutorial/doflagt`,
    `tutorial/doflagq`, `tutorial/doflaga`, `tutorial/compare`,
    `tutorial/doflagx`, `tutorial/doflagh`, `tutorial/doflagc1`,
    `tutorial/doflagc2`, `tutorial/doflageoq`, `tutorial/doflageof`,
    `tutorial/readline`, `tutorial/find`, ``.libname.`/tutorial.m`;
quit
