
/*
 * Josh Holtrop
 * 2008-10-01
 * Grand Valley State University
 * CS677
 * Programming Assignment #2
 */

#include <iostream>
#include <fstream>
#include <vector>
#include <sys/time.h>   /* gettimeofday(), struct timeval */
using namespace std;

#define eq(x, y) ( ( (x) == (y) ) || ( (x) == '?' ) || ( (y) == '?' ) )

void usage(char * prog);
void similarityMatrix(vector<char> & s, vector<char> & t);
bool readFile(char * fileName, vector<char> & v);

/* Print basic usage information */
void usage(char * prog)
{
    cout << "Usage: " << prog << " <file1> <file2>" << endl;
    exit(42);
}

int main(int argc, char * argv[])
{
    vector<char> file1, file2;

    if (argc < 3)
        usage(argv[0]);

    readFile(argv[1], file1);
    readFile(argv[2], file2);

    struct timeval before, after;
    gettimeofday(&before, NULL);        /* Start timing */
    similarityMatrix(file1, file2);
    gettimeofday(&after, NULL);         /* Stop timing */
    double time_before = before.tv_sec + before.tv_usec / 1000000.0;
    double time_after = after.tv_sec + after.tv_usec / 1000000.0;
    double diff = time_after - time_before;
    cout << "Elapsed time: " << diff << " seconds." << endl;
}

/* Read a file into a vector of non-space characters */
bool readFile(char * fileName, vector<char> & v)
{
    ifstream in(fileName);
    if (!in.is_open())
        return false;
    for(;;)
    {
        char chr;
        in >> chr;
        if (in.eof())
            break;
        v.push_back(chr);
//        cout << "0x" << hex << (int) chr << " (" << chr << ") ";
    }
//    cout << endl;
    return true;
}

/* Compute the similarity matrix between two character arrays */
void similarityMatrix(vector<char> & s, vector<char> & t)
{
    int s_size = s.size();
    int t_size = t.size();
    int (*F)[s_size+1][t_size+1] =
        (int (*)[s_size+1][t_size+1]) new int[(s_size+1) * (t_size+1)];
    int max_x = 0, max_y = 0, max_val = 0;
    for (int i = 0; i <= t_size; i++)    /* set first row to 0's */
        (*F)[0][i] = 0;
    for (int i = 0; i <= s_size; i++)    /* set first column to 0's */
        (*F)[i][0] = 0;
    for (int i = 1; i <= s_size; i++)
    {
        for (int j = 1; j <= t_size; j++)
        {
            /* Compute the value for the matrix */
            (*F)[i][j] =
                max(
                    max(
                        (*F)[i][j-1] - 2,
                        (*F)[i-1][j-1] + (eq(s[i-1],  t[j-1]) ? 1 : -1)
                    ),
                    max(
                        (*F)[i-1][j] - 2,
                        0
                    )
                );
            /* See if we found a new maximum value */
            if ((*F)[i][j] > max_val)
            {
                max_val = (*F)[i][j];
                max_x = i;
                max_y = j;
            }
            else if ((*F)[i][j] == max_val)
            {
                /* If we found a value the same as our current maximum
                 * value, see if it has a greater i+j value */
                if ( (i + j) > (max_x + max_y) )
                {
                    max_x = i;
                    max_y = j;
                }
            }
        }
    }
#if 0
    cout << "Matrix: " << s_size+1 << " x " << t_size+1 << endl;
    for (int i = 0; i <= s_size; i++)
    {
        for (int j = 0; j <= t_size; j++)
        {
            printf("%2d ", F[i][j]);
        }
        printf("\n");
    }
#endif
    cout << "Maximum value is " << max_val << " at position ("
        << max_x << ", " << max_y << ")" << endl;
    delete[] F;
}
