#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>

#include "grid.h"
#include "cycletimer.h"

#ifndef OMP
#define OMP 0
#endif

#if OMP
#include <omp.h>
#endif

void usage(char *name) {
#if OMP
    printf("Usage: %s [-h] [-v] [-n GRID] [-b BMODE] [-e EPS] [-s STEPS] [-t THDS]\n", name);
#else
    printf("Usage: %s [-h] [-v] [-n GRID] [-b BMODE] [-e EPS] [-s STEPS]\n", name);
#endif
    printf("Usage: %s [-h] [-v] [-n GRID] [-b BMODE] [-e EPS] [-s STEPS]\n", name);    printf("  -h       Print this message\n");
    printf("  -v       Verbose mode\n");
    printf("  -n GRID  Set grid size\n");
    printf("  -b BMODE Boundary conditions (h:horizontal, c:corner, d:diagonal, r:random)\n");
    printf("  -e EPS   Set convergence limit\n");
    printf("  -s STEPS Set step limit\n");
#if OMP
    printf("  -t THDS  Use THDS threads\n");
#endif
    exit(0);
}

int main(int argc, char *argv[]) {
    int nrow = 40;
    int maxSteps = 1000;
    double epsilon = 0.0001;
    char mode = 'h';
    bool verbose = false;
    int c;
    int threads = 1;
#if OMP
    char *optstring = "hvn:b:e:s:t:";
#else
    char *optstring = "hvn:b:e:s:";
#endif
    while ((c = getopt(argc, argv, optstring)) != -1) {
	switch (c) {
	case 'h':
	    usage(argv[0]);
	    break;
	case 'v':
	    verbose = true;
	    break;
	case 'n':
	    nrow = atoi(optarg);
	    break;
	case 'b':
	    mode = optarg[0];
	    break;
	case 'e':
	    epsilon = atof(optarg);
	    break;
	case 's':
	    maxSteps = atoi(optarg);
	    break;
	case 't':
	    threads = atoi(optarg);
	    break;
	default:
	    printf("Unknown command line option '%d'\n", c);
	    usage(argv[0]);
	    break;
	}
    }

#if OMP
    omp_set_num_threads(threads);
#endif

    double start_time = currentSeconds();

    int steps = solve(nrow, nrow, mode, epsilon, maxSteps, verbose);

    double seconds = currentSeconds() - start_time;
    long comps = (long) nrow * nrow * steps;
    double npc = seconds * 1e9 / comps;
    printf("%d rows.  %d threads.  %.2f seconds.  %ld grid point computations.  nanoseconds/comp. = %.2f\n",
	   nrow, threads, seconds, comps, npc);
    return 0;
}
