//*******************************************************************
//*                                                                 *
//*  File Name:       h_substitution.cpp                            *
//*  Project:         Cryptology Programming Project #3, part b     *
//*  Author:          Richard Kernan                                *
//*  Date:            03/28/01                                      *
//*                                                                 *
//*******************************************************************
//*                                                                 *
//*  File Description:                                              *
//*  This file contains the main program and other incidental       *
//*  functions to solve homophonic ciphers.  It uses the            *
//*  "homophonic" class to handle the bulk of the data manipulation *
//*  and display.                                                   *
//*  This program was developed as a response to project 3b, which  *
//*  is described below.  Although the description recommends       *
//*  simply augmenting one of the existing programs, I was not      *
//*  impressed by any of them.  So I wrote this one from scratch.   *
//*                                                                 *
//*  This program uses a UNIX-style command line interface with     *
//*  options.  One of the commands is "help", which provides a full *
//*  listing of available commands.  Further, "help" can be called  *
//*  on any one specific command for details and examples of how    *
//*  to use the command and what it does.                           *
//*                                                                 *
//*  3.  b)Several programs exist on our website which are tools    *
//*        for helping solve homophonic ciphers. In this project    *
//*        you are to either alter one of these programs            *
//*        (recommended) or start fresh and augment the output.     *
//*        The following modifications need to be made to the tool. *
//*            i) revise program so that single digit numbers can   *
//*               be counted.                                       *
//*           ii) print out social index for each number, or at     *
//*               least those with highest index                    *
//*          iii) highest freq. trigrams should be indexed.         *
//*                                                                 *
//*  There are 3 files needed to build this project:                *
//*     1)  h_substitution.cpp  (this file - has main)              *
//*     2)  homophonic.cpp                                          *
//*     3)  homophonic.H                                            *
//*                                                                 *
//*  To compile this project with a specific executable file name,  *
//*     type the following (replace <exec_name> with the name that  *
//*     you want for you executable file).                          *
//*                                                                 *
//*  CC -o <exec_name> h_sustitution.cpp homophonic.cpp             *
//*                                                                 *
//*  Note "CC" is in capital letters.  This invokes the C++         *
//*  compiler.  "cc" (lower-case) WILL NOT WORK.  This is a plain   *
//*  C compiler.                                                    *
//*                                                                 *
//*  I suggest that you DO NOT try to compile this project using    *
//*  the GNU compiler "gcc".  This project uses the C++ Standard    *
//*  Template Library, and gcc has a very strange way of dealing    *
//*  with templates.                                                *
//*                                                                 *
//*******************************************************************


#include <string>
#include <iostream.h>
#include <iomanip.h>
#include <stdlib.h>
#include <ctype.h>
#include "homophonic.H"




void print_general_help();
void print_sub_help();
void print_undo_help();
void print_save_help();
void print_print_help();
void print_exit_help();
void print_help_help();
void print_table_help();
void print_neighbor_help();
void print_percent_help();
void print_freq_help();
void print_ngram_help();

std::string get_filename_string( std::string s );


