header
//---------------------------------------------------------
// TwoDArrays1.cpp
//
// A simple program demonstrating processing of two-
// dimensional arrays.
//
// D. Searls
// Asbury College
// Oct 2002
//---------------------------------------------------------

#include<iostream>
#include<iomanip>
#include<string>
#include<fstream>
using namespace std;

const int MAXROWS = 100; // Maximum number of rows
const int MAXCOLS = 10;  // Maximum number of columns

struct StatsType
{
    double min;   // The minimum
    double max;   // The maximum
    double avg;   // The average
};

//---------------------------------------------------------
// readFileData
//
// Purpose: read the file data into the table.
//
// Preconditions: the file contains no errors and the first
//    two values represent the number of rows and the
//    number of columns. The table data follows these
//    two values.
//
// Out Parameters: table, numRows, numCols
//---------------------------------------------------------
void readFileData(double table[][MAXCOLS],
                  int& numRows, int& numCols)
{
    ifstream infile;
    string filename;      // Name of input file
    
    cout << "Enter name of input file "
         << "(try 'sample1.dat' or 'sample2.dat'): ";
    cin >> filename;
    cout << endl;
    infile.open(filename.c_str());
    if (infile.fail())
    {
        cout << "Could not open input file " << filename << "!\n\n";
        cout << "Program abnormally terminated!\n";
        exit(0);
    }
    infile >> numRows;
    infile >> numCols;
    if (numRows > MAXROWS || numCols > MAXCOLS)
    {
        cout << "FATAL ERROR: ";
        cout << "The table in the data file has more rows or \n";
        cout << "more columns than ";
        cout << "this program was designed to handle.\n\n";
        exit(0);
    }
    for(int row = 0; row < numRows; row++)
    {
        for(int col = 0; col < numCols; col++)
        {
            infile >> table[row][col];
        }
    }
    infile.close();
}

//---------------------------------------------------------
// findRowStats
//
// Purpose: find the min, max, and avg for each row.
//
// In Parameters: table, numRows, numCols
//
// Out Parameter: rowStats
//---------------------------------------------------------
void findRowStats(const double table[][MAXCOLS], int numRows,
                  int numCols, StatsType rowStats[])
{
    double min;  // Minimum value in row
    double max;  // Maximum value in row
    double sum;  // Sum of row values
    double x;    // A row value

    for(int row = 0; row < numRows; row++)
    {
        min = table[row][0];
        max = table[row][0];
        sum = 0.0;
        for(int col = 0; col < numCols; col++)
        {
            x = table[row][col];
            if(x < min)
            {
                min = x;
            }
            if (x > max)
            {
                max = x;
            }
            sum = sum + x;
        }
        rowStats[row].min = min;
        rowStats[row].max = max;
        rowStats[row].avg = sum/(double)numCols;
    }
}

//---------------------------------------------------------
// findColStats
//
// Purpose: find the min, max, and avg for each col.
//
// In Parameters: table, numRows, numCols
//
// Out Parameter: colStats
//---------------------------------------------------------
void findColStats(const double table[][MAXCOLS], int numRows,
                  int numCols, StatsType colStats[])
{
    double min;  // Minimum value in column
    double max;  // Maximum value in column
    double sum;  // Sum of column values
    double x;    // A column value

    for(int col = 0; col < numCols; col++)
    {
        min = table[0][col];
        max = table[0][col];
        sum = 0.0;
        for(int row = 0; row < numRows; row++)
        {
            x = table[row][col];
            if(x < min)
            {
                min = x;
            }
            if (x > max)
            {
                max = x;
            }
            sum = sum + x;
        }
        colStats[col].min = min;
        colStats[col].max = max;
        colStats[col].avg = sum/(double)numRows;
    }
}

//---------------------------------------------------------
// display
//
// Purpose: Display the table data, the row statistics, and
//    the column statistics.
//
// In Parameters: table, numRows, numCols, rowStats, colStats
//---------------------------------------------------------
void display(const double table[][MAXCOLS],
             int numRows, int numCols,
             const StatsType rowStats[],
             const StatsType colStats[])
{
    int row;    // Row counter
    int col;    // Col counter

    
    cout << fixed << setprecision(1);
    
    // Display table headings

    cout << setw((7*numCols)/2 + 11) << "Column\n\n";
    cout << " Row";
    for(col = 0; col < numCols; col ++)
    {
        cout << setw(7) << col;
    }
    cout << "    Min    Max    Avg\n";
    cout << endl;
    cout << "----";
    for(col = 0; col < numCols; col ++)
    {
        cout << "-------";
    }
    cout << "---------------------\n";

    // Display body of table

    for(row = 0; row < numRows; row++)
    {
        cout << setw(4) << row;
        for(col = 0; col < numCols; col++)
        {
            cout << setw(7) << table[row][col];
        }
        cout << setw(7) << rowStats[row].min;
        cout << setw(7) << rowStats[row].max;
        cout << setprecision(2)
             << setw(7) << rowStats[row].avg
             << setprecision(1);
        cout << endl;
    }

    // Display footer and column stats

    cout << "----";
    for(col = 0; col < numCols; col ++)
    {
        cout << "-------";
    }
    cout << "---------------------\n";

    cout << " Min";
    for(col = 0; col < numCols; col ++)
    {
        cout << setw(7) << colStats[col].min;
    }
    cout << endl;

    cout << " Max";
    for(col = 0; col < numCols; col ++)
    {
        cout << setw(7) << colStats[col].max;
    }
    cout << endl;

    cout << " Avg";
    for(col = 0; col < numCols; col ++)
    {
        cout << setw(7) << colStats[col].avg;
    }
    cout << endl;
}

//*********************************************************
//       M  A  I  N     D  R  I  V  E  R
//*********************************************************

int main()
{
    double table[MAXROWS][MAXCOLS];  // The table data
    int numRows;                 // Number of rows
    int numCols;                 // Number of columns
    StatsType rowStats[MAXROWS]; // Row statistics
    StatsType colStats[MAXCOLS]; // Col statistics

    readFileData(table, numRows, numCols);
    findRowStats(table, numRows, numCols, rowStats);
    findColStats(table, numRows, numCols, colStats);
    display(table, numRows, numCols, rowStats, colStats);
    
    return 0;
}