// classifyChar2B.cpp
//
// Classifies the characters in an
// entered string of 1 to 15 characters,
// using logical operators.
// Uses interactive input.
// Outputs to a text file.
// Uses programmer-defined functions instead
// of setw, to avoid including <iomanip>

#include <iostream>
#include <string>
#include <fstream>

using namespace std;

void printRightJustified(int numberToPrint,
                         int columnWidth,
                         ofstream& output);
int digitCount(int n);


/*
 * Outputs, to a text file classification.txt,
 * a table classifying the characters in an
 * entered string.
 *
 * The characters are classified as ASCII
 * letters, ASCII digits, ASCII space,
 * ASCII punctuation marks, ASCII control
 * characters, or non-ASCII characters.
 *
 * Global variables:
 *    cin - an istream object for interactive input.
 *           cin is an external variable, declared
 *           in library header file <iostream>.
 *    cout - an ostream object for output to the terminal.
 *           cout is an external variable, declared
 *           in library header file <iostream>.
 */
int main()
{
   cout << "Enter a string between 1 and 15 characters long:>";

   string text;            // to be entered by the user
   getline( cin, text );   // input entire line, including spaces
   cout << endl;

   // Check whether string length is within range:
   if ( text.length() == 0 || text.length() > 15 )  {
      cout << "You entered a string of length "
                 << text.length()
                 << ", should be between 1 and 15." << endl;
      return 1;
   }  // if

   // Prepare to write to output file classification.txt:
   ofstream outFile;
   char* outputFilename = "classification.txt";   // C-string
   outFile.open(outputFilename);
   if ( !outFile )  {
      cout << "Could not open file "
                 << outputFilename << "." << endl;
      return 1;
   }  // if

   // Print table headings:
   outFile << "Position   Character   Classification" << endl;
   outFile << "--------   ---------   --------------" << endl << endl;

   // Print table body:
   for ( int i = 0; i < text.length(); i++ )  {

      // Display character's position in string text:
      printRightJustified( i, 5, outFile );

      // Display the character itself:
      char x = text[i];   // character at position i in string text
      outFile << "          " << x << "        ";

      // Classify the character:
      if ( x < 0 )
         outFile << "non-ASCII character" << endl;
      else if ( x == ' ' )
         outFile << "ASCII space" << endl;
      else if ( x >= '0' && x <= '9' )
         outFile << "ASCII digit" << endl;
      else if ( (x >= 'A' && x <= 'Z')
               || (x >= 'a' && x <= 'z') )
         outFile << "ASCII letter" << endl;
      else if ( x < 32 || x == 127 )
         outFile << "ASCII control character" << endl;
      else
         outFile << "ASCII punctuation mark" << endl;
   }  // for i

   cout << "File " << outputFilename
               << " has been created." << endl;

   return 0;
}  // function main


/*
 * void printRightJustified(int numberToPrint,
 *                          int columnWidth,
 *                          ofstream& outputFile)
 *
 * Prints an integer with enough leading spaces
 * to line it up in a right-justified column
 * with the specified width.
 *
 * Parameters:
 *    numberToPrint - the integer to be printed.
 *    columnWidth - total number of characters in a
 *         line of the desired right-justified column,
 *         including leading spaces.
 *    outputFile - a file output stream
 *       Precondition:  the state of output is true.
 *       PostconcitionL  the state of output is still true.
 */
void printRightJustified(int numberToPrint,
                         int columnWidth,
                         ofstream& outputFile)
{
   int nonSpaceCharacters
            = digitCount(numberToPrint)
               + ( ( numberToPrint < 0 ) ? 1 : 0 );
   int leadingSpaces
            = columnWidth - nonSpaceCharacters;

   for ( int i = 0; i < leadingSpaces; i++ )
      outputFile << " ";

   outputFile << numberToPrint;
}  // function printRightJustified


/*
 * int digitCount(int n)
 *
 * Counts base-10 digits in the specifed integer.
 *
 * Parameter:
 *    n - the integer whose digits are to be counted.
 *
 * Returns:
 *    The number of digits in a base-10
 *    representation of n.
 */
int digitCount(int n)
{
   if ( n < 0 )
      n = 0 - n;

   int numberOfDigits = 1;

   while ( n >= 10 )  {
      n = n / 10;
      numberOfDigits++;
   }  // while

   return numberOfDigits;
}  // function digitCount