void main( int argc, char **argv )
{
    char c[128];

    std::string ciphertext_filename;
    std::string plaintext_filename;

    // Get the command-line arguments and setup the
    // program to do the substitution.
    switch( argc )
    {
    case 1:
        {
            break;
        }
    case 2:
        {
            ciphertext_filename = argv[1];
            break;
        }
    default:
        {
            cout << endl;
            cout << "Usage: " << argv[0] << " [ciphertext_filename]" << endl;
            cout << "Please restart program: " << argv[0] << endl;
            exit( 1 );
        }
    }

    // Prompt user for setup information
    // not provided on the command-line.
    if( ciphertext_filename.size() < 1 )
    {
            cout << "Enter the name of the ciphertext file: ";
            cin.getline( c, 128 );
            ciphertext_filename = c;
    }

    homophonic subtxt;
    if( ! subtxt.load_file( ciphertext_filename ) )
    {
        cout << endl << "Unable to load file: \"" << ciphertext_filename.c_str() << "\".";
        cout << endl << "Program terminated." << endl << endl;
        exit( 1 );
    }

    cout << endl << "---- CIPHERTEXT ----";
    cout << endl << "--------------------" << endl;
    subtxt.print_txt();
    cout << endl << endl;
    cout << "Type \"help\" for command information." << endl << endl;


    //******************************************************************************
    // Program setup is complete at this point.
    // Start parsing for the command-line interface.
    //******************************************************************************


    std::string command;

    while( true )
    {
        cout << "homophonic >> ";
        cin.getline( c, 128 );
        command = c;

        // INVALID COMMAND.
        if( command.size() < 4 )
        {
            cout << "Invalid command: \"" << command.c_str() << "\"" << endl;
            cout << "Type \"help [command]\" for command information." << endl;
            continue;
        }

        // Remove leading whitespace from
        // the command.
        for( int b = 0; b < command.size(); b++ )
        {
            if( ! isspace( command.at( b ) ) )
                break;
        }

        command = command.substr( b );

        //**************************************************************************

        // COMMAND:  sub <a> <b>
        if( command.substr( 0, 4 ) == "sub " && command.size() > 6 )
        {
            // Find the position of the first
            // argument to "sub"
            std::string args = command.substr( 4 );
            for( int i = 0; i < args.size(); i++ )
            {
                if( ! isspace( args.at( i )) )
                    break;
            }

            if( i == args.size() )
            {
                cout << "Invalid arguments to the \"sub\" command." << endl;
                cout << "Type \"help sub\" for command information." << endl;
                continue;
            }

            // Find the end of the first argument
            for( int j = i + 1; j < args.size(); j++ )
            {
                if( isspace( args.at( j ) ) )
                    break;
            }

            // If there is only 1 argument,
            // the command is invalid.
            if( j == args.size() )
            {
                cout << "Invalid arguments to the \"sub\" command." << endl;
                cout << "Type \"help sub\" for command information." << endl;
                continue;
            }

            std::string a = args.substr( i, (j - i) );
            std::string b;

            // Find the position of the second
            // argument to "sub"
            for( i = j + 1; i < args.size(); i++ )
            {
                if( ! isspace( args.at( i ) ) )
                    break;
            }

            // If there is only 1 argument,
            // the command is invalid.
            if( i == args.size() )
            {
                cout << "Invalid arguments to the \"sub\" command." << endl;
                cout << "Type \"help sub\" for command information." << endl;
                continue;
            }

            // Find the end of the second argument
            for( j = i + 1; j < args.size(); j++ )
            {
                if( isspace( args.at( j ) ) )
                    break;
            }

            b = args.substr( i, (j - i) );

            bool invalid = false;

            // Make sure there's not a third argument
            if( j < args.size() )
            {
                for( i = j + 1; i < args.size(); i++ )
                {
                    if( ! isspace( args.at( i ) ) )
                    {
                        invalid = true;
                        break;
                    }
                }
            }

            if( ! invalid )
            {
                if( ! subtxt.substitute( a, b ) )
                {
                    cout << "Unable to substitute \'" << a.c_str() << "\' for \'";
                    cout << b.c_str() << "\'" << endl;
                    continue;
                }
            }
            else
            {
                cout << "Invalid arguments to the \"sub\" command." << endl;
                cout << "Type \"help sub\" for command information." << endl;
                continue;
            }

        }  // close  =>  "COMMAND: sub <a> <b>"

        //**************************************************************************

        // COMMAND:  undo [n]
        else if( command.substr( 0, 4 ) == "undo" )
        {
            if( command.size() > 4 )
            {
                // Find the position of the first
                // argument to "undo", if there is one.
                std::string args = command.substr( 4 );
                for( int i = 0; i < args.size(); i++ )
                {
                    if( ! isspace( args.at( i )) )
                        break;
                }

                // If the command was simple "undo"
                // then try to undo once.
                if( i == command.size() )
                {
                    if( ! subtxt.undo_sub() )
                    {
                        cout << "Unable to undo substitution." << endl;
                        continue;
                    }
                }

                int j = i;
                while( j < args.size() && isdigit( args.at( j ) ))
                    j++;
                
                // If the argument is not a number,
                // then it is invalid.
                if( j == i )
                {
                    cout << "Invalid command: \"" << command.c_str() << "\"" << endl;
                    cout << "Type \"help [command]\" for command information." << endl;
                    continue;
                }

                // If not the end of the command,
                // verify that the rest is only whitespace.
                else if( j != args.size() )
                {
                    int k = j;
                    while( k < args.size() )
                    {
                        if( ! isspace( args.at( k ) ) )
                        {
                            cout << "Invalid command: \"" << command.c_str() << "\"" << endl;
                            cout << "Type \"help [command]\" for command information." << endl;
                            continue;
                        }
                        k++;
                    }
                }

                args = args.substr( i, (j - i) );

                int stop_undo = atoi( args.c_str() );

                if( stop_undo < 1 )
                {
                    cout << "Unable to undo " << stop_undo << " substitutions." << endl;
                    continue;
                }

                for( i = 0; i < stop_undo; i++ )
                {
                    if( ! subtxt.undo_sub() )
                    {
                        cout << "Undid " << i;
                        if( i > 1 )
                            cout << " substitutions." << endl;
                        else
                            cout << " substituion." << endl;
                        cout << "Unable to undo more." << endl;
                        break;
                    }
                }

            }  //  close  =>  if(command.size()>4)
            
            else if( ! subtxt.undo_sub() )
            {
                cout << "Unable to undo substitution." << endl;
                continue;
            }
            
            continue;

        }  // close  =>  "COMMAND:  undo [n]"

        //**************************************************************************

        // COMMAND:  table [-g] <n>
        else if( command.substr( 0, 4 ) == "tabl" )
        {
            int len = command.size();

            if( len < 5 )
            {
                cout << "Invalid command: \"" << command.c_str() << "\"" << endl;
                cout << "Type \"help [command]\" for command information." << endl;
                continue;
            }

            if( len == 5 )
            {
                if( command == "table" )
                {
                    subtxt.print_freq_table();
                    continue;
                }
                else
                {
                    cout << "Invalid command: \"" << command.c_str() << "\"" << endl;
                    cout << "Type \"help [command]\" for command information." << endl;
                    continue;
                }
            }
            
            // The length of the command is greater than 5
            if( command.substr( 0, 5 ) == "table" &&
                isspace( command.at( 5 ) ) )
            {
                
                std::string arg1;
                std::string arg2;
                
                // Find the beginning of the first argument
                for( int i = 5; i < len; i++ )
                {
                    if( ! isspace( command.at( i ) ) )
                        break;
                }
                
                // If there was no argument...
                if( i == len )
                {
                    subtxt.print_freq_table();
                    continue;
                }
                
                // Find the end of the first argument
                for( int j = i + 1; j < len; j++ )
                {
                    if( isspace( command.at( j ) ) )
                        break;
                }
                
                // If there was only one argument the 
                if( j == len )
                {
                    cout << "Invalid arguments to \"table\"" << endl;
                    cout << "Type \"help table\" for command information." << endl;
                    continue;
                }

                arg1 = command.substr( i, (j - i) );

                // Find the beginning of the second argument
                for( i = j + 1; i < len; i++ )
                {
                    if( ! isspace( command.at( i ) ) )
                        break;
                }

                // If there was only one argument the 
                if( i == len )
                {
                    cout << "Invalid arguments to \"table\"" << endl;
                    cout << "Type \"help table\" for command information." << endl;
                    continue;
                }

                // Find the end of the second argument
                for( j = i + 1; j < len; j++ )
                {
                    if( isspace( command.at( j ) ) )
                        break;
                }

                arg2 = command.substr( i, (j - i) );

                bool invalid = false;

                // Make sure that the second argument
                // was a number.
                for( i = 0; i < arg2.size(); i++ )
                {
                    if( ! isdigit( arg2.at( i ) ) )
                    {
                        invalid = true;
                        break;
                    }
                }

                if( invalid )
                {
                    cout << "Invalid arguments to \"table\"" << endl;
                    cout << "Type \"help table\" for command information." << endl;
                    continue;
                }

                int n_arg2 = atoi( arg2.c_str() );

                if( n_arg2 < 1 )
                {
                    cout << "Invalid arguments to \"table\"" << endl;
                    cout << "Type \"help table\" for command information." << endl;
                    continue;
                }

                // Make sure there was not more than 2 arguments
                if( j != len )
                {
                    for( i = j + 1; i < len; i++ )
                    {
                        if( ! isspace( command.at( i ) ) )
                            break;
                    }
                    if( i < len )
                    {
                        cout << "Invalid arguments to \"table\"" << endl;
                        cout << "Type \"help table\" for command information." << endl;
                        continue;
                    }
                }

                if( arg1 == "-g" )
                {
                    subtxt.print_soc_idx_table( n_arg2 );
                    continue;
                }
                else
                {
                    cout << "Invalid arguments to \"table\"" << endl;
                    cout << "Type \"help table\" for command information." << endl;
                    continue;
                }

            }  //  close  =>  if(command.substr(0,5)=="table"&&
               //                isspace(command.at(5)))
            else
            {
                cout << "Invalid command: \"" << command.c_str() << "\"" << endl;
                cout << "Type \"help [command]\" for command information." << endl;
                continue;
            }

        }  // close  =>  "COMMAND:  table [-g] <n>"

        //**************************************************************************

        // COMMAND:  ngram [n]
        else if( command.substr( 0, 4 ) == "ngra" )
        {
            if( command.size() < 5 )
            {
                cout << "Invalid command: \"" << command.c_str() << "\"" << endl;
                cout << "Type \"help [command]\" for command information." << endl;
                continue;
            }

            if( command.size() == 5 && command == "ngram" )
            {
                subtxt.print_ngram_table( 2 );
                continue;
            }

            else if( command.size() > 5 && isspace( command.at( 5 ) ) )
            {
                // Find the beginning of the argument
                for( int i = 6; i < command.size(); i++ )
                {
                    if( ! isspace( command.at( i ) ) )
                        break;
                }

                // If there was no argument, do "ngram 2"
                if( i == command.size() )
                {
                    subtxt.print_ngram_table( 2 );
                    continue;
                }

                // Find the end of the argument
                for( int j = i + 1; j < command.size(); j++ )
                {
                    if( isspace( command.at( j ) ) )
                        break;
                }

                std::string arg = command.substr( i, (j - i) );
                bool invalid = false;

                // Make sure that the argument is an integer >= 2
                for( int k = 0; k < arg.size(); k++ )
                {
                    if( ! isdigit( arg.at( k ) ) )
                    {
                        invalid = true;
                        break;
                    }
                }

                if( invalid )
                {
                    cout << "Invalid argument to the \"ngram\" command." << endl;
                    cout << "Type \"help ngram\" for command information." << endl;
                    continue;
                }

                int n_arg = atoi( arg.c_str() );
                if( n_arg < 2 )
                    invalid = true;

                // Make sure there was only 1 argument
                if( j != command.size() )
                {
                    for( i = j + 1; i < command.size(); i++ )
                    {
                        if( ! isspace( command.at( i ) ) )
                        {
                            invalid = true;
                            break;
                        }
                    }
                }

                if( invalid )
                {
                    cout << "Invalid argument to the \"ngram\" command." << endl;
                    cout << "Type \"help ngram\" for command information." << endl;
                    continue;
                }

                subtxt.print_ngram_table( n_arg );
                continue;

            }  //  close  =>  else if(command.size()>5 && isspace(command.at(5)))

            else
            {
                cout << "Invalid command: \"" << command.c_str() << "\"" << endl;
                cout << "Type \"help [command]\" for command information." << endl;
                continue;
            }

        }  // close  =>  "COMMAND:  ngram [n]"

        //**************************************************************************

        // COMMAND:  help [command]
        else if( command.substr( 0, 4 ) == "help" )
        {
            if( command.size() > 4 && isspace( command.at( 4 ) ) )
            {
                for( int i = 4; i < command.size(); i++ )
                {
                    if( ! isspace( command.at( i ) ) )
                        break;
                }

                // If there are no arguments,
                // just print the general help screen.
                if( i == command.size() )
                {
                    print_general_help();
                    continue;
                }

                // If there is an argument, make sure there
                // is only one argument.
                bool invalid = false;
                bool space_found = false;
                int end = i + 1;
                for( int j = i + 1; j < command.size(); j++ )
                {
                    // If another whitespace character is found
                    // followed by a non-whitespace character,
                    // then the command is invalid.
                    if( isspace( command.at( j ) ) )
                    {
                        space_found = true;
                        for( int k = j; k < command.size(); k++ )
                        {
                            if( ! isspace( command.at( k ) ) )
                            {
                                invalid = true;
                                break;
                            }
                        }
                    }
                    if( invalid )
                        break;

                    if( ! space_found )
                        end++;
                }

                if( invalid )
                {
                    cout << "Invalid command: \"" << command.c_str() << "\"" << endl;
                    cout << "Type \"help [command]\" for command information." << endl;
                    continue;
                }

                std::string com_arg = command.substr( i, (end - i) );

                if( com_arg == "sub" )
                    print_sub_help();
                else if( com_arg == "undo" )
                    print_undo_help();
                else if( com_arg == "save" )
                    print_save_help();
                else if( com_arg == "print" )
                    print_print_help();
                else if( com_arg == "exit" )
                    print_exit_help();
                else if( com_arg == "help" )
                    print_help_help();
                else if( com_arg == "table" )
                    print_table_help();
                else if( com_arg == "neighbor" )
                    print_neighbor_help();
                else if( com_arg == "percent" )
                    print_percent_help();
                else if( com_arg == "freq" )
                    print_freq_help();
                else if( com_arg == "ngram" )
                    print_ngram_help();
                else
                {
                    cout << "No help available for \"" << com_arg.c_str() << "\"" << endl;
                    continue;
                }
            }

            else
            {
                print_general_help();
                continue;
            }

        }  // close  =>  "COMMAND:  help [command]"

        //**************************************************************************

        // COMMAND:  freq <a>
        else if( command.substr( 0, 4 ) == "freq" )
        {
            if( command.size() < 6 )
            {
                cout << "Invalid command: \"" << command.c_str() << "\"" << endl;
                cout << "Type \"help [command]\" for command information." << endl;
                continue;
            }
            
            if( command.substr( 0, 5 ) == "freq " )
            {
                // Find the position of the argument to "freq"
                std::string args = command.substr( 4 );
                for( int i = 0; i < args.size(); i++ )
                {
                    if( ! isspace( args.at( i )) )
                        break;
                }
                
                // If there was no argument given,
                // the command is invalid.
                if( i == args.size() )
                {
                    cout << "Invalid arguments to the \"freq\" command." << endl;
                    cout << "Type \"help freq\" for command information." << endl;
                    continue;
                }

                // Find the end of the argument to "percent"
                for( int j = i + 1; j < args.size(); j++ )
                {
                    if( isspace( args.at( j ) ) )
                        break;
                }
                
                std::string a = args.substr( i, (j - i) );
                j++;
                bool invalid = false;
                
                // If this character is not the end of the
                // argument string, verify that the rest is
                // just whitespace.
                while( j < args.size() )
                {
                    if( ! isspace( args.at( j ) ))
                    {
                        invalid = true;
                        break;
                    }
                    j++;
                }
                
                if( invalid )
                {
                    cout << "Invalid arguments to the \"freq\" command." << endl;
                    cout << "Type \"help freq\" for command information." << endl;
                    continue;
                }
                
                int f = subtxt.num_freq( a );
                cout << " \"" << a.c_str() << "\" occurs " << f;
                if( f == 1 )
                    cout << " time." << endl;
                else
                    cout << " times." << endl;
                continue;
            }

            else
            {
                cout << "Invalid command: \"" << command.c_str() << "\"" << endl;
                cout << "Type \"help [command]\" for command information." << endl;
                continue;
            }

        }  // close  =>  "COMMAND:  freq <a>"

        //**************************************************************************

        // COMMAND:  neighbor [-b, -a] <a> <b>
        else if( command.substr( 0, 4 ) == "neig" )
        {
            if( command.size() < 10 )
            {
                cout << "Invalid command: \"" << command.c_str() << "\"" << endl;
                cout << "Type \"help [command]\" for command information." << endl;
                continue;
            }

            // If the command was "neighbor"...
            if( command.substr( 0, 8 ) == "neighbor" &&
                isspace( command.at( 8 ) ) )
            {
                std::string args = command.substr( 9 );
                
                // Find the beginning of the first argument
                for( int i = 0; i < args.size(); i++ )
                {
                    if( ! isspace( args.at( i )) )
                        break;
                }

                // If there was no argument given,
                // the command is invalid.
                if( i == args.size() )
                {
                    cout << "\"neighbor\" requires an argument." << endl;
                    cout << "Type \"help neighbor\" for command information." << endl;
                    continue;
                }

                // Find the end of the first argument
                for( int j = i + 1; j < args.size(); j++ )
                {
                    if( isspace( args.at( j ) ) )
                        break;
                }

                std::string arg1 = args.substr( i, (j - i) );
                std::string arg2;
                std::string arg3;
                int num_args = 1;
                bool invalid = false;

                if( j < args.size() )
                {
                    // Find the second argument if there is one
                    for( int k = j + 1; k < args.size(); k++ )
                    {
                        if( ! isspace( args.at( k ) ) )
                            break;
                    }

                    // If there is a second argument...
                    if( k < args.size() )
                    {
                        // Find the end of the second argument.
                        for ( int l = k + 1; l < args.size(); l++ )
                        {
                            if( isspace( args.at( l ) ) )
                                break;
                        }

                        arg2 = args.substr( k, (l - k) );
                        num_args++;

                        // Find the third argument if there is one
                        if( l < args.size() )
                        {
                            for( int m = l + 1; m < args.size(); m++ )
                            {
                                if( ! isspace( args.at( m ) ) )
                                    break;
                            }

                            // If there is a third argument...
                            if( m < args.size() )
                            {
                                // Find the end of the third argument.
                                for( int n = m + 1; n < args.size(); n++ )
                                {
                                    if( isspace( args.at( n ) ) )
                                        break;
                                }

                                arg3 = args.substr( m, (n - m) );
                                num_args++;

                                // Verify that there is not a fourth argument
                                if( n < args.size() )
                                {
                                    for( j = n + 1; j < args.size(); j++ )
                                    {
                                        if( ! isspace( args.at( j ) ) )
                                            num_args++;
                                    }
                                }

                            }  //  close  =>  if(m<args.size())

                        }  //  close  =>  if(l<args.size())

                    }  //  close  =>  if(k<args.size())

                }  //  close  =>  if(j<args.size())

                switch( num_args )
                {
                case 1:  // There was 1 argument.
                    {
                        invalid = true;
                        break;
                    }
                case 2:  // There were 2 arguments.
                    {
                        int n = subtxt.neighbor( arg1, arg2 );
                        cout << "\'" << arg2.c_str() << "\' is next to \'" << arg1.c_str();
                        if( n != 1 )
                            cout << "\' " << n << " times in the text." << endl;
                        else
                            cout << "\' 1 time in the text." << endl;
                        break;
                    }
                case 3:  // There were 3 arguments.
                    {
                        if( arg1.size() != 2 )
                        {
                            invalid = true;
                            break;
                        }
                        if( arg1 == "-b" )
                        {
                            int n = subtxt.neighbor( arg2, arg3, H_BEFORE );
                            cout << "\'" << arg3.c_str() << "\' occurs before \'" << arg2.c_str();
                            if( n != 1 )
                                cout << "\' " << n << " times in the text." << endl;
                            else
                                cout << "\' 1 time in the text." << endl;
                        }
                        else if( arg1 == "-a" )
                        {
                            int n = subtxt.neighbor( arg2, arg3, H_AFTER );
                            cout << "\'" << arg3.c_str() << "\' occurs after \'" << arg2.c_str();
                            if( n != 1 )
                                cout << "\' " << n << " times in the text." << endl;
                            else
                                cout << "\' 1 time in the text." << endl;
                        }
                        else
                            invalid = true;

                        break;
                    }
                default:  // There were more than 3 arguments.
                    {
                        invalid = true;
                    }

                }  //  close  =>  switch(num_args)

                // If there were more than 3 arguments...
                if( invalid )
                {
                    cout << "Invalid arguments for \"neighbor\"." << endl;
                    cout << "Type \"help neighbor\" for command information." << endl;
                    continue;
                }

            }  //  close  =>  if(command.substr(0,9)=="neighbor ")

            else  // The command is invalid.
            {
                cout << "Invalid command: \"" << command.c_str() << "\"" << endl;
                cout << "Type \"help [command]\" for command information." << endl;
                continue;
            }

        }  // close  =>  "COMMAND:  neighbor [-b, -a] <a> <b>"

        //**************************************************************************

        // COMMAND:  percent <a>
        else if( command.substr( 0, 4 ) == "perc" )
        {
            if( command.size() < 9 )
            {
                cout << "Invalid command: \"" << command.c_str() << "\"" << endl;
                cout << "Type \"help [command]\" for command information." << endl;
                continue;
            }
            
            if( command.substr( 0, 8 ) == "percent " )
            {
                // Find the beginning of the argument to "percent"
                std::string args = command.substr( 8 );
                for( int i = 0; i < args.size(); i++ )
                {
                    if( ! isspace( args.at( i )) )
                        break;
                }
                
                // If there was no argument given,
                // the command is invalid.
                if( i == args.size() )
                {
                    cout << "\"percent\" requires an argument." << endl;
                    cout << "Type \"help percent\" for command information." << endl;
                    continue;
                }

                // Find the end of the argument to "percent"
                for( int j = i + 1; j < args.size(); j++ )
                {
                    if( isspace( args.at( j ) ) )
                        break;
                }
                
                std::string a = args.substr( i, (j - i) );
                j++;
                bool invalid = false;
                
                // If this character is not the end of the
                // argument string, verify that the rest is
                // just whitespace.
                while( j < args.size() )
                {
                    if( ! isspace( args.at( j ) ))
                    {
                        invalid = true;
                        break;
                    }
                    j++;
                }
                
                if( invalid )
                {
                    cout << "\"percent\" can only have 1 argument." << endl;
                    cout << "Type \"help percent\" for command information." << endl;
                    continue;
                }
                
                cout << " \"" << a.c_str() << "\" occurs ";
                cout << setprecision( 3 ) << subtxt.num_percent( a );
                cout << "% of the time." << endl;
                continue;
                
            }  // close  =>  if(command.substr(0,8)=="percent ")

            else  // The command is invalid.
            {
                cout << "Invalid command: \"" << command.c_str() << "\"" << endl;
                cout << "Type \"help [command]\" for command information." << endl;
                continue;
            }

        }  // close  =>  "COMMAND:  percent <a>"

        //**************************************************************************

        // COMMAND:  print [-c, -p]
        else if( command.substr( 0, 4 ) == "prin" )
        {
            if( command.size() < 5 )
            {
                cout << "Invalid command: \"" << command.c_str() << "\"" << endl;
                cout << "Type \"help [command]\" for command information." << endl;
                continue;
            }

            if( command == "print" )
            {
                subtxt.print_txt();
                continue;
            }

            if( command.substr( 0 , 5 ) == "print" )
            {
                // Now we know that the command string length > 5

                // Find the position of the argument
                for( int i = 5; i < command.size(); i++ )
                {
                    if( ! isspace( command.at( i ) ) )
                        break;
                }

                // If there are no arguments...
                if( i == command.size() )
                {
                    subtxt.print_txt();
                    continue;
                }

                // Find the end of the argument
                for( int j = i; j < command.size(); j++ )
                {
                    if( isspace( command.at( j ) ) )
                        break;
                }

                std::string arg = command.substr( i, (j - i) );

                bool invalid = false;
                if( j < command.size() )
                {
                    // Make sure there are no other arguments
                    for( i = j; i < command.size(); i++ )
                    {
                        if( ! isspace( command.at( i ) ) )
                        {
                            invalid = true;
                            break;
                        }
                    }
                }

                if( invalid )
                {
                    cout << "Invalid argument to \"print\"" << endl;
                    cout << "Type \"help print\" for command information." << endl;
                    continue;
                }

                if( arg == "-p" )
                    subtxt.print_txt();
                else if( arg == "-c" )
                    subtxt.print_txt( H_CIPHERTEXT );
                else
                {
                    cout << "Invalid argument to \"print\"" << endl;
                    cout << "Type \"help print\" for command information." << endl;
                    continue;
                }
            }
            else
            {
                cout << "Invalid command: \"" << command.c_str() << "\"" << endl;
                cout << "Type \"help [command]\" for command information." << endl;
                continue;
            }

        }  // close  =>  "COMMAND:  print [-c, -p]"

        //**************************************************************************

        // COMMAND:  save [-c, -n]
        else if( command.substr( 0, 4 ) == "save" )
        {
            int sz = command.size();
            std::string answer;

            if( sz > 4 )
            {
                // Find the position of the argument
                for( int i = 4; i < command.size(); i++ )
                {
                    if( ! isspace( command.at( i ) ) )
                        break;
                }

                // If there are no arguments...
                if( i == command.size() )
                {
                    if( plaintext_filename.size() < 1 )
                    {
                        cout << "Enter the name of the plaintext file: ";
                        cin.getline( c, 128 );
                        answer = c;
                        plaintext_filename = get_filename_string( answer );
                    }
                    else
                    {
                        cout << "Save to \"" << plaintext_filename.c_str() << "\"? ";
                        cout << "<y>es OR <new_filename>: ";
                        cin.getline( c, 128 );
                        answer = c;
                        answer = get_filename_string( answer );

                        if( answer == "y" || answer == "Y" ||
                            answer == "yes" || answer == "YES" || answer == "Yes" )
                        {
                            if( ! subtxt.save( plaintext_filename ) )
                                cout << "Unable to save to file: \"" << plaintext_filename.c_str() << "\"" << endl;
                            continue;
                        }

                        else
                            plaintext_filename = answer;
                    }

                    if( ! subtxt.save( plaintext_filename ) )
                        cout << "Unable to save to file: \"" << plaintext_filename.c_str() << "\"" << endl;
                    continue;
                }

                // Find the end of the argument
                for( int j = i; j < command.size(); j++ )
                {
                    if( isspace( command.at( j ) ) )
                        break;
                }

                std::string arg = command.substr( i, (j - i) );

                bool invalid = false;
                if( j < command.size() )
                {
                    // Make sure there are no other arguments
                    for( i = j; i < command.size(); i++ )
                    {
                        if( ! isspace( command.at( i ) ) )
                        {
                            invalid = true;
                            break;
                        }
                    }
                }

                if( invalid )
                {
                    cout << "Invalid argument to \"save\"" << endl;
                    cout << "Type \"help save\" for command information." << endl;
                    continue;
                }

                if( arg == "-n" )
                {
                    if( plaintext_filename.size() < 1 )
                    {
                        cout << "Enter the name of the plaintext file: ";
                        cin.getline( c, 128 );
                        answer = c;
                        plaintext_filename = get_filename_string( answer );
                    }
                    else
                    {
                        cout << "Save to \"" << plaintext_filename.c_str() << "\"? ";
                        cout << "<y>es OR <new_filename>: ";
                        cin.getline( c, 128 );
                        answer = c;
                        answer = get_filename_string( answer );

                        if( answer == "y" || answer == "Y" ||
                            answer == "yes" || answer == "YES" || answer == "Yes" )
                        {
                            if( ! subtxt.save( plaintext_filename ) )
                                cout << "Unable to save to file: \"" << plaintext_filename.c_str() << "\"" << endl;
                            continue;
                        }

                        else
                            plaintext_filename = answer;
                    }

                    if( ! subtxt.save( plaintext_filename, false ) )
                        cout << "Unable to save to file: \"" << plaintext_filename.c_str() << "\"" << endl;
                    continue;
                }
                else if( arg == "-c" )
                {
                    if( plaintext_filename.size() < 1 )
                    {
                        cout << "Enter the name of the plaintext file: ";
                        cin.getline( c, 128 );
                        answer = c;
                        plaintext_filename = get_filename_string( answer );
                    }
                    else
                    {
                        cout << "Save to \"" << plaintext_filename.c_str() << "\"? ";
                        cout << "<y>es OR <new_filename>: ";
                        cin.getline( c, 128 );
                        answer = c;
                        answer = get_filename_string( answer );

                        if( answer == "y" || answer == "Y" ||
                            answer == "yes" || answer == "YES" || answer == "Yes" )
                        {
                            if( ! subtxt.save( plaintext_filename ) )
                                cout << "Unable to save to file: \"" << plaintext_filename.c_str() << "\"" << endl;
                            continue;
                        }

                        else
                            plaintext_filename = answer;
                    }

                    if( ! subtxt.save( plaintext_filename ) )
                        cout << "Unable to save to file: \"" << plaintext_filename.c_str() << "\"" << endl;
                    continue;
                }
                else
                {
                    cout << "Invalid argument to \"save\"" << endl;
                    cout << "Type \"help save\" for command information." << endl;
                    continue;
                }
            }
            else
            {
                if( plaintext_filename.size() < 1 )
                {
                    cout << "Enter the name of the plaintext file: ";
                    cin.getline( c, 128 );
                    answer = c;
                    plaintext_filename = get_filename_string( answer );
                }
                else
                {
                    cout << "Save to \"" << plaintext_filename.c_str() << "\"? ";
                    cout << "<y>es OR <new_filename>: ";
                    cin.getline( c, 128 );
                    answer = c;
                    answer = get_filename_string( answer );
                    
                    if( answer == "y" || answer == "Y" ||
                        answer == "yes" || answer == "YES" || answer == "Yes" )
                    {
                        if( ! subtxt.save( plaintext_filename ) )
                            cout << "Unable to save to file: \"" << plaintext_filename.c_str() << "\"" << endl;
                        continue;
                    }
                    
                    else
                        plaintext_filename = answer;
                }
                
                if( ! subtxt.save( plaintext_filename ) )
                    cout << "Unable to save to file: \"" << plaintext_filename.c_str() << "\"" << endl;
                continue;
            }


        }  // close  =>  "COMMAND:  save [-c, -n]"

        //**************************************************************************

        // COMMAND:  exit
        else if( command.substr( 0, 4 ) == "exit" )
        {
            bool invalid = false;
            if( command.size() > 4 )
            {
                for( int i = 4; i < command.size(); i++ )
                {
                    if( ! isspace( command.at( i ) ) )
                    {
                        cout << "Invalid command: \"" << command.c_str() << "\"" << endl;
                        cout << "Type \"help [command]\" for command information." << endl;
                        invalid = true;
                        break;
                    }
                }
            }

            if( ! invalid )
                exit( 0 );

        }  // close  =>  "COMMAND:  exit"

        //**************************************************************************

        // INVALID COMMAND.
        else
        {
            cout << "Invalid command: \"" << command.c_str() << "\"" << endl;
            cout << "Type \"help [command]\" for command information." << endl;
        }

    }  // close  =>  while(true)
}


