/*
 * This is a very badly broken C++ program.  Its purpose in life is to
 * illustrate some basic debugging concepts.  Comments have been kept
 * to a minimum because the code will be explained in class, and so
 * that the maximum amount of information will fit on the display.
 */

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

int		main(int argc, char* argv[]);
					// Matrix multiplier
static void	usage(char* progname);	// Issue a usage message
static double**	makeMatrix(int rows, int columns, bool initWell);
					// Create a test matrix
static void	zapMatrix(double** matrix, int rows, int columns);
					// Free a matrix
static  void	matrixMultiply(double** dest, double** m1, double** m2,
		  int r1, int c1, int r2, int c2);
					// Do matrix multiplication
static void	printMatrix(ostream& stream, double** matrix,
		   int rows, int columns);
					// Print a matrix to a stream

int main(
    int		argc,			// Number of arguments
    char*	argv[])			// Vector of argument strings
    {
    if (argc != 4)			// BUG 2: Wrong constant
	usage(argv[0]);
    int r1 = atoi(argv[1]);
    int c1 = atoi(argv[2]);
    int r2 = atoi(argv[3]);
    int c2 = atoi(argv[4]);
    double** m1 = makeMatrix(r1, c1, true);
    cout << "Matrix 1:\n";
    printMatrix(cout, m1, r1, c1);
    double** m2 = makeMatrix(r2, c2, true);
    cout << "\nMatrix 2:\n";
    printMatrix(cout, m2, r2, c2);
    zapMatrix(m1, r1, c1);		// BUG 7: freed too early
    zapMatrix(m2, r1, c1);		// BUG 6: should be r2/c2
    double** m3 = makeMatrix(r1, c2, false);
    matrixMultiply(m3, m1, m2, r1, c1, r2, c2);
    cout << "\nResult:\n";
    printMatrix(cout, m3, r1, c2);
    zapMatrix(m3, r1, c2);
    return 0;
    }

static void usage(			// Issue a usage message
    char*	progname)		// Name we were run under
    {
    cerr << "Usage: " << progname << " r1 c1 r2 c2";
					// BUG 1: no newline
    exit(2);
    }

static double**	makeMatrix(		// Create a test matrix
    int		rows,			// Number of rows in matrix
    int		columns,		// Number of columns in matrix
    bool	initWell)		// True to initialize usefully
    {
    double** matrix = new double*[rows];
    for (int i = 0;  i < rows;  i++)
	{
	matrix[i] = new double[columns];
	for (int j = 0;  j < columns;  j++)
	    {
	    if (initWell)
		matrix[i][j] = i * rows + j;
					// BUG 3: should be columns
	    else
		matrix[i][j] = time((time_t*) NULL) + i + j;
	    }
	}
    return matrix;
    }

static void zapMatrix(			// Free a matrix
    double**	matrix,			// Matrix to delete
    int		rows,			// Number of rows in matrix
    int		)			// Number of columns in matrix
    {
    for (int i = 0;  i < rows;  i++)
	delete[] matrix[i];
    delete[] matrix;
    }

static void matrixMultiply(		// Multiply matrices
    double**	dest,			// Space for result
    double**	m1,			// Left operand
    double**	m2,			// Right operand
    int		r1,			// Rows in left operand
    int		c1,			// Columns in left operand
    int		r2,			// Rows in right operand
    int		c2)			// Columns in right operand
    {
    if (c1 != r2)
	{
	cerr << "Can't multiply nonconformal matrices\n";
	exit(1);
	}
    for (int i = 0;  i < r1;  i++)
	{
	for (int j = 0;  j < c2;  j++)
	    {
	    double sum;			// BUG 4: uninitialized variable
	    for (int k = 0;  k < c1;  k++)
		sum += m1[i][k] * m2[k][j];
	    // BUG 5: forgot to put sum in dest[i][j]
	    }
	}
    }

static void printMatrix(		// Print a matrix to a stream
    ostream&	stream,			// Stream to print to
    double**	matrix,			// Matrix to print
    int		rows,			// Number of rows in matrix
    int		columns)		// Number of columns in matrix
    {
    for (int i = 0;  i < rows;  i++)
	{
	for (int j = 0;  j < columns;  j++)
	    {
	    if (j != 0)
		stream << ' ';
	    stream << matrix[i][j];
	    }
	stream << endl;
	}
    }
