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

/*
 * Allocates a new buffer for a string of a given size len.
 * Input: size of the string
 * Ouput: pointer to a char string 
 */
char *make_str(int len){
  char *result = NULL;
  
  assert(len >= 1);
  result = (char *) calloc(len, 1);
  return result;
}

/*
 * Creates an empty tuple structured that can be filled
 * with all pertinent information.
 */
tuple *make_empty_tuple(){
  return (tuple *) calloc(1, sizeof(tuple));
}

/*
 * Creates an empty attribute list of len attributes.
 */
attribute *make_empty_attrs(int len){
  return (attribute *) calloc(len, sizeof(attribute));
}



/*
 * Returns the size in bytes of an attribute based on the schema
 * information about a relation.
 * Input: rel_info - pointer to a relation schema information structure
 * Ouput: number of bytes in a tuple that follows the given schema.
 */
int tuple_size(relation_info *rel_info){
  int i=0, len = 0;
  int size = 0;
  
  len = rel_info->num_attrs;
  for (i=0; i < len; ++i){
    size += rel_info->attributes[i].type_size;
  }
  return size;
}


void read_int(char *src, attribute& attr){
  
  // take an integer out of the src pointer
  attr.attr_val.int_val = *((int *) src);
}

void read_double(char *src, attribute& attr){
  
  // take an double out of the src pointer
  attr.attr_val.double_val = *((double *) src);
}

void read_char(char *src, int len, attribute& attr){
  // read a string of chars out of the pointer
  memset(attr.attr_val.char_val.str, 0, len);
  memcpy(attr.attr_val.char_val.str, src, len);
  
}

/*
 * This method is used to fill in the data stored in a block of 
 * bytes into a tuple.
 * Input: src - pointer the beginning of the data block.
 * Input: src_size - number of bytes in the data block.
 * Input: rel_info - pointer to the relation schema info.
 * Input: target - pointer to the tuple where the data is to be stored.
 * Ouput: Diagnostic value indicating if the operation was a success or not.
 */

int fill_in_tuple(char *src, int src_size,  relation_info *rel_info,  
		  tuple *target){
  int i=0, len = 0, offset=0;
  attr_info a_info;
  
  len = rel_info->num_attrs;
  for (i=0; i < len; ++i){
    a_info = rel_info->attributes[i];
    switch(a_info.attr_type){
    case INT_TYPE:
      if (offset + a_info.type_size > src_size){
	// Not enough space to read data
	return BAD_RECORD_FORMAT;
      }
      read_int(src + offset, target->attr_list[i]);
      offset += a_info.type_size;
      break;
    case DOUBLE_TYPE:
      if (offset + a_info.type_size > src_size){
	// Not enough space to read data
	return BAD_RECORD_FORMAT;
      }
      read_double(src + offset, target->attr_list[i]);
      offset += a_info.type_size;
      break;
    case CHAR_TYPE:
      if (offset + a_info.type_size >  src_size){
	// Not enough space to read data
	return BAD_RECORD_FORMAT;
      }
      read_char(src + offset, a_info.type_size, target->attr_list[i]);
      offset += a_info.type_size;
      break;
    default:
      return BAD_RECORD_FORMAT;
    }
  }
  return OK;
}


/*
 * Copies an integer value from one attribute to another.
 * Input: dest - the attribute where the integer value is to be stored.
 * Input: src - the attribute where the integer is currently held.
 */

void copy_int_attr(attribute& dest, const attribute& src){
  dest.attr_val.int_val = src.attr_val.int_val;
}

/*
 * Copies a double value from one attribute to another.
 * Input: dest - the attribute where the double value is to be stored.
 * Input: src - the attribute where the double is currently held.
 */

void copy_double_attr(attribute& dest, const attribute& src){
  dest.attr_val.double_val = src.attr_val.double_val;
}

/*
 * Copies a character value from one attribute to another.
 * Input: dest - the attribute where the character value is to be stored.
 * Input: src - the attribute where the characted is currently held.
 */

void copy_char_attr(attribute& dest, const attribute& src){
  dest.attr_val.char_val.len = src.attr_val.char_val.len;
  memset(dest.attr_val.char_val.str, 0, dest.attr_val.char_val.len);
  memcpy(dest.attr_val.char_val.str, src.attr_val.char_val.str, 
	  src.attr_val.char_val.len);
}


void print_tuple(tuple *tup, FILE *out){
  int i=0, len = 0;
  
  len = tup->num_attrs;
  for (i=0; i < len; ++i){
    switch(tup->attr_list[i].attr_type){
    case CHAR_TYPE:
      fprintf(out, "%s    ", tup->attr_list[i].attr_val.char_val.str);
      break;
    case INT_TYPE:
      fprintf(out, "%d    ", tup->attr_list[i].attr_val.int_val);
      break;
    case DOUBLE_TYPE:
      fprintf(out, "%g    ", tup->attr_list[i].attr_val.double_val);
      break;
    default:
      fprintf(out, "???    ");
    }
  }
  fprintf(out, "\n");
}


/*
 * This function creates a new tuple from a relation schema
 * information object.
 * Input: rel_info - pointer to relation information structure.
 * Output: a new tuple that conforms to the schema.
 */
tuple *make_tuple(relation_info *rel_info){
  // Asumes that rel_info is not null.
  tuple *result = NULL;

  // ADD YOUR CODE HERE TO CREATE A TUPLE FROM THE RELATION 
  // SCHEMA INFORMATION

  return result;
}


/*
 * This function creates a new tuple based on the schema 
 * information contained in a projection list.
 * Input: proj_list - list of infornmation about projections to be performed.
 * Output: a new tuple that conforms to the schema for the projections.
 */
tuple *make_tuple(proj_attr_list *proj_list){
  // Asumes that proj_list is not null.
  tuple *result = NULL;

  // ADD YOUR CODE HERE T0 CREATE A TUPLE FROM THE RELATION
  // SCHEMA INFORMATION

  return result;
}