//*******************************************************************
//*                                                                 *
//*  METHOD:     print_general_help()                               *
//*  PURPOSE:    To print a list of valid commands (with syntax).   *
//*  ARGUMENTS:  None.                                              *
//*  RETURNS:    Nothing.                                           *
//*  NOTES:      None.                                              *
//*                                                                 *
//*******************************************************************
void print_general_help()
{
    cout << endl;
    cout << "---------------------------------------------------------" << endl;
    cout << "\t\tCOMMAND LIST" << endl;
    cout << "---------------------------------------------------------" << endl;
    cout << "1)  sub <a> <b>             7)  table [-g] <n>" << endl;
    cout << "2)  undo [n]                8)  neighbor [-b, -a] <a> <b>" << endl;
    cout << "3)  save [-c, -n]           9)  percent <a>" << endl;
    cout << "4)  print [-c, -p]         10)  freq <a>" << endl;
    cout << "5)  exit                   11)  ngram [n]" << endl;
    cout << "6)  help [command]" << endl;
    cout << "---------------------------------------------------------" << endl << endl;
    cout << "=========================================================" << endl;
    cout << "Note: Angle  brackets \"<>\" indicate required arguments." << endl;
    cout << "      Square brackets \"[]\" indicate optional arguments." << endl;
    cout << "=========================================================" << endl;
    cout << "For help with a specific command," << endl;
    cout << "    type \"help\" followed by the command name." << endl;
    cout << "Example:  For help with the \"sub\" command..." << endl;
    cout << "    type \"help sub\"" << endl;
    cout << "=========================================================" << endl;
    cout << endl;
}


