/**
 * Compute the addition of numbers in range 1,000,000 to 5,000,000 for 
 * a fixed number of trials. Using this information we create a histogram
 * of sorts and output the reults.
 */
int main (int argc, char **argv) {
  long len;
  int i, x;

  int i1=0;
  long min   =  8000000;
  long max   = 16000000;
  long delta =  2000000; 

  for (len = min; len <= max; len += delta, i1++) {
    for (i = 0; i < T; i++) {
      long sum;

      gettimeofday(&beforeV, 0);    /* begin time */
      clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &before); 

      sum = 0;
      for (x = 0; x < len; x++) { sum += x; }

      gettimeofday(&afterV, 0);    /* begin time */
      clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &after); 

      MStimes[i1][i] = diffTimer (&beforeV, &afterV);
      NStimes[i1][i] = diffNanoTimer (&before, &after);
    }
  }

  printf ("Table A-5\n");
  printf ("n\taverage\t\tmin\tmax\tstdev\t\t#\n");
  buildTable(MStimes);

  printf ("Table A-7\n");
  printf ("n\taverage\t\tmin\tmax\tstdev\t\t#\n");
  buildTable(NStimes);

  return 0;
}
/**
 * Sample program to load the contents of a file (supplied
 * by the user) and sort it. The result is then written to
 * standard output.
 *
 * Each input line is terminated by a '\n' character. No
 * single line of input exceeds a fixed MAX amount.  If it
 * does, the line is split into multiple input lines.
 */
int main (int argc, char **argv) {
  char buf[MAX];
  FILE *in;
  void **ptrs;
  int  size = 1000;
  int  count = 0;
  int  i;
  struct timeval before;   /** Time before start.  */
  struct timeval after;    /** Time after completion. */
  long usecs;
  double actual;

  if (argc < 2) {
    printf ("Usage: %s InFile\n", argv[0]);
    exit (1);
  }

  in = fopen (argv[1], "r");
  if (in == NULL) {
    printf ("Unable to open input file %s\n", argv[1]);
    exit (1);    
  }

  /** Allocate an initial batch. */
  ptrs = malloc (size*sizeof(char *));

  while (fgets(buf, MAX, in) != NULL) {
    ptrs[count++] = strdup (buf);

    /** When capacity fills, double and keep going on... */
    if (count == size) {
      ptrs = realloc (ptrs, (size*2)*sizeof(char *));
      size = size*2;
    }
  }

  fclose(in);

  /* Use sortPointers interface using strcmp. */
  gettimeofday(&before, (struct timezone *) NULL);
  sortPointers(ptrs, count, stringComp);
  gettimeofday(&after, (struct timezone *) NULL); 
  usecs = diffTimer (&before, &after);

  for (i = 0; i < count; i++) {
    fputs(ptrs[i], stdout);
  }

  actual = usecs;
  actual /= 1000000;
  sprintf (buf, "%f seconds\n", actual);
  fputs (buf, stderr);

#ifdef COUNT
  sprintf (buf, "%ld comparisons, %ld swaps\n",
	   COMP_COUNT, SWAP_COUNT);
  fputs (buf, stderr);
#endif /* COUNT */

  return 0;
}
/**
 * load up TSP data file.a as stored within a file. Process graph using 
 * dense Dijkstra's algorithm, if requested.

 <pre>
 NAME : ym7663
 COMMENT : 7663 locations in Yemen
 COMMENT : Derived from National Imagery and Mapping Agency data
 TYPE : TSP
 DIMENSION : 7663
 EDGE_WEIGHT_TYPE : EUC_2D
 NODE_COORD_SECTION
 ...
 EOF
 </pre>
 *
 */
