/* This file contains the implementation for class Table.

-------------------------------------------------------------------*/

#include "Table.h"

#include <assert.h>
#include <iostream.h>
#include <stdlib.h>

/*------------------------------------------------------------------
   This function is the class constructor for class Table.
   
   Precondition:  A Table object has been declared.
   Receive:       NumRows (optional), the number of rows in the Table
                  NumCols (optional), the number of columns in the 
                     Table
                  InitValue (default value zero), to initialize
                     the values of the Table's elements
   Postcondition: The declared Table object containing this function
                     has its Rows_ member initialized to NumRows
                     and its Columns_ member initialized to NumCols.
-------------------------------------------------------------------*/

Table::Table(unsigned NumRows, unsigned NumCols,
             TableElement InitValue)
{
   Rows_ = NumRows;                     // set the scalar members
   Columns_ = NumCols;

   if (NumRows > 0)                     // if not empty
   {
      Grid = new Row[NumRows];          //   allocate array of Row
      assert(Grid != 0);                //   verify success
      for (int r = 0; r < NumRows; r++) //   build NumRows Rows,
         Grid[r] = Row(NumCols);        //     each of length NumCols

                                        //   now fill the 2-dim array
      for (int row = 0; row < NumRows; row++)
         for (int col = 0; col < NumCols; col++)
            Grid[row][col] = InitValue;
   }
   else                                 // otherwise
      Grid = 0;                         //    set Grid to NULL address
}

/*------------------------------------------------------------------
   This function makes a copy of a Table object.

   Precondition:  The compiler nees a copy of a table object.
   Received:      The Table (reference) object Original to be copied
   Postcondition: The members of the object containing this function,
                  are copies of those of Original.
-------------------------------------------------------------------*/

Table::Table(const Table& Original)
{
   Rows_ = Original.Rows_;            // copy Rows_
   Columns_ = Original.Columns_;      // copy Columns_
                                      // copy Grid member:
   if (Rows_ > 0)                     // if Original is not an empty
   {
      Grid = new Row[Rows_];          //   allocate new Row array
      assert (Grid != 0);             //   verify success
      for (int r = 0; r < Rows_; r++) //   for each Row:
          Grid[r] = Original.Grid[r]; //     make it a copy of
   }                                  //       that in Original
   else                               // otherwise
      Grid = 0;                       //    set Grid to NULL
}

/*------------------------------------------------------------------
   This function tears down a Table.

   Precondition:  This Table object should no longer exist.
   Postcondition: The run-time storage of this Table has been
                     reclaimed, and its members reset as an
                     empty Table.
------------------------------------------------------------------*/

Table::~Table(void)
{
   delete [] Grid;                 // then destroy the array itself

   Rows_ = 0;                      // set scalars for empty Table
   Columns_ = 0;
   Grid = 0;
}

/*------------------------------------------------------------------
   This function performs the subscript operation on a Table.

   Receive: i, an index into the Table
   Return:  That row in Table whose index is i
-----------------------------------------------------------------*/

Row& Table::operator[] (unsigned i)
{
   if (i < Rows_)       // if subscript is valid
      return Grid[i];   //   return Row i

   cerr << "\n*** Table Subscript: invalid index " 
        << i << " received!\n";
   exit (-1);
}

/*------------------------------------------------------------------
   This function overloads the assignment operator for a Table object.

   Receive: Tab, a (const reference) Table object
   Return:  The Table containing this function, its data members
               containing copies of those of Tab, and a reference
               to the object assigned.
------------------------------------------------------------------*/

Table& Table::operator= (const Table& Tab)
{
   if (this != &Tab)
   {
      delete [] Grid;                    // deallocate old storage
      Rows_ = Tab.Rows_;                 // copy scalar members of Tab
      Columns_ = Tab.Columns_;

      if (Rows_ > 0)                     // if Tab is not empty
      {
         Grid = new Row[Rows_];          //   allocate new Row array
         assert(Grid != 0);              //   verify success
         for (int r = 0; r < Rows_; r++) //   for each row r
            Grid[r] = Tab.Grid[r];       //     copy row r from Tab
      }
      else                               // otherwise
         Grid = 0;                       //   set Grid to NULL
   }

   return *this;                      // to allow chaining
}

/*------------------------------------------------------------------
   This function loads a Table object with data from a file,
     and assumes that the first two values in the file
     give the number of rows and columns of the Table.

   Receive:      FileName, a Strings object containing the name of 
                    an input file
   Input (File): The number of rows and columns and a table 
                    of values
   Return:       False, if the file could not be opened; otherwise,
                    true and the Table object containing this 
                    function, its Grid member containing the 
                    input values
------------------------------------------------------------------*/