//*******************************************************************
//*                                                                 *
//*  METHOD:     print_sub_help()                                   *
//*  PURPOSE:    To print a detailed description of the "sub"       *
//*              command.                                           *
//*  ARGUMENTS:  None.                                              *
//*  RETURNS:    Nothing.                                           *
//*  NOTES:      None.                                              *
//*                                                                 *
//*******************************************************************
void print_sub_help()
{
    cout << endl;
    cout << "==========================================================" << endl;
    cout << "COMMAND:    sub <a> <b>" << endl;
    cout << "PURPOSE:    The purpose of the \"sub\" command is to allow" << endl;
    cout << "            the user to substitute one number or character" << endl;
    cout << "            for another in the text." << endl;
    cout << "            With the \"sub <a> <b>\" command, argument \'a\'" << endl;
    cout << "            is substituted for argument \'b\'" << endl;
    cout << "ARGUMENTS:  Required." << endl;
    cout << "            There are two arguments to the \"sub <a> <b>\"" << endl;
    cout << "            command and both are required.  Each argument" << endl;
    cout << "            is a string separated by whitespace." << endl;
    cout << "NOTES:      <a> is substituted for <b>." << endl;
    cout << "EXAMPLE:    Given the text:  \"43 6911 7 380 7\"" << endl;
    cout << "            and the commands: sub A 43" << endl;
    cout << "                              sub A 7" << endl;
    cout << "                              sub B A" << endl;
    cout << "            text becomes:    \"A 6911 7 380 7\"" << endl;
    cout << "            then:            \"A 6911 A 380 A\"" << endl;
    cout << "            then:            \"B 6911 A 380 A\"" << endl;
    cout << "            Notice that only the \"A\" that was substituted" << endl;
    cout << "            first becomes a \"B\".  This is because only" << endl;
    cout << "            numbers and characters that have not been" << endl;
    cout << "            changed for the longest amount of time are" << endl;
    cout << "            substituted." << endl;
    cout << "==========================================================" << endl;
    cout << endl;
}


