//  Program:  simple_stats.cpp
//  Author:   Prof. Chuck Stewart
//  Purpose:  Demonstrate the use of command-line arguments and file
//    input. 

//  Notice in the includes we have added <fstream>.  This is needed
//  if you are going to read from or write to files.  You will also
//  notice that I don't have a "using namespace std;" line here.  I
//  generally will not do this in order to clearly show what is in
//  the standard library namespace, but you are welcome to use this
//  line in your programs.

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

//  The main program now has arguments.  An argument is a C-style
//  string that is passed to the program. (C-style strings are arrays
//  of chars (or pointers to chars, written as char*) that end with a
//  '\0' char.  This is not something you need to know much about as
//  long as you follow this example.)  Arguments are usually typed
//  from a command-prompt and the underlying "shell" program launches
//  your program by passing it these arguments.  (In the instructions
//  for lab you will see how to specify these when running your
//  program from within Visual Studio.)  In doing so, the shell
//  packages these arguments into an array of C-style strings.  This
//  array is argv, and the number of arguments is passed to the
//  parameter argc.

int
main( int argc, char* argv[] )
{
  //  The first thing this program does is print the command-line
  //  arguments, one at a time.  As you will see when you run the
  //  program, the 0-th command-line argument is ALWAYS the name of
  //  the program.  (This makes sense, because it is what you typed
  //  on the command-line.)   Your programs do not have to print the
  //  command-line arguments.

  std::cout << "\nHere are the arguments to the program:\n";
  for ( int i=0; i<argc; ++i )
    {
      std::cout << "    argv[" << i << "]:  " << argv[i] << "\n";
    }

  //  Next, the program tests to see if it indeed has the expected
  //  number of arguments.  If it does not have 2, it outputs an
  //  appropriate error message to the error stream, cerr, and
  //  terminates the program.  By returning 1 or some other non-zero
  //  value it is signaling that something was wrong.  Shell or perl
  //  scripts often make use of these return values.  We will not do
  //  this at all in CS II.

  if ( argc != 2 )
    {
      std::cerr << "Usage: " << argv[0] << " numbers-file\n";
      return 1;
    }

  //  The program is now ready to open the file for input.  This is
  //  done by "constructing" a stream object, called numbers_str,
  //  passing the name of the file as an argument.  If the program
  //  fails to open the file, then numbers_str will not be properly
  //  created.  This can be tested by applying the ! operator to
  //  numbers_str.  The operator will return true to indicate that the
  //  file was not properly opened.  In this case, the program outputs
  //  an error message and quits.
  
  std::ifstream numbers_str( argv[1] );
  if ( !numbers_str )
    {
      std::cerr << "Can't open " << argv[1] << " to read numbers.\n";
      return 1;
    }

  int count = 0;
  float sum_values = 0;
  float value;

  //  Now the program is ready to do the actual computation.  In a
  //  loop, the program reads the float values from the file, one at
  //  a time.  For each new value read, the program increments the
  //  cout and adds the value to the sum. 
  //
  //  The trickiest part to this is the condition in the while loop.
  //  Consider the expression
  //
  //       numbers_str >> value
  //
  //  In the execution of this expression, numbers_str attempts to
  //  read the next float from the input file and, if it is
  //  successful, it places the float in the variable called value.
  //  If it is unsuccessful, the while loop will terminate.  This
  //  termination is a good thing when the stream has reached the end
  //  of the input and no more float values are available.  This is
  //  bad when the next non-whitespace char to be read can not be
  //  converted to a float --- e.g. if the next char is a alphabetic
  //  or punctuation.  We do not make a distinction between these in
  //  this program.  
  //
  //  The actual mechanism is slightly tricky, but instructive.
  //  Remember from Lecture 1 that "numbers_str >> value" is an
  //  expression.  The value of this expression is the stream
  //  numbers_str.  The condition test (for true or false) asks
  //  numbers_str if it was able to successful read the float value
  //  it tried to read.  If the answer is true then the condition is
  //  true and the while loop continues.  If the answer is false,
  //  then the while loop terminates.

  while ( numbers_str >> value )
    {
      count ++ ;
      sum_values += value;
    }

  //  Use the "ordinary" cout to output the average to the
  //  command-prompt display.  Note that this program will crash if
  //  count is 0.

  std::cout << "The average of " << count << " values in " << argv[1] 
	    << " is " << sum_values / count << std::endl;

  return 0;
}

