/* This file contains the implementation for class Table.

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

#include "Table.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)
{
   if (NumRows > Table::MaxRows)               // if NumRows too big
   {
      cerr << "\nConstructor warning - rows received: "
           << NumRows << " exceed Table maximum!\n";
      Rows_ = Table::MaxRows;                  //   use maximum
   }
   else                                        // else
      Rows_ = NumRows;                         //   use value passed

   if (NumCols > Table::MaxCols)               // if NumCols too big
   {
      cerr << "\nConstructor warning - columns received: "
           << NumCols << " exceed Table maximum !\n";
      Columns_ = Table::MaxCols;               //   use maximum
   }
   else                                        // else
      Columns_ = NumCols;                      //    use value passed

   for (int row = 0; row < Rows_; row++)       // for each row:
      for (int col = 0; col < Columns_; col++) //   for each column:
         Grid[row][col] = InitValue;           //     initialize array
                                               //     element
}

/*-------------------------------------------------------------------
   This function fills a Table object with data from a file,
     assuming that the Table has been constructed with the
     number of rows and columns for the Table in the file.

   Receive: FileName, a Strings object containing the name of an
               input file
   Input:   A table of values from the input file
   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::Fill(const Strings& FileName)
{
   fstream
      InStream(FileName, ios::in);             // open the stream

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

   for (int row = 0; row < Rows_; row++)       // for each row:
      for (int col = 0; col < Columns_; col++) //  for each column:
         InStream >> Grid[row][col];           //   fill
                                               //     Grid[row][col]
   InStream.close();                           // close the stream

   return True;                                // indicate success
}

/*-------------------------------------------------------------------
   This function fills 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 in 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 "  //    display message
           << FileName << " for input!\n";   //    and
      return False;                          //    indicate failure
   }

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

   if (Rows_ > Table::MaxRows)               // check their validity
   {
      cerr << "\nLoad: " << Rows_ <<
            " exceeds maximum number of rows for a Table!\n";
      exit (-1);
   }
   else if (Columns_ > Table::MaxCols)
   {
      cerr << "\nLoad: " << Columns_ <<
            " exceeds maximum number of columns for a Table!\n";
      exit (-1);
   }

   for (int row = 0; row < Rows_; row++)       // for each row:
      for (int col = 0; col < Columns_; col++) //  for each column:
         InStream >> Grid[row][col];           //   fill [row,col]

   InStream.close();                           // close the stream

   return True;                                // indicate success
}

/*-------------------------------------------------------------------
   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
}

/*-------------------------------------------------------------------
   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
-------------------------------------------------------------------*/

Table& Table::operator= (const Table& Tab)
{
   if (Rows_ != Tab.Rows_)                     // check row equality
      cerr << "\nAssignment warning: number of rows not equal!\n";

   Rows_ = Tab.Rows_;                          // update row size

   if (Columns_ != Tab.Columns_)               // check col. equality
      cerr << "\nAssignment warning: number of columns not equal!\n";

   Columns_ = Tab.Columns_;                    // update column size

   for (int row = 0; row < Rows_; row++)       // for each row:
      for (int col = 0; col < Columns_; col++) //  for each column:
         Grid[row][col] = Tab.Grid[row][col];  //   copy
                                               //    Grid[row][col]

   return *this;                               // return copy
}

/*-------------------------------------------------------------------
   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 accesses the element at a given row & column in
   a Table.

   Receive: row, a row index
            col, a column index
   Return:  The element at Grid[row][col]
------------------------------------------------------------------*/

TableElement Table::GetElem(unsigned row, unsigned col) const
{
   if ((row < Rows_) && (col < Columns_))
      return Grid[row][col];
   cerr << "\n*** GetElem - invalid index received - row: " << row
        << " column: " << col << endl;
   exit (-1);
}