//*******************************************************************
//*                                                                 *
//*  METHOD:     print_undo_help()                                  *
//*  PURPOSE:    To print a detailed description of the "undo"      *
//*              command.                                           *
//*  ARGUMENTS:  None.                                              *
//*  RETURNS:    Nothing.                                           *
//*  NOTES:      None.                                              *
//*                                                                 *
//*******************************************************************
void print_undo_help()
{
    cout << endl;
    cout << "==========================================================" << endl;
    cout << "COMMAND:    undo [n]" << endl;
    cout << "PURPOSE:    The purpose of the \"undo\" command is to undo" << endl;
    cout << "            a the last \"n\" substitutions." << endl;
    cout << "ARGUMENTS:  Optional." << endl;
    cout << "            The \"undo\" command can be used without any" << endl;
    cout << "            arguments.  In this case, it simple undoes the" << endl;
    cout << "            last substitution.  However, it can be given" << endl;
    cout << "            positive integer argument, which tell the" << endl;
    cout << "            \"undo\" command how many substitutions to" << endl;
    cout << "            undo." << endl;
    cout << "NOTES:      The \"undo\" command will undo at most the" << endl;
    cout << "            number of substitutions that have been done." << endl;
    cout << "            If the \"undo\" command is given an argument" << endl;
    cout << "            less than 1, nothing will be undone." << endl;
    cout << "EXAMPLE:    undo 4" << endl;
    cout << "            This will undo the last 4 substitutions if" << endl;
    cout << "            there has been at least 4 substitutions made." << endl;
    cout << "            If there has been less than 4 substitutions" << endl;
    cout << "            made, all will be undone." << endl;
    cout << "==========================================================" << endl;
    cout << endl;
}


