/*
   This file contains the subroutines for Nucleotide databases
*/

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <vlcutils/error.h>
#include "dsutil.h"
#include "definitions.h"
#include "freqdist.h"
#include "index.h"


/* Creates a match matrix and prints it to a file
 *
 * indexFName : name of index file
 * queryFName : name of query file
 * outputFName: name of the file for output matrix */
void createMatrix(const char indexFName[], const char queryFName[], 
		  const char outputFName[], double errorRate, int pageSize)
{
     FILE *qfp, *ofp;
     char c, *qs;
     int i, j, k, m, wPerPage, boxPerPage, xval, yval, 
	  qlen, err, delta, qnum, oldyval, 
	  indexpos, start1, dif, isMarked,  
	  numMarked, numUnmarked, q[ALPH_LEN], *mark;
     struct index *index;

     /*
      * Open files.
      */

     qfp = fopen(queryFName, "r");
     if (!qfp)
	  fatal_perror("%s: fopen", queryFName);
     ofp = fopen(outputFName, "w");
     if (!ofp)
	  fatal_perror("%s: fopen", outputFName);

     /* 
      * Read index from file.
      */

     printf("Reading index\n");
     index = read_index(indexFName);
     assert(index);

     /*
      * Read the complete query into memory.
      */

     qlen = statistics(queryFName);
     qs = (char*)malloc(sizeof(char) * qlen);
     j = 0;
     while (fscanf(qfp, "%c", &qs[j]) > 0) 
	  j++;
     qlen = j;
     fclose(qfp);
     /* printf("   Query Size = %d \n", qlen); */

     /* 
      * Create match table
      */

     printf("Creating Match Table.\n");

     fprintf(ofp, "%d %d\n", index->box_capacity, index->window_size);
     err = floor(index->window_size * errorRate);
     /* delta = floor(index->window_size / 2); */
     delta = index->window_size;
     qnum = floor((qlen - index->window_size + delta - 1) / delta);
     wPerPage = floor(pageSize / index->window_size);
     if (wPerPage == 0)
	  wPerPage = 1;
     /*  boxPerPage = floor(pageSize/boxCapacity); */
     boxPerPage = ceil((double)(pageSize - index->window_size + 1) 
		       / index->box_capacity);
     if (boxPerPage == 0)
	  boxPerPage = 1;

     /*
      * Run query 
      */

     mark = (int*)malloc(sizeof(int) * index->num_boxes);
     start1 = k = xval = numMarked = numUnmarked = 0; 
     while (k < qnum) {
	  /* Initialize mark array. */
	  for (j = 0; j < index->num_boxes; j++)
	       mark[j] = 0;

	  /* Consume a page size portion of the query. */
	  for (i = 0; i < wPerPage; i++){
	       /* map k'th subquery into integer space */
	       for(j = 0; j < ALPH_LEN; j++)
		    q[j]=0;
	       j = start1;
	       for (m = 0; m < index->window_size; m++) {
		    c = qs[j];
		    j++;
		    increment(c, q);
	       }
    
	       /* Scan the MBRs checking the distance for each. */
	       for (indexpos = 0; indexpos < index->num_boxes; indexpos++) {
		    dif = infdist(q, index->elements[indexpos]);  
		    if (dif < err) 
			 mark[indexpos] = 1;
	       }
	       /* Rearrange the boundaries for the next subquery. */
	       start1 = start1 + delta;
	       if (k == qnum - 1) {
		    if (start1 > qlen)
			 start1 = qlen - index->window_size;
	       }
	       k++;
	       if (k == qnum)
		    break;
	  }

	  /*
	   * Print marked entries to file here
	   */
	  oldyval = -1;
	  indexpos = yval = 0;
	  while (indexpos < index->num_boxes) { 
	       isMarked = 0;
	       yval = ceil((double)indexpos * index->box_capacity / pageSize);
	       for (i = 0; i < boxPerPage; i++){
		    if (mark[indexpos] == 1){
			 isMarked = 1;
			 indexpos += (boxPerPage - i);
			 break;
		    }
		    indexpos++;
		    if (indexpos == index->num_boxes) 
			 break;
	       }
	       if ((isMarked) && (yval != oldyval)){
		    fprintf(ofp, "%d %d\n", xval, yval);
		    oldyval = yval;
		    numMarked++;
	       }
	       else
		    numUnmarked++;
	       /*      yval++; */
	  }
	  xval++;
     }
     fclose(ofp);

     printf("Number of marked = %d\n", numMarked);
     printf("Number of unmarked = %d\n", numUnmarked);
     printf("Rate of marked = %f\n",
	    (double)(numMarked / (double)(numMarked + numUnmarked)));

} /* createMatrix */

