#include <cstdio>
#include <cstdlib>
#include "schema.h"
#include "error.h"

/*
 * Returns a pointer to a new relation information structure.
 * Input: none
 * Output: a pointer to a new relation information structure.
 */
relation_info *make_relation_info(){
  relation_info* result;
  
  result = (relation_info *) calloc(1, sizeof(relation_info));
  return result;
}

/*
 * Free the pointer to the relation information structure.
 * Input: a pointer to the relation information structure.
 * Output: none
 */
void free_relation_info(relation_info *relation_info){
  if (relation_info != NULL){
    if (relation_info->attributes != NULL){
      free(relation_info->attributes);
    }
    free(relation_info);
  }
  return;
}

/*
 * Reads a string from the input file. 
 * Input: the pointer to the input file structure
 * Input: the pointer to the place to store the string. The function
 * assumes that there is enough space to store the string being read.
 * Output: status code indicating OK, if the operation was successful,
 * or ERROR otherwise.
 */
int read_string(FILE *data_in, char* buf){
  int code = 0;
  
  code = fscanf(data_in, "%s", buf);
  if (code >= 1){
    return OK;
  }
  else {
    return ERROR;
  }
}

/*
 * Reads an integer from the input file. 
 * Input: the pointer to the input file structure
 * Input: the pointer to the place to store the integer. 
 * Output: status code indicating OK, if the operation was successful,
 * or ERROR otherwise.
 */
int read_integer(FILE *data_in, int* buf){
  int code = 0;
  
  code = fscanf(data_in, "%d", buf);
  if (code >= 1){
    return OK;
  }
  else {
    return ERROR;
  }
}

/*
 * This function closes the input data file and deallocates
 * the memory for the relation information object.
 */
void clean_up(FILE *data_in, relation_info* r_info){
  fclose(data_in);
  free_relation_info(r_info);
  return;
}

attr_info *make_relation_attrs(int num_attrs){
  attr_info *result;
  
  result = (attr_info *) calloc(num_attrs, sizeof(attr_info));
  return result;
}


/*
 * This function is used to map the name of an attribute type from 
 * a numeric value to a string.
 */
void get_type_name(char *buf, int type){
  switch(type){
  case CHAR_TYPE:
    strcpy(buf, "char\0");
    break;
  case INT_TYPE:
    strcpy(buf, "integer\0");
    break;
  case DOUBLE_TYPE:
    strcpy(buf, "double\0");
    break;
  default:
    strcpy(buf, "unknown\0");
  }
  return;
}

/*
 * This is a utility function used to print the contents of a
 * relation schema information structure. This function is 
 * can be used for debugging purposes. The function assumes 
 * the relation information structure to be correct.
 * Input: pointer to the relation schema 
 * Output: none
 */
void print_relation_schema(relation_info *rel_info){
  int i=0, len = 0;
  char attr_type_name[MAX_NAME];
  attr_info a_info;
  
  // Print contents to output screen via stderr to avoid buffering
  fprintf(stderr, "Relation Name: %s\n", rel_info->rel_name);
  fprintf(stderr, "Relation Cardinality: %d\n", rel_info->rel_card);
  fprintf(stderr, "Relation Storage File: %s\n", 
	  rel_info->rel_file);
  fprintf(stderr, "Relation number of attributes: %d\n", 
	  rel_info->num_attrs);
  fprintf(stderr, "Relation attributes:\n");
  len = rel_info->num_attrs;
  for (i=0; i < len; ++i){
    a_info = rel_info->attributes[i];
    fprintf(stderr, "\t Attribute Name: %s\n", a_info.attr_name);
    get_type_name(attr_type_name, a_info.attr_type);
    fprintf(stderr, "\t Attribute Type Name: %s\n", attr_type_name);
    fprintf(stderr, "\t Attribute Type Sise: %d bytes\n\n", 
	    a_info.type_size);
  }
}

/*
 * This function should be used to read the information for an
 * attributer from the schema file. The information should be
 * stored in the info structure.
 */
int  get_next_attr(FILE *in, attr_info& info){

  // ADD YOUR CODE HERE TO READ ATTRIBUTE INFO FROM FILE

  return OK;
}

/*
 * This function is used to read the schema information for 
 * a relation R, and return a pointer to a relation information
 * structure. The function must always close the input data file
 * before exiting.
 * Input: the relation name relation_name
 * Input: a variable used to determine the status of the operation.
 * Ouput: A pointer to a relation information structure if the 
 * schema information is found. In this case, the status code should be
 * set to OK. Otherwise, the function should return the NULL pointer,
 * and the status code should indicate the cause for the error,
 * which could be one of : FILE_NOT_FOUND, ILLEGAL_FILE_FORMAT, NO_MEMORY.
 */

relation_info *get_relation_info(const char* relation_name,
				 int& status){
  FILE* data_in = NULL;
  relation_info *result = NULL;

  // ADD YOUR CODE HERE
  return result;
}  