//*******************************************************************
//*                                                                 *
//*  METHOD:     print_save_help()                                  *
//*  PURPOSE:    To print a detailed description of the "save"      *
//*              command.                                           *
//*  ARGUMENTS:  None.                                              *
//*  RETURNS:    Nothing.                                           *
//*  NOTES:      None.                                              *
//*                                                                 *
//*******************************************************************
void print_save_help()
{
    cout << endl;
    cout << "==========================================================" << endl;
    cout << "COMMAND:    save [-c, -n]" << endl;
    cout << "PURPOSE:    The purpose of the \"save\" command is to save" << endl;
    cout << "            the plaintext to a file." << endl;
    cout << "ARGUMENTS:  Optional." << endl;
    cout << "            The \"save\" command can be used without any" << endl;
    cout << "            arguments.  In this case the ciphertext is" << endl;
    cout << "            saved at the top of the file and the plaintext" << endl;
    cout << "            is saved at the bottom of the file." << endl;
    cout << "            However, there are also two switches that can" << endl;
    cout << "            be used with the \"save\" command.  Only one" << endl;
    cout << "            switch can be used at a time.  Using the \"-c\"" << endl;
    cout << "            switch just produces the default behavior of" << endl;
    cout << "            saving the ciphertext with the plaintext." << endl;
    cout << "            Using the \"-n\" switch causes the \"save\"" << endl;
    cout << "            command to save only the plaintext; that is," << endl;
    cout << "            to \"not\" save the ciphertext with the" << endl;
    cout << "            plaintext." << endl;
    cout << "NOTES:      The user will be prompted for the name of the" << endl;
    cout << "            file to which to save." << endl;
    cout << endl;
    cout << "            The ciphertext is considered to be the" << endl;
    cout << "            original text from the ciphertext file." << endl;
    cout << "            The plaintext is considered to be the text" << endl;
    cout << "            on which the user is working.  This text" << endl;
    cout << "            will be identical to the ciphertext if no" << endl;
    cout << "            substitutions are made.  But in any case," << endl;
    cout << "            the plaintext may not be fully decrypted." << endl;
    cout << "EXAMPLE:    save -n" << endl;
    cout << "            This will save the plaintext without the" << endl;
    cout << "            ciphertext." << endl;
    cout << "==========================================================" << endl;
    cout << endl;
}


//*******************************************************************
//*                                                                 *
//*  METHOD:     print_print_help()                                 *
//*  PURPOSE:    To print a detailed description of the "print"     *
//*              command.                                           *
//*  ARGUMENTS:  None.                                              *
//*  RETURNS:    Nothing.                                           *
//*  NOTES:      None.                                              *
//*                                                                 *
//*******************************************************************
void print_print_help()
{
    cout << endl;
    cout << "==========================================================" << endl;
    cout << "COMMAND:    print [-c, -p]" << endl;
    cout << "PURPOSE:    The purpose of the \"print\" command is to" << endl;
    cout << "            print the ciphertext or the plaintext to the." << endl;
    cout << "            screen." << endl;
    cout << "ARGUMENTS:  Optional." << endl;
    cout << "            The \"print\" command can be use without any" << endl;
    cout << "            arguments.  In this case the plaintext is" << endl;
    cout << "            printed.  However, there are also two switches" << endl;
    cout << "            that can be used with the \"print\" command." << endl;
    cout << "            Only one switch can be used at a time.  Using" << endl;
    cout << "            the \"-p\" switch just produces the default" << endl;
    cout << "            behavior of printing the plaintext.  Using" << endl;
    cout << "            the \"-c\" switch causes the \"print\" command" << endl;
    cout << "            to print the ciphertext." << endl;
    cout << "NOTES:      The ciphertext is considered to be the" << endl;
    cout << "            original text from the ciphertext file." << endl;
    cout << "            The plaintext is considered to be the text" << endl;
    cout << "            on which the user is working.  This text" << endl;
    cout << "            will be identical to the ciphertext if no" << endl;
    cout << "            substitutions are made.  But in any case," << endl;
    cout << "            the plaintext may not be fully decrypted." << endl;
    cout << "EXAMPLE:    print -c" << endl;
    cout << "            This will print the ciphertext to the screen." << endl;
    cout << "==========================================================" << endl;
    cout << endl;
}