Boolean Table::Load(const Strings& FileName)
{
   fstream
      InStream(FileName, ios::in);         // open the stream

   if (InStream.fail())                    // check for failure...
   {
      cerr << "\n*** Load: Unable to open "// ...displaying msg, and
           << FileName << " for input !\n";
      return False;                        // ...indicate failure
   }

   delete [] Grid;                         // deallocate old storage

   InStream >> Rows_ >> Columns_;          // get # rows and columns

   if (Rows_ > 0)                          // if the file isn't empty
   {
      Grid = new Row[Rows_];               //  allocate new Row array
      assert (Grid != 0);                  //  verify success
      for (int r = 0; r < Rows_; r++)      //  for each Row r:
      {
         Grid[r] = Row(Columns_);          //    build Row of correct
                                           //     number of elements
         for (int c = 0; c < Columns_; c++)//    for each column c:
            InStream >> Grid[r][c];        //     read value from file
      }                                    //      into element [r][c]
   }
   else                                    // otherwise
      Grid = 0;                            //    set Grid to NULL

   InStream.close();                       // close the stream

   return True;                            // indicate success
}

/*------------------------------------------------------------------
   This function writes a Table object with data to a file,
     and assumes that the first two values in the file
     give the number of rows and columns of the Table.

   Receive:      FileName, a Strings object containing the name of
                    an output file
   Output(File): The number of rows and columns and a table
                    of values
   Return:       False, if the file could not be opened; otherwise,
                    True and the file containing this Table object
------------------------------------------------------------------*/

Boolean Table::Write(const Strings& FileName) const
{
   fstream
      OutStream(FileName, ios::out);       // open the stream

   if (OutStream.fail())                   // check for failure...
   {
      cerr << "\n*** Write: Unable to open " // ...displaying msg, and
           << FileName << " for output !\n";
      return False;                        // ...indicate failure
   }

   OutStream << Rows_ << ' '
             << Columns_ << endl;          // write # rows and columns

   if (Rows_ > 0)                          // if the file isn't empty
   {
      for (int r = 0; r < Rows_; r++)      //  for each Row r:
      {
         for (int c = 0; c < Columns_; c++)//    for each column c:
            OutStream << Grid[r][c] << ' ';//     write value to file
         OutStream << endl;
      }
   }

   OutStream.close();                       // close the stream

   return True;                            // indicate success
}

/*------------------------------------------------------------------
   This function sums the elements of a given row in a Table object.

   Receive:  Integer row, the row number
   Return:   The sum of the elements in the row-th row of the Table
                object containing this function
-------------------------------------------------------------------*/

TableElement Table::RowSum(unsigned row) const
{
   if (row >= Rows_)                         // check index validity
   {
      cerr << "\n*** RowSum: invalid row index "
           << row << " received !\n";
      return 0;
   }

   TableElement                              // running total
      Sum = 0;

   for (int col = 0; col < Columns_; col++)  // for each column:
      Sum += Grid[row][col];                 //   add Grid[row][col]
                                             //     to total

   return Sum;                               // return total
}

/*------------------------------------------------------------------
   This function sums the elements of a given column in a Table object.

   Receive:  Integer col, the column number
   Return:   The sum of the elements in the col-th column of the Table
                object containing this function
-------------------------------------------------------------------*/

TableElement Table::ColumnSum(unsigned col) const
{
   if (col >= Columns_)                      // check index validity
   {
      cerr << "\n*** ColumnSum: invalid column index "
           << col << " received !\n";
      return 0;
   }

   TableElement                              // running total
      Sum = 0;

   for (int row = 0; row < Rows_; row++)     // for each row:
      Sum += Grid[row][col];                 //   add Grid[row][col]
                                             //     to total

   return Sum;                               // return total
}

/*-------------------------------------------------------------------
   This function overloads the output operator for a Table object.

   Receive: Out, an ostream (reference) object
            Tab, a (const reference) Table object
   Return:  Out, containing the data from Tab
------------------------------------------------------------------*/

#include <iomanip.h>

ostream& operator<< (ostream& Out, const Table& Tab)
{
   Out << setprecision(2)                           // 2 decimal places
       << setiosflags(ios::showpoint | ios::fixed); // non-scientific

   for (int row = 0; row < Tab.Rows_; row++)        // for each row:
   {
      for (int col = 0; col < Tab.Columns_; col++)  //  for each column:
         Out << setw(8) << Tab.Grid[row][col];      //   display
                                                    //    Grid[row][col]
      Out << endl;                                  //  add a newline
   }

   return Out;                                      // allow chaining
}