void process (char *fileName, bool dense) {
  FILE *fp = fopen (fileName, "r");
  int i,j,n=0;

  // read header as a whole line, extracting dimension for constructor
  buf[0] = '\0';
  while (strncmp (buf, "NODE_COORD_SECTION", 18)) {
    int nr, i;
    char *ss = fgets (buf, 4096, fp);
    if (ss == NULL) {
      break;
    }

    nr = sscanf (buf, "DIMENSION : %d", &i);
    if (nr == 1) {
      n = i;
    }
    if (verbose) {
      printf ("%s", buf); 
    }
  }
  
  Graph graph (n, false);

  // load values
  float **values = (float **) calloc (n, sizeof (float *));
  for (i = 0; i < n; i++) {
    values[i] = (float *) calloc (2, sizeof (float));
  }

  i = n;
  while (i-- > 0) {
    int j; 
    float longit, latit;
    int nr = fscanf (fp, "%d %f %f\n", &j, &longit, &latit);
    if (nr != 3) {
      printf("invalid line format.\n");
    }

    values[j-1][0] = longit;
    values[j-1][1] = latit;
  }

  fclose(fp);

  if (dense) {
    printf ("Using dense implementation\n");
    int **weight = new int*[n];
    for (int k = 0; k < n; k++) {
      weight[k] = new int[n];
    }

    int *pred = new int [n];
    int *d = new int [n];

    // convert into distances for each pair
    for (i = 0; i < n-1; i++) {
      for (j = i+1; j < n; j++) {
	if (i != j) {
	  int d = dist (i, j, values);
	  weight[i][j] = d;
	  weight[j][i] = d;
	}
      }
    }

    gettimeofday(&before, (struct timezone *) NULL);    // begin time
    singleSourceShortestDense(n, weight, 0, d, pred);
    gettimeofday(&after, (struct timezone *) NULL);     // end time

    if (verbose) {
      for (int i = 0; i < n; i++) {
	printf ("%d. %d\n", i, d[i]);
      }
    }
  } else {
    // convert into distances for each pair
    for (i = 0; i < n-1; i++) {
      for (j = i+1; j < n; j++) {
	if (i != j) {
	  int d = dist (i, j, values);
	  graph.addEdge (i, j, d);
	}
      }
    }
    
    vector<int> dist(n);
    vector<int> pred(n);
    
    gettimeofday(&before, (struct timezone *) NULL);    // begin time
    singleSourceShortest(graph, 0, dist, pred);
    gettimeofday(&after, (struct timezone *) NULL);     // end time

    if (verbose) {
      for (int i = 0; i < n; i++) {
	printf ("%d. %d\n", i, dist[i]);
      }
    }
  }

  long usecs = diffTimer (&before, &after);           // show results

  printDiffTimer(usecs);
}
/** Generate full table. */
void generateTable() {
  int i;
  long base, addT, altT, lastT;
  long checkSum = 0;

  /* larger trials (n=262144 to 2097152) if desired. */

  /* Trials */
  int MAX_SIZE = 1048576;
  int NUM_TRIALS = 10000;
  n = 256;
		
  while (n <= MAX_SIZE) {
    int *n1, *n2, *sum, *copy1, *copy2;
    printf ("Trying %d...\n", n);

    /* generate numbers and space for storage */
    n1 = calloc (n, sizeof (int));
    n2 = calloc (n, sizeof (int));
    randomNumber(n1);
    randomNumber(n2);
    sum = calloc (n+1, sizeof (int));

    copy1= calloc (n, sizeof (int));
    copy2= calloc (n, sizeof (int));

    bcopy (n1, copy1, n);
    bcopy (n2, copy2, n);

    /** Timing as follows:
     *
     * gettimeofday(&before, (struct timezone *) NULL);    BEGIN
     *    OP HERE
     * gettimeofday(&after, (struct timezone *) NULL);     END
     *
     * long usecs = diffTimer (&before, &after);           SHOW RESULTS
     * report (usecs);
     */

    /*  BASELINE*/
    gettimeofday(&before, (struct timezone *) NULL);   

    for (i = 0; i < NUM_TRIALS; i++) {
      int c;

      /* NOP */
      checkSum += n1[0];
				
      /* circular shift (n1 left, n2 right). */
      c = n1[0];
      bcopy (n1+1, n1, n-1);
      n1[n-1] = c;

      c = n2[n-1];
      bcopy (n2, n2+1, n-1);
      n2[0] = c;
    }

    gettimeofday(&after, (struct timezone *) NULL);   
    base = diffTimer (&before, &after);
			
    /* ADD */
    bcopy (copy1, n1, n);
    bcopy (copy2, n2, n);

    gettimeofday(&before, (struct timezone *) NULL);   
    for (i = 0; i < NUM_TRIALS; i++) {
      int c;
      add(n1,n2,sum);
      checkSum += sum[0];

      /* circular shift (n1 left, n2 right). */
      c = n1[0];
      bcopy (n1+1, n1, n-1);
      n1[n-1] = c;

      c = n2[n-1];
      bcopy (n2, n2+1, n-1);
      n2[0] = c;
    }

    gettimeofday(&after, (struct timezone *) NULL); 
    addT = diffTimer (&before, &after);
			
    /* ALT */
    bcopy (copy1, n1, n);
    bcopy (copy2, n2, n);
    for (i = 0; i < NUM_TRIALS; i++) {
      int c;
      alt(n1,n2,sum);
      checkSum += sum[0];
				
      /* circular shift (n1 left, n2 right). */
      c = n1[0];
      bcopy (n1+1, n1, n-1);
      n1[n-1] = c;

      c = n2[n-1];
      bcopy (n2, n2+1, n-1);
      n2[0] = c;
    }
    gettimeofday(&after, (struct timezone *) NULL);   
    altT = diffTimer (&before, &after);
    
			
    /* LAST */
    bcopy (copy1, n1, n);
    bcopy (copy2, n2, n);
    gettimeofday(&before, (struct timezone *) NULL);   
    for (i = 0; i < NUM_TRIALS; i++) {
      int c;
      last(n1,n2,sum);
      checkSum += sum[0];
				
      /* circular shift (n1 left, n2 right). */
      c = n1[0];
      bcopy (n1+1, n1, n-1);
      n1[n-1] = c;

      c = n2[n-1];
      bcopy (n2, n2+1, n-1);
      n2[0] = c;
    }
    gettimeofday(&after, (struct timezone *) NULL);   
    lastT = diffTimer (&before, &after);
    report (lastT);

			
    printf("%d,Base:%ld,ms.\n", n, base/1000);
    printf("%d,Add*:%ld,ms.\n", n, (addT-base)/1000);
    printf("%d,Alt*:%ld,ms.\n", n, (altT-base)/1000);
    printf("%d,Last*:%ld,ms.\n", n, (lastT-base)/1000);

    /* advance */
    n = n * 2;
    free(n1);
    free(n2);
    free(copy1);
    free(copy2);
    free(sum);
  }
  printf ("Checksum:%ld\n", checkSum);
}