//*******************************************************************
//*                                                                 *
//*  METHOD:     print_exit_help()                                  *
//*  PURPOSE:    To print a detailed description of the "exit"      *
//*              command.                                           *
//*  ARGUMENTS:  None.                                              *
//*  RETURNS:    Nothing.                                           *
//*  NOTES:      None.                                              *
//*                                                                 *
//*******************************************************************
void print_exit_help()
{
    cout << endl;
    cout << "==========================================================" << endl;
    cout << "COMMAND:    exit" << endl;
    cout << "PURPOSE:    The purpose of the \"exit\" command is to" << endl;
    cout << "            terminate the program." << endl;
    cout << "ARGUMENTS:  None." << endl;
    cout << "EXAMPLE:    exit" << endl;
    cout << "            This terminates the program." << endl;
    cout << "==========================================================" << endl;
    cout << endl;
}


//*******************************************************************
//*                                                                 *
//*  METHOD:     print_help_help()                                  *
//*  PURPOSE:    To print a detailed description of the "help"      *
//*              command.                                           *
//*  ARGUMENTS:  None.                                              *
//*  RETURNS:    Nothing.                                           *
//*  NOTES:      None.                                              *
//*                                                                 *
//*******************************************************************
void print_help_help()
{
    cout << endl;
    cout << "==========================================================" << endl;
    cout << "COMMAND:    help [command]" << endl;
    cout << "PURPOSE:    The purpose of the \"help\" command is to" << endl;
    cout << "            provide help for using this program's command-" << endl;
    cout << "            line interface by printing command information" << endl;
    cout << "            to the screen." << endl;
    cout << "ARGUMENTS:  Optional." << endl;
    cout << "            The \"help\" command can be use without any" << endl;
    cout << "            arguments.  In this case a general help screen" << endl;
    cout << "            is printed, which lists all available commands." << endl;
    cout << "            However, the \"help\" command can take one of" << endl;
    cout << "            the available commands (without its arguments)" << endl;
    cout << "            as an argument.  This provides a detailed" << endl;
    cout << "            description of that command and an example" << endl;
    cout << "            of its use." << endl;
    cout << "EXAMPLE:    help undo" << endl;
    cout << "            This prints a description similar to this one"  << endl;
    cout << "            for the \"undo\" command." << endl;
    cout << "==========================================================" << endl;
    cout << endl;
}


//*******************************************************************
//*                                                                 *
//*  METHOD:     print_table_help()                                 *
//*  PURPOSE:    To print a detailed description of the "table"     *
//*              command.                                           *
//*  ARGUMENTS:  None.                                              *
//*  RETURNS:    Nothing.                                           *
//*  NOTES:      None.                                              *
//*                                                                 *
//*******************************************************************
void print_table_help()
{
    cout << endl;
    cout << "==========================================================" << endl;
    cout << "COMMAND:    table [-g] <n>" << endl;
    cout << "PURPOSE:    The purpose of the \"table\" command is to" << endl;
    cout << "            print the user's choice of 2 types of tables" << endl;
    cout << "            to the screen.  The choices are as follows." << endl;
    cout << "            General Social Index Table on the \"n\" most" << endl;
    cout << "               frequently occurring numbers or characters." << endl;
    cout << "            Frequency Table on all numbers or characters" << endl;
    cout << "               that appear in the plaintext (as defined" << endl;
    cout << "               in the notes below)." << endl;
    cout << "ARGUMENTS:  Optional / Required (based on table choice)." << endl;
    cout << "            The \"table\" command can be used without any" << endl;
    cout << "            arguments.  In this case the frequency table" << endl;
    cout << "            is printed.  This table shows the frequency" << endl;
    cout << "            (the number of occurrences) of each number" << endl;
    cout << "            or character and the percentage of the time" << endl;
    cout << "            each occurs.  However, there is also a" << endl;
    cout << "            switch that can be used with the \"table\"" << endl;
    cout << "            command." << endl;
    cout << "            Using the \"-g\" switch, causes the \"General" << endl;
    cout << "            Social Index Table\" to be printed." << endl;
    cout << "            Using this switch REQUIRES another argument" << endl;
    cout << "            after the switch.  This subsequent argument" << endl;
    cout << "            must be an positive integer, \"n\"." << endl;
    cout << "            The \"General Index Table will then be printed" << endl;
    cout << "            for the \"n\" most frequently occurring" << endl;
    cout << "            numbers or characters." << endl;
    cout << "NOTES:      The ciphertext is considered to be the" << endl;
    cout << "            original text from the ciphertext file." << endl;
    cout << "            The plaintext is considered to be the text" << endl;
    cout << "            on which the user is working.  This text" << endl;
    cout << "            will be identical to the ciphertext if no" << endl;
    cout << "            substitutions are made.  But in any case," << endl;
    cout << "            the plaintext may not be fully decrypted." << endl;
    cout << "EXAMPLES:   table -g 30" << endl;
    cout << "            This will print the \"General Social Index" << endl;
    cout << "            Table for the 30 most frequently occurring" << endl;
    cout << "            numbers or characters." << endl;
    cout << "            If there are fewer than 30 distinct numbers" << endl;
    cout << "            or characters in the plaintext, the \"General" << endl;
    cout << "            Social Index Table will be printed on all" << endl;
    cout << "            numbers or characters in the plaintext." << endl;
    cout << "==========================================================" << endl;
    cout << endl;
}


//*******************************************************************
//*                                                                 *
//*  METHOD:     print_neighbor_help()                              *
//*  PURPOSE:    To print a detailed description of the "neighbor"  *
//*              command.                                           *
//*  ARGUMENTS:  None.                                              *
//*  RETURNS:    Nothing.                                           *
//*  NOTES:      None.                                              *
//*                                                                 *
//*******************************************************************
void print_neighbor_help()
{
    cout << endl;
    cout << "==========================================================" << endl;
    cout << "COMMAND:    neighbor [-b, -a] <a> <b>" << endl;
    cout << "PURPOSE:    The purpose of the \"neighbor\" command is to" << endl;
    cout << "            print the number of times a number or" << endl;
    cout << "            character is beside (before, after) other" << endl;
    cout << "            numbers or characters in the plaintext." << endl;
    cout << "            This is the \"neighbor count.\"" << endl;
    cout << "ARGUMENTS:  Required." << endl;
    cout << "            The \"neighbor\" command cannot be used" << endl;
    cout << "            without at least two arguments.  Each required" << endl;
    cout << "            argument, <a> and <b>, is a string." << endl;
    cout << "            With no other arguments, the neighbor count" << endl;
    cout << "            reports the number or times that <b> appears" << endl;
    cout << "            both before and after <a> in the plaintext" << endl;
    cout << "            (as defined in the notes below)." << endl;
    cout << "            There are also 2 optional switches that can be" << endl;
    cout << "            used.  ONLY one switch can be used at a time." << endl;
    cout << "            Using the \"-b\" switch causes the \"neighbor\"" << endl;
    cout << "            command to report the neighbor count only for" << endl;
    cout << "            occurrences of <b> that appear directly before" << endl;
    cout << "            <a> in the plaintext." << endl;
    cout << "            Using the \"-a\" switch causes the \"neighbor\"" << endl;
    cout << "            command to report the neighbor count only for" << endl;
    cout << "            occurrences of <b> that appear directly after" << endl;
    cout << "            <a> in the plaintext." << endl;
    cout << "NOTES:      The ciphertext is considered to be the" << endl;
    cout << "            original text from the ciphertext file." << endl;
    cout << "            The plaintext is considered to be the text" << endl;
    cout << "            on which the user is working.  This text" << endl;
    cout << "            will be identical to the ciphertext if no" << endl;
    cout << "            substitutions are made.  But in any case," << endl;
    cout << "            the plaintext may not be fully decrypted." << endl;
    cout << "EXAMPLE:    neighbor -a 21467 951" << endl;
    cout << "            This reports the number of times that \"951\"" << endl;
    cout << "            appear after \"21467\" in the plaintext" << endl;
    cout << "            (as defined in the notes above)." << endl;
    cout << endl;
    cout << "            neighbor , 44" << endl;
    cout << "            This reports the number of times that \"44\" is" << endl;
    cout << "            is next to a comma (\',\') in the plaintext" << endl;
    cout << "            (as defined in the notes above)." << endl;
    cout << "==========================================================" << endl;
    cout << endl;
}


