#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <cstring>
#include "error.h"
#include "schema.h"
#include "tuple.h"
#include "predicate.h"
#include "iterator.h"


/*
 * This function is used to initialized to all 0 the contents 
 * of the buffer used to read bytes from the data file.
 */
void clear_buffer(scan_iterator *s_iter){
  memset(s_iter->buf, 0, MAX_BUF);
}

/*
 * This function creates a new scan iterator from a relation 
 * schema information object, a projection list, a selection
 * expression, and a tuple containing a group of constant 
 * expressions.
 * Input: rel_info - pointer to relation information structure
 * Input: proj_list - pointer to projection list
 * Input: expr - pointer to the selection condition
 * Input: const_exprs - tuple with constant values
 * Output: scan_iterator - pointer to a scan iterator structure
 */
scan_iterator *make_scan_iterator(relation_info *rel_info, 
				  proj_attr_list  *proj_list,
				  bool_expr *expr, 
				  tuple *const_exprs){
  scan_iterator *result = NULL;
  
  assert(rel_info != NULL);
  assert(proj_list != NULL);
  
  result = (scan_iterator *) calloc(1, sizeof(scan_iterator));
  result->rel_info = rel_info;
  result->proj_list = proj_list;
  result->expr = expr;
  result->next_tuple = make_tuple(rel_info);
  result->empty = false;
  result->const_tuple = const_exprs;
  return result;
}



/*
 * This function is used to read a tuple from the data file.
 * The tuple is stored within the scan_iterator structure, in
 * the field next_tuple.
 * Input: s_iter - pointer to the scan iterator.
 * Output: a status of OK if the tuple was read, or an error 
 * value otherwise.
 */
int read_next_tuple(scan_iterator *s_iter){
  int num_read = 0, num_to_read = 0;
  clear_buffer(s_iter);
  
  if (feof(s_iter->data_file)){
    return NO_MORE_TUPLES;
  }
  else {
    num_to_read = tuple_size(s_iter->rel_info);
    num_read = fread((void *) s_iter->buf, sizeof(char), num_to_read, 
		     s_iter->data_file);
    if (num_read != num_to_read){
      if (feof(s_iter->data_file)){
	return NO_MORE_TUPLES;
      }
      else {
	return NOT_ENOUGH_DATA;
      }
    }
    else {
      return fill_in_tuple(s_iter->buf, num_read, s_iter->rel_info, 
			   s_iter->next_tuple);
    }
  }
}

/*
 * This function takes care of opening the data file from which
 * tuples will be read.
 * Input: s_iter - pointer to the scan iterator structure.
 * Output: status code of OK indicating if the operation was successful,
 * or FILE_NOT_FOUND if the data file could not be opened.
 */
int open_scan_iterator(scan_iterator *s_iter){
  
  // ADD YOUR CODE TO OPEN THE DATA FILE
  
  return OK;
}

/*
 * This function is used to evaluate  a seleciton condition.
 * If the expr is equal to NULL, then the function must return
 * true immediately.
 * Input: expr - pointer to the selection condition 
 * Input: src - pointer to the tuple read from the database.
 * Input: cons - pointer to the tuple with constants.
 * Output: true if the src tuple passes the selection condition, or 
 * false otherwise.
 */
bool eval_selection(bool_expr *expr, tuple *src, tuple *cons){
  // ADD YOUR CODE HERE
  
  return true;
}

/*
 * This function projects one or more attributes from a source tuples,
 * and stores them in a destination tuple. 
 * Input: proj_list - pointer to an array with the list of projection to do.
 * Input: dest - pointer to the destination tuple.
 * Input: src - pointer to the source tuple.
 * Output: OK if the tuple was projection, or an error value otherwise.
 */
int project_tuple(proj_attr_list *proj_list, tuple *dest, tuple* src){
  
  // ADD YOUR CODE HERE

  return OK;
} 

/*
 * This function is used to obtain the next tuple that results
 * from evaluating a selection condition, and a series of projections
 * of a tuple read from the data file (database).
 * Input: s_iter - pointer to the scan iterator object.
 * Input: status - flag to be set with the diagnostic value that 
 * indicates what was the result of the call to next. Possible values are:
 *     OK : a tuple was returned
 *     ITERATOR_EMPTY : no more tuples are available
 *     NOT_ENOUGH_DATA: no enough data is avaliable to read a full tuple.
 *
 * Output: the next tuple that passes the selection and projections, or 
 * NULL if either there are no more tuples, or an error condition 
 * occurred. The value of status must be set accordingly.
 */
tuple *next_scan_iterator(scan_iterator *s_iter, int& status){
  tuple *result = NULL;

  // ADD YOUR CODE HERE
  
  /*
   * This function should work as follows:
   * 1) First determine if the iterator is not empty.
   * 2) Try to read a tuple from the data file (if any).
   * 3) If no tuple are available, return with NULL.
   * 4) If a tuple is read, evaluate the selection, if it does not
   * passes, then go to 2).
   * 5) If the tuple passes, then project it.
   * 6) Return the tuple that consists of the projected columns.
   */

  return result;
}

/*
 * This function is used to close the file from which tuples where being
 * read. The function should also set the empty iterator flag in the 
 * scan iterator structure to the value true.
 * Input: s_iter - pointer to the scan iterator structure
 * Output: status code of OK if the file gets closed, or UNKNOWN_FILE_ERROR
 * if the file cannot be closed.  
 */
int close_scan_iterator(scan_iterator *s_iter){
  
  // ADD YOUR CODE TO CLOSE THE DATA FILE
  return OK;
}







