/*
 * This file name: query1.c
 * This file contains a program (severly hacked) that computes 
 * the query:
 *    SELECT name, age
 *    from students
 *    where age > 12;
 * 
 * The results are then printed to the screen.
 */

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


// this function is used to create the projection list 
// for the query
proj_attr_list *make_projs(relation_info *rel_info);

// returns the tuple with the constants
tuple *make_cons_tuple();

// make the where clause
bool_expr *make_where(relation_info *rel_info, tuple *cons);

int main(){
  char rel_name[MAX_NAME], f_name[MAX_NAME];
  relation_info *rel_info;
  int status, err_code;
  proj_attr_list *proj_list;
  scan_iterator *s_iter;
  bool done = false;
  tuple *next_tuple = NULL, *cons = NULL;
  bool_expr *expr = NULL;
  memset(rel_name, 0, MAX_NAME);
  memset(f_name, 0, MAX_NAME);
  
  printf("Computing query: SELECT name, age from students where ");
  printf("results > 12;\n");
  sprintf(rel_name,"students");

  sprintf(f_name, "schemas/%s.sf", rel_name);
  printf("Accessing schema information for relation: %s\n", rel_name);

  rel_info =  get_relation_info(f_name, status);
  if (status == OK){
    print_relation_schema(rel_info);
  }
  else if (status == FILE_NOT_FOUND){
    printf("Schema file %s was not found.\n", f_name);
    exit(1);
  }
  else if (status == ILLEGAL_FILE_FORMAT){
    printf("Schema file %s has an illegal format.\n", f_name);
    exit(1);
  }
  else if (status == NO_MEMORY){
    printf("Program ran out of memory.\n");
    exit(1);
  }

  printf("Preparing to run the query.\n");
  printf("Making projection list.\n");
  proj_list = make_projs(rel_info);
  printf("Setting up constants.\n");
  cons = make_cons_tuple();
  printf("Making where clause.\n");
  expr = make_where(rel_info, cons);
  
  printf("Making the scan iterator.\n");
  s_iter = make_scan_iterator(rel_info,proj_list, expr, cons);
  printf("Opening the scan iterator.\n");
  if ((err_code = open_scan_iterator(s_iter)) != OK){
    printf("Cannot open the iterator. Error code: %d\n", err_code);
    exit(1);
  }

  //print_attr_names(rel_info);
  printf("Query Results:\n");
  while(!done){
    next_tuple = next_scan_iterator(s_iter, status);
    if (status == OK){
      print_tuple(next_tuple, stdout);
    }
    else {
      done = true;
    }
  }
  printf("Closing the iterator.\n");
  if (close_scan_iterator(s_iter) != OK){
    printf("Cannot close the iterator.\n");
    exit(1);
  }
  printf("Program execution terminated.\n");
  exit(0);
  
}

void get_proj_attr(const char* attr_name, relation_info *rel_info,
		   proj_attr_list *proj_list, int proj_idx){
  int i=0, len = 0, found = 0;
  
  len = rel_info->num_attrs;
  for (i=0; i < len; ++i){
    if (strcmp(attr_name, rel_info->attributes[i].attr_name) == 0){
      // set where its argument will come from
      proj_list->projections[proj_idx].attr_pos = i;
      // copy the attribute info
      memcpy((void *) &(proj_list->projections[proj_idx].a_info),
	     (void *) &(rel_info->attributes[i]),
	     sizeof(attr_info));
      found = 1;
      break;
    }
  }
  if (!found){
    printf("Could not find metadata about attribute %s in the relation ",
	   attr_name);
    printf("schema information.\n");
    exit(1);
  }
}

proj_attr_list *make_projs(relation_info *rel_info){
  int len = 0;
  proj_attr_list *proj_list = NULL;

  // allocate space for two projections
  len = 2;
  proj_list = (proj_attr_list *) calloc(1, sizeof(proj_attr_list));
  proj_list->num_projs = len;
  proj_list->projections = (proj_attr *) calloc(len, sizeof(proj_attr));
	
  
  // get first projected attribute, which will be: name
  get_proj_attr("name\0", rel_info, proj_list, 0);
  // get second projected attribute, which will be: age
  get_proj_attr("age\0", rel_info, proj_list, 1);
  
  return proj_list;
}

tuple *make_cons_tuple(){
  tuple *result = NULL;
  
  result = (tuple *) calloc(1, sizeof(tuple));
  result->num_attrs = 1;
  result->attr_list = (attribute *) calloc(1, sizeof(attribute));
  result->attr_list[0].attr_type = INT_TYPE;
  result->attr_list[0].attr_val.int_val = 12;
  return result;
}

bool_expr *make_where(relation_info *rel_info, tuple *cons){
  bool_expr *result = NULL;
  int arg1 = 0, arg2 = 0, i = 0, len = 0, found = 0;
  char name[MAX_NAME];

  memset((void *) name, 0, MAX_NAME);
  sprintf(name, "age");
  
  // argument 1 is the attribute age
  len = rel_info->num_attrs;
  for (i=0; i < len; ++i){
    if (strcmp(name, rel_info->attributes[i].attr_name) == 0){
      arg1 = i;
      found = 1;
      break;
    }
  }
  if (!found){
    printf("Could not find metadata about attribute %s.\n", name);
    exit(1);
  }

  // argument 2 is the offset + the first spot in the constant tuple.
  arg2 = rel_info->num_attrs + 0;

  // make gt expression
  result = make_gt_expr(arg1, arg2);
  return result;
}