//*******************************************************************
//*                                                                 *
//*  METHOD:     print_percent_help()                               *
//*  PURPOSE:    To print a detailed description of the "percent"   *
//*              command.                                           *
//*  ARGUMENTS:  None.                                              *
//*  RETURNS:    Nothing.                                           *
//*  NOTES:      None.                                              *
//*                                                                 *
//*******************************************************************
void print_percent_help()
{
    cout << endl;
    cout << "==========================================================" << endl;
    cout << "COMMAND:    percent <a>" << endl;
    cout << "PURPOSE:    The purpose of the \"percent\" command is to" << endl;
    cout << "            report the percentage of the time that a" << endl;
    cout << "            particular number or character occurs in the" << endl;
    cout << "            plaintext (as defined in the notes below)." << endl;
    cout << "ARGUMENTS:  Required." << endl;
    cout << "            The \"percent\" command must have exactly one" << endl;
    cout << "            argument.  This argument is a string." << endl;
    cout << "            It is this string's frequency percentage" << endl;
    cout << "            that will be reported." << endl;
    cout << "NOTES:      The argument string cannot contain any" << endl;
    cout << "            whitespace characters." << endl;
    cout << endl;
    cout << "            The ciphertext is considered to be the" << endl;
    cout << "            original text from the ciphertext file." << endl;
    cout << "            The plaintext is considered to be the text" << endl;
    cout << "            on which the user is working.  This text" << endl;
    cout << "            will be identical to the ciphertext if no" << endl;
    cout << "            substitutions are made.  But in any case," << endl;
    cout << "            the plaintext may not be fully decrypted." << endl;
    cout << "EXAMPLE:    percent 11347" << endl;
    cout << "            This will report the frequency percentage for" << endl;
    cout << "            the string \"11347\"." << endl;
    cout << "==========================================================" << endl;
    cout << endl;
}


//*******************************************************************
//*                                                                 *
//*  METHOD:     print_freq_help()                                  *
//*  PURPOSE:    To print a detailed description of the "freq"      *
//*              command.                                           *
//*  ARGUMENTS:  None.                                              *
//*  RETURNS:    Nothing.                                           *
//*  NOTES:      None.                                              *
//*                                                                 *
//*******************************************************************
void print_freq_help()
{
    cout << endl;
    cout << "==========================================================" << endl;
    cout << "COMMAND:    freq <a>" << endl;
    cout << "PURPOSE:    The purpose of the \"freq\" command is to" << endl;
    cout << "            report the number of occurrences of a" << endl;
    cout << "            particular number or character in the" << endl;
    cout << "            plaintext (as defined in the notes below)." << endl;
    cout << "ARGUMENTS:  Required." << endl;
    cout << "            The \"freq\" command must have exactly one" << endl;
    cout << "            argument.  This argument is a string." << endl;
    cout << "            It is this string's frequency that will be" << endl;
    cout << "            reported." << endl;
    cout << "NOTES:      The argument string cannot contain any" << endl;
    cout << "            whitespace characters." << endl;
    cout << endl;
    cout << "            The ciphertext is considered to be the" << endl;
    cout << "            original text from the ciphertext file." << endl;
    cout << "            The plaintext is considered to be the text" << endl;
    cout << "            on which the user is working.  This text" << endl;
    cout << "            will be identical to the ciphertext if no" << endl;
    cout << "            substitutions are made.  But in any case," << endl;
    cout << "            the plaintext may not be fully decrypted." << endl;
    cout << "EXAMPLE:    freq 11347" << endl;
    cout << "            This will report the frequency of the" << endl;
    cout << "            string \"11347\"." << endl;
    cout << "==========================================================" << endl;
    cout << endl;
}


//*******************************************************************
//*                                                                 *
//*  METHOD:     print_ngram_help()                                 *
//*  PURPOSE:    To print a detailed description of the "ngram"     *
//*              command.                                           *
//*  ARGUMENTS:  None.                                              *
//*  RETURNS:    Nothing.                                           *
//*  NOTES:      None.                                              *
//*                                                                 *
//*******************************************************************
void print_ngram_help()
{
    cout << endl;
    cout << "==========================================================" << endl;
    cout << "COMMAND:    ngram [n]" << endl;
    cout << "PURPOSE:    The purpose of the \"ngram\" command is to" << endl;
    cout << "            report the number of occurrences of a" << endl;
    cout << "            particular \"n\"-gram in the text" << endl;
    cout << "ARGUMENTS:  Optional" << endl;
    cout << "            If no argument is given, the \"n\" defaults" << endl;
    cout << "            to 2, and table becomes a digram table." << endl;
    cout << "NOTES:      ONLY ngrams that appear at least twice are" << endl;
    cout << "            reported in the table." << endl;
    cout << "            An \"ngram\" is an ordered set of \"n\" numbers" << endl;
    cout << "            or characters." << endl;
    cout << "              Example:  a \"digram\" would be a 2-gram," << endl;
    cout << "              such as: \"th\", \"sh\", \"101 43\", etc." << endl;
    cout << "              A trigram would be a 3-gram, such as:" << endl;
    cout << "              \"the\", \"and\", \"2753 12 781\", etc." << endl;
    cout << "EXAMPLE:    ngram 3" << endl;
    cout << "            This reports the frequency of all trigrams" << endl;
    cout << "            that appear at least twice in the text." << endl;
    cout << "==========================================================" << endl;
    cout << endl;
}



//*******************************************************************
//*                                                                 *
//*  METHOD:     get_filename_string( std::string s )               *
//*  PURPOSE:    To get the first whitespace-separated string from  *
//*              the string s.                                      *
//*  ARGUMENTS:  A std::string object from which the first word     *
//*              is extracted.                                      *
//*  RETURNS:    The first extracted word as a std::string          *
//*  NOTES:      None.                                              *
//*                                                                 *
//*******************************************************************
std::string get_filename_string( std::string s )
{   
    // Find the first character of the answer
    for( int i = 0; i < s.size(); i++ )
    {
        if( ! isspace( s.at( i ) ) )
            break;
    }
    
    // Find the end of the answer
    for( int j = i + 1; j < s.size(); j++ )
    {
        if( isspace( s.at( j ) ) )
            break;
    }
    
    s = s.substr( i , (j - i) );
    
    return s;
}



