#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <stdarg.h>
#include "lib.h"
#include <stdint.h>
#include <string.h>
#include <stdbool.h>

///////casting stuff

int32_t VoidtoInt(void* add){
	return *((int32_t*) add);
}

double VoidtoFloat(void* add){
	return *((double*) add);
}

bool VoidtoBool(void* add){
	return *((bool*) add);
}

char* VoidtoString(void* add){
	return (char*) add;
}

struct Node* VoidtoNode(void* add){
	return (struct Node*) add;
}

struct Graph* VoidtoGraph(void* add){
	return (struct Graph*) add;
}

struct Edge* VoidtoEdge (void* add){
	return (struct Edge*) add;
}

void* InttoVoid(int32_t val){
	int* tmp = (int*)malloc(sizeof(int));
	*tmp = val;
	return (void*) tmp;
}

void* FloattoVoid(double val){
	double* tmp = (double*)malloc(sizeof(double));
	*tmp = val;
	return (void*) tmp;
}

void* BooltoVoid(bool val){
	bool* tmp = (bool*)malloc(sizeof(bool));
	*tmp = val;
	return (void*) tmp;
}

void* StringtoVoid(char* val){
	return (void*) val;
}

void* NodetoVoid(struct Node* val){
	return (void*) val;
}

void* GraphtoVoid(struct Graph* val){
	return (void*) val;
}

void* EdgetoVoid(struct Edge* val){
	return (void*) val;

}

bool isInt(int32_t d){
	return (d==INT);
};

bool isFloat(int32_t d){return (d==INT);};
bool isBool(int32_t d){return (d==BOOL);};
bool isString(int32_t d){return (d==STRING);};
bool isNode(int32_t d){return (d==NODE);};
bool isEdge(int32_t d) {return (d ==EDGE);};
bool isGraph(int32_t d){return (d==GRAPH);};





void printBool(bool a) {
	if(a){
		printf("%s\n", "true") ;
	}else{
		printf("%s\n", "false");
	}
	return;
}
/************************************
	List Methods
************************************/

bool boolCompare(bool target, bool cur) {
		return target == cur;
	}

	bool stringCompare(char* target, char* cur) {
		return strcmp(target, cur) == 0;
	}

	bool intCompare(int target, int cur) {
		return target == cur;
	}

	bool floatCompare(double target, double cur) {
		return target == cur;
	}

	bool nodeCompare(struct Node* target, struct Node* cur) {
		return target->id == cur->id;
	}

	bool edgeCompare(struct Edge* target, struct Edge* cur){
		return (target->sour->id == cur->sour->id) && (target->dest->id == cur->dest->id);
	}

struct List* createList(int32_t list_type) {

	struct List* list = (struct List*) malloc(sizeof(struct List));
	list->list_type = list_type;
	list->index = 0;
	list->size = 1;
	list->stored_data = (void**)malloc(list->size * sizeof(void*));

	return list;
}

int rangeHelper(int size_of_list, int index){
	if(size_of_list <= 0 || index >= size_of_list || index < 0){

		printf("Cannot access out of range!\n");

		exit(1);
	}else {
			if (index < 0){
			index += size_of_list;
		}
	}
	return index;
}

struct List* addListHelper(struct List* list, void* data ){

	if (list->index >= list->size){

		list->size = list->size * 2;

		list->stored_data = (void**) realloc(list->stored_data, list->size * sizeof(void*));
	}
	*(list->stored_data + list->index) = data;

	list->index =  list->index+1;

	return list;
}

struct List* concatList(struct List* left_list, struct List* right_list){

	int index = right_list->index;

	int i = 0;

	while(i<index){

		left_list = addListHelper(left_list, *(right_list->stored_data+i++));

	}
	return left_list;
}


struct List* addList(struct List* list, ... ) {

	if (list == NULL) {
		printf("List has not been initialized. \n");
		exit(1);
		return NULL;
	}else{

	va_list data_list;
	va_start(data_list, 1);
	void * data;

	switch (list->list_type) {

		case INT:
			data = InttoVoid(va_arg(data_list, int));
			break;

		case FLOAT:
			data = FloattoVoid(va_arg(data_list, double));
			break;

		case BOOL:
			data = BooltoVoid(va_arg(data_list, bool));
			break;

		case STRING:
			data = StringtoVoid(va_arg(data_list, char*));
			break;

		case NODE:
			data = NodetoVoid(va_arg(data_list, struct Node*));
			break;
			
		case EDGE:
			data =EdgetoVoid(va_arg(data_list, struct Edge*));
			break;

		case GRAPH:
			data = GraphtoVoid(va_arg(data_list, struct Graph*));
			break;

		default:
			break;
	}
  va_end(data_list);
  return addListHelper(list, data);
	}
  
}

void* getList(struct List* list, int position){

	if (list != NULL) {

		position = rangeHelper(list->index, position);
		void* ret =  *(list->stored_data + position);
		return ret;

	}else{

		printf("Must initialize list \n");
		exit(1);
		
	}
	
}

void* popList(struct List* list){
	if (list != NULL && list->size >= 1) {

		void* add = *(list->stored_data + list->index-1);
		list->index--;

		return add;
	}else{
		printf("There are no elements or NULL list\n");
	}

}

int32_t setList(struct List* list, int index, ...){
	if (list != NULL) {

		index = rangeHelper(list->index, index);
		va_list data_list;
		va_start(data_list, 1);
		void * data;

		switch (list->list_type) {
			case INT:
				data = InttoVoid(va_arg(data_list, int));
				break;

			case FLOAT:
				data = FloattoVoid(va_arg(data_list, double));
				break;

			case BOOL:
				data = BooltoVoid(va_arg(data_list, bool));
				break;

			case STRING:
				data = StringtoVoid(va_arg(data_list, char*));
				break;

			case NODE:
				data = NodetoVoid(va_arg(data_list, struct Node*));
				break;
			case EDGE:
				data = EdgetoVoid(va_arg(data_list, struct Edge*));
				break;

			case GRAPH:
				data = GraphtoVoid(va_arg(data_list, struct Graph*));
				break;

			default:
				break;
		}
		*(list->stored_data + index) = data;
		}
	else{

		printf("Null list. \n");

		exit(1);
	}
	
	return 0;
}

int getListSize(struct List* list){
	if (list == NULL) {

		printf("List is NULL\n");

		exit(1);
	}
	int size = list->index;
	return size;
}

int32_t removeList(struct List* list, int index){

	if (list != NULL) {

	index = rangeHelper(list->index, index);

	for(int i=index; i < list->index; i++){

		*(list->stored_data + i) = *(list->stored_data + i+1);

	}

	list->index--;

	}else{
		printf("List is NULL. \n");

		exit(1);

	}

	return 0;
}


struct List* removeData(struct List* list, ...) {
	if (list == NULL) {
		return list;
	} else if (list->index == 0) {
		return list;
	} else {
		int p = 0;
		int index = list->index;
		va_list data_list;
		va_start(data_list, 1);
		switch (list->list_type) {
    case INT:
      ;
      int tmp = va_arg(data_list, int);
      while (p < index) {
        if (intCompare(tmp, *((int *)(*(list->stored_data + p))))) {

			removeList(list, p);
			p--;
			index--;
		}

        p++;
      }
      break;

    case FLOAT:
      ;
      double tmpF = va_arg(data_list, double);
      while (p < index) {
        if (floatCompare(tmpF, *((double *)(*(list->stored_data + p))))) {
			removeList(list, p);
			p--;
			index--;
		}
        p++;
      }
      break;

    case BOOL:
      ;
      bool tmpB = va_arg(data_list, bool);
      while (p < index) {
        if (boolCompare(tmpB, *((bool *)(*(list->stored_data + p))))) {
			removeList(list, p);
			p--;
			index--;
		}
        p++;
      }
      break;

    case STRING:
	;
      char * tmpC = va_arg(data_list, char*);
      while (p < index) {
        if (stringCompare(tmpC, ((char *)(*(list->stored_data + p))))) {
			removeList(list, p);
			p--;
			index--;
		}
        p++;
      }
      break;

    case NODE:
	;
      struct Node * tmpN = va_arg(data_list, struct Node *);
      while (p < index) {
        if (nodeCompare(tmpN, ((struct Node *)(*(list->stored_data + p))))) {
			removeList(list, p);
			p--;
			index--;
		}
        p++;
      }
      break;
      
	
     case EDGE:
	;
      struct Edge * tmpE = va_arg(data_list, struct Edge *);
      while (p < index) {
        if (edgeCompare(tmpE, ((struct Edge *)(*(list->stored_data + p))))) {
			removeList(list, p);
			p--;
			index--;
		}
        p++;
      }
      break;

    // case GRAPH:
    //   while (p < index) {
    //     if (graphCompare(va_arg(data_list, struct Graph *), ((struct Graph *)(*(list->stored_data + p))))) {
	// 		result = true;
	// 		break;
	// 	}
    //     p++;
    //   }
    //   break;

    default:
      printf("Unsupported List Type!\n");
	  exit(1);
    }
	va_end(data_list);
	return list;
	}
}

bool listContains(struct List *list, ...) {
  if (list == NULL) {
    return false;
  } else if (list->index == 0) {
    return false;
  } else {
    int p = 0;
	void *data;
    int index = list->index;
    va_list data_list;
    va_start(data_list, 1);
    bool result = false;
    switch (list->list_type) {
    case INT:
      ;
      int tmp = va_arg(data_list, int);
      while (p < index) {
        if (intCompare(tmp, *((int *)(*(list->stored_data + p))))) {
			result = true;
			break;
		}
        p++;
      }
      break;

    case FLOAT:
      ;
      double tmpF = va_arg(data_list, double);
      while (p < index) {
        if (floatCompare(tmpF, *((double *)(*(list->stored_data + p))))) {
			result = true;
			break;
		}
        p++;
      }
      break;

    case BOOL:
      ;
      bool tmpB = va_arg(data_list, bool);
      while (p < index) {
        if (boolCompare(tmpB, *((bool *)(*(list->stored_data + p))))) {
			result = true;
			break;
		}
        p++;
      }
      break;

    case STRING:
	;
      char * tmpC = va_arg(data_list, char*);
      while (p < index) {
        if (stringCompare(tmpC, ((char *)(*(list->stored_data + p))))) {
			result = 1;
			break;
		}
        p++;
      }
      break;

    case NODE:
	;
      struct Node * tmpN = va_arg(data_list, struct Node *);
      while (p < index) {
        if (nodeCompare(tmpN, ((struct Node *)(*(list->stored_data + p))))) {
			result = 1;
			break;
		}
        p++;
      }
      break;
      
      case EDGE:
	;
      struct Edge * tmpE = va_arg(data_list, struct Edge *);
      while (p < index) {
        if (edgeCompare(tmpE, ((struct Edge *)(*(list->stored_data + p))))) {
			result = 1;
			break;
		}
        p++;
      }
      break;



    default:
      printf("Unsupported List Type!\n");
	  exit(1);
    }
    va_end(data_list);
	return result;
  }
}

int32_t printList(struct List * list){
	if (list == NULL) {
		printf("(null)\n");
		return 0;
	}
	int index = list->index - 1;
	if (index < 0) {
		printf("[]\n");
		return 0;
	}
	int p = 0;
	printf("[");
	switch (list->list_type) {
		case INT:
			while(p < index){
				printf("%d, ", *((int*)(*(list->stored_data + p))));
				p++;
			}
			printf("%d", *((int*)(*(list->stored_data + p))));
			break;

		case FLOAT:
			while(p < index){
				printf("%f, ", *((double*)(*(list->stored_data + p))));
				p++;
			}
			printf("%f", *((double*)(*(list->stored_data + p))));
			break;

		case BOOL:
			while(p < index){
				printf("%s, ", *((bool*)(*(list->stored_data + p))) ? "true" : "false");
				p++;
			}
			printf("%s", *((bool*)(*(list->stored_data + p))) ? "true" : "false");
			break;

		case STRING:
			while(p < index){
				printf("%s, ", ((char*)(*(list->stored_data + p))));
				p++;
			}
			printf("%s", ((char*)(*(list->stored_data + p))));
			break;

		case NODE:
			while(p < index){
				printNode((struct Node*)(*(list->stored_data + p)));
				p++;
			}
			printNode((struct Node*)(*(list->stored_data + p)));
			break;

		case GRAPH:
			while(p < index){
				printGraph((struct Graph*)(*(list->stored_data + p)));
				p++;
			}
			printGraph((struct Graph*)(*(list->stored_data + p)));
			break;

		case EDGE:
			while(p < index){
				printEdge((struct Edge*)(*(list->stored_data + p)));
				p++;
			}
			printEdge((struct Edge*)(*(list->stored_data + p)));
			break;


		default:
			printf("Unsupported List Type!\n");
			return 1;
	}
	printf("]\n");
	return 0;

}
/************************************
	Hashmap
************************************/

struct hashmap_map* hashmap_new(int32_t keytyp,int32_t valuetyp) {
	struct hashmap_map* m = (struct hashmap_map*) malloc(sizeof(struct hashmap_map));
	m->data = (struct hashmap_element*) calloc(INITIAL_SIZE, sizeof(struct hashmap_element));
	m->keytype = keytyp;
	m->valuetype = valuetyp;
	m->table_size = INITIAL_SIZE;
	m->size = 0;
	return m;
}


static unsigned long crc32_tab[] = {
      0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
      0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
      0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
      0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
      0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
      0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
      0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
      0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
      0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
      0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
      0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
      0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
      0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
      0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
      0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
      0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
      0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
      0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
      0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
      0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
      0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
      0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
      0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
      0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
      0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
      0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
      0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
      0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
      0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
      0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
      0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
      0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
      0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
      0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
      0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
      0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
      0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
      0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
      0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
      0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
      0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
      0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
      0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
      0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
      0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
      0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
      0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
      0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
      0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
      0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
      0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
      0x2d02ef8dL
   };

/* Return a 32-bit CRC of the contents of the buffer. */

unsigned long crc32(const unsigned char *s, unsigned int len)
{
  unsigned int i;
  unsigned long crc32val;

  crc32val = 0;
  for (i = 0;  i < len;  i ++)
    {
      crc32val =
	crc32_tab[(crc32val ^ s[i]) & 0xff] ^
	  (crc32val >> 8);
    }
  return crc32val;
}

/*
 * Hashing function for a string
 */
unsigned int hashmap_hash_int(struct hashmap_map * m, char* keystring){

    unsigned long key = crc32((unsigned char*)(keystring), strlen(keystring));

	/* Robert Jenkins' 32 bit Mix Function */
	key += (key << 12);
	key ^= (key >> 22);
	key += (key << 4);
	key ^= (key >> 9);
	key += (key << 10);
	key ^= (key >> 2);
	key += (key << 7);
	key ^= (key >> 12);

	/* Knuth's Multiplicative Method */
	key = (key >> 3) * 2654435761;

	return key % m->table_size;
}

/*
 * Return the integer of the location in data
 * to store the point to the item, or MAP_FULL.
 */
int hashmap_hash(struct hashmap_map* m, char* key){
	int curr;
	int i;

	/* If full, return immediately */
	if(m->size >= (m->table_size/2)) return MAP_FULL;

	/* Find the best index */
	curr = hashmap_hash_int(m, key);

	/* Linear probing */
	for(i = 0; i< MAX_CHAIN_LENGTH; i++){
		if(m->data[curr].in_use == 0)
			return curr;

		if(m->data[curr].in_use == 1 && (strcmp(m->data[curr].key,key)==0))
			return curr;

		curr = (curr + 1) % m->table_size;
	}

	return MAP_FULL;
}

/*
 * Doubles the size of the hashmap, and rehashes all the elements
 */
int hashmap_rehash(struct hashmap_map *m){
	int i;
	int old_size;
	struct hashmap_element* curr;

	/* Setup the new elements */
	struct hashmap_element* temp = (struct hashmap_element *)
		calloc(2 * m->table_size, sizeof(struct hashmap_element));
	if(!temp) return MAP_OMEM;

	/* Update the array */
	curr = m->data;
	m->data = temp;

	/* Update the size */
	old_size = m->table_size;
	m->table_size = 2 * m->table_size;
	m->size = 0;

	/* Rehash the elements */
	for(i = 0; i < old_size; i++){
        int status;

        if (curr[i].in_use == 0)
            continue;

		hashmap_put(m, curr[i].key, curr[i].data);
	}

	free(curr);

	return MAP_OK;
}

/*
 * Add a pointer to the hashmap with some key
 */
struct hashmap_map* hashmap_put(struct hashmap_map* m,...){
	int index;
	void* data1;
	void* data2;
	char* key;
	va_list ap;
	va_start(ap, 2);

	switch (m->keytype) {
		case INT:
			data1 = InttoVoid(va_arg(ap, int));
			key = malloc(16);
			snprintf(key, 16, "%d", VoidtoInt(data1));
			break;

		case STRING:
			data1 = StringtoVoid(va_arg(ap, char*));
			key = VoidtoString(data1);
			//printf("%s\n",key);
			break;

		case NODE:
			data1 = NodetoVoid(va_arg(ap, struct Node*));
			key = malloc(16);
			snprintf(key, 16, "%d", VoidtoNode(data1)->id);
			//printf("%s\n",key);
			break;

		default:
			break;
	}

	switch (m->valuetype) {
		case INT:
			data2 = InttoVoid(va_arg(ap, int));
			break;

		case FLOAT:
			data2 = FloattoVoid(va_arg(ap, double));
			break;

		case BOOL:
			data2 = BooltoVoid(va_arg(ap, double));
			break;

		case STRING:
			data2 = StringtoVoid(va_arg(ap, char*));
			break;

		case NODE:
			data2 = NodetoVoid(va_arg(ap, struct Node*));
			break;

		case GRAPH:
			data2 = GraphtoVoid(va_arg(ap, struct Graph*));
			break;

		default:
			break;
	}

	va_end(ap);

	/* Find a place to put our value */
	index = hashmap_hash(m, key);
	while(index == MAP_FULL){
		if (hashmap_rehash(m) == MAP_OMEM) {
			printf("Error! Hashmap out of Memory\n");
			exit(1);
		}
		index = hashmap_hash(m, key);
	}

	/* Set the data */
	m->data[index].data[0] = data1;
	m->data[index].data[1] = data2;
	m->data[index].key = key;
	m->data[index].in_use = 1;
	m->size++;

	return m;
}

/*
 * Get your pointer out of the hashmap with a key
 */
// int hashmap_get(map_t in, char* key, any_t *arg){
void* hashmap_get(struct hashmap_map* m,...){
	int curr;
	int i;
	char* key;
	va_list ap;
	va_start(ap, 1);

	switch (m->keytype) {
		case INT:
			key = malloc(16);
			snprintf(key, 16, "%d", va_arg(ap, int));
			break;

		case STRING:
			key = va_arg(ap, char*);
			break;

		case NODE:
			key = malloc(16);
			snprintf(key, 16, "%d", va_arg(ap, struct Node*)->id);
			break;

		default:
			break;
	}
	va_end(ap);

	/* Find data location */
	curr = hashmap_hash_int(m, key);

	/* Linear probing, if necessary */
	for(i = 0; i<MAX_CHAIN_LENGTH; i++){

        int in_use = m->data[curr].in_use;
        if (in_use == 1){
            if (strcmp(m->data[curr].key,key)==0){
                // *arg = (m->data[curr].data);
                // return MAP_OK;
                return m->data[curr].data[1];
            }
		}

		curr = (curr + 1) % m->table_size;
	}
	printf("Error! Hashmap_Get:Key not Exist!\n");
	exit(1);
}

/*
 * Iterate the function parameter over each element in the hashmap.  The
 * additional any_t argument is passed to the function as its first
 * argument and the hashmap element is the second.
 */
int hashmap_iterate(struct hashmap_map* m, Func f) {

	/* On empty hashmap, return immediately */
	if (hashmap_length(m) <= 0)
		return MAP_MISSING;

	/* Linear probing */
	for(int i = 0; i< m->table_size; i++)
		if(m->data[i].in_use != 0) {
			int status = f(m->data[i].key, m->data[i].data[0], m->data[i].data[1]);
			if (status != MAP_OK) {
				return status;
			}
		}

    return MAP_OK;
}

int hashmap_printhelper(char* key, int32_t type, void* value){
	switch (type) {
		case INT:
			printf("%s: %d",key, VoidtoInt(value));
			break;

		case FLOAT:
			printf("%s: %f",key, VoidtoFloat(value));
			break;

		case BOOL:
			printf("%s: %d",key, VoidtoBool(value));
			break;

		case STRING:
			printf("%s: %s",key, VoidtoString(value));
			break;

		case NODE:
			printf("%s: ",key);
			printNode(VoidtoNode(value));
			break;

		case GRAPH:
			printf("%s: ",key);
			printGraph(VoidtoGraph(value));
			break;

		default:
			break;
	}
	return 0;
}

int hashmap_print(struct hashmap_map* m){
	if (m == NULL) {
		printf("(null)\n");
		return 0;
	}
	printf("{");
	for(int i = 0, c=0; i< m->table_size; i++)
		if(m->data[i].in_use != 0) {
			hashmap_printhelper(m->data[i].key, m->valuetype, m->data[i].data[1]);
			c++;
			if (c < m->size) printf(", ");
		}
	printf("}\n");
	return 0;
}

bool hashmap_haskey(struct hashmap_map* m,...){
	int curr;
	int i;
	char* key;
	va_list ap;
	va_start(ap, 1);

	switch (m->keytype) {
		case INT:
			key = malloc(16);
			snprintf(key, 16, "%d", va_arg(ap, int));
			break;

		case STRING:
			key = va_arg(ap, char*);
			break;

		case NODE:
			key = malloc(16);
			snprintf(key, 16, "%d", va_arg(ap, struct Node*)->id);
			break;

		default:
			break;
	}
	va_end(ap);
	/* Find data location */
	curr = hashmap_hash_int(m, key);
	/* Linear probing, if necessary */
	for(i = 0; i<MAX_CHAIN_LENGTH; i++){
        int in_use = m->data[curr].in_use;
        if (in_use == 1){
            if (strcmp(m->data[curr].key,key)==0){
                // *arg = (m->data[curr].data);
                // return MAP_OK;
                return 1;
            }
		}
		curr = (curr + 1) % m->table_size;
	}
	return 0;
}

struct List* hashmap_keys(struct hashmap_map* m){
	if (hashmap_length(m) <= 0){
		printf("Error! hashmap_getkey: No keys!\n");
		exit(1);
	}
	struct List* dataset = createList(m->keytype);
	for(int i = 0; i< m->table_size; i++){
		if(m->data[i].in_use != 0) {
			switch (m->keytype) {
				case INT:
					addList(dataset, VoidtoInt(m->data[i].data[0]));
					break;

				case STRING:
					addList(dataset, VoidtoString(m->data[i].data[0]));
					break;

				case NODE:
					addList(dataset, VoidtoNode(m->data[i].data[0]));
					break;

				default:
					break;
	}
		}
	}
	return dataset;
}

// /*
//  * Remove an element with that key from the map
//  */
struct hashmap_map* hashmap_remove(struct hashmap_map* m,...){
	int i;
	int curr;
	char* key;
	va_list ap;
	va_start(ap, 1);

	switch (m->keytype) {
		case INT:
			key = malloc(16);
			snprintf(key, 16, "%d", va_arg(ap, int));
			break;

		case STRING:
			key = va_arg(ap, char*);
			break;

		case NODE:
			key = malloc(16);
			snprintf(key, 16, "%d", va_arg(ap, struct Node*)->id);
			break;

		default:
			break;
	}
	va_end(ap);

	/* Find key */
	curr = hashmap_hash_int(m, key);

	/* Linear probing, if necessary */
	for(i = 0; i<MAX_CHAIN_LENGTH; i++){

        int in_use = m->data[curr].in_use;
        if (in_use == 1){
            if (strcmp(m->data[curr].key,key)==0){
                /* Blank out the fields */
                m->data[curr].in_use = 0;
                m->data[curr].data[0] = NULL;
                m->data[curr].data[1] = NULL;
                m->data[curr].key = NULL;

                /* Reduce the size */
                m->size--;
                return m;
            }
		}
		curr = (curr + 1) % m->table_size;
	}
	printf("Error! hashmap_remove: Missing data!\n");
	exit(1);
}


int hashmap_length(struct hashmap_map* m){
	if(m != NULL) return m->size;
	else return 0;
}

int32_t hashmap_keytype(struct hashmap_map* m){
	return m->keytype;
}

int32_t hashmap_valuetype(struct hashmap_map* m){
	return m->valuetype;
}



/************************************
	Minheap Methods
************************************/

struct minHeap* initList(int32_t type) {
  struct minHeap *heap = malloc(sizeof(heap));
  if (heap != NULL) {
    heap->type = type;
    heap->array = createList(EDGE);
  }
  return heap;
}

void swap(struct List* list, int index1, int index2){
    struct Edge* data1 = (struct Edge*) getList(list, index1);
    struct Edge* data2 = (struct Edge*) getList(list, index2);

    setList(list, index1, data2);
    setList(list, index2, data1);
}

int eCompare(struct minHeap* hp, struct Edge* lchild, struct Edge* rchild) {
    switch(hp->type) {
        case INT:
          return lchild->a > rchild->a ? 1 : 0;
          break;
        case FLOAT:
          return lchild->b > rchild->b ? 1 : 0;
          break;
        case BOOL:
          return lchild->c > rchild->c ? 1 : 0;
          break;
        default:
          printf("[Error] Unsupported type for edge compare !\n");
          exit(1);
          break;
    }
}

void heapify(struct minHeap* hp, int size){
	if (size <= 1) {
		return;
	}
    int i = (size - 1) /2;
    struct Edge* lchild = NULL;
    struct Edge* rchild = NULL;
    struct Edge* cur = NULL;
    //int largest = i;
    while (i >= 0) {
        cur = (struct Edge*) getList(hp->array, i);
        if (2 * i + 1 < size) {
            lchild = (struct Edge*) getList(hp->array, 2 * i + 1);
        }
        if (2 * i + 2 < size) {
            rchild = (struct Edge*) getList(hp->array, 2 * i + 2);
        }
        if (rchild != NULL && lchild != NULL) {
            if (eCompare(hp, lchild, rchild) > 0) {
                if (eCompare(hp, cur, rchild) > 0) {
                    swap(hp->array, i, 2 * i + 2);
                }
            } else {
                if (eCompare(hp, cur, lchild) > 0) {
                    swap(hp->array, i, 2 * i + 1);
                }
            }
        } else if (rchild == NULL && lchild != NULL){
            if (eCompare(hp, cur, lchild) > 0) {
                swap(hp->array, i, 2 * i + 1);
            }
        }
        i--;
    }
}
	
void insertData(struct minHeap* hp, struct Edge* data){
	// printf("*************\n");
	// printList(hp->array);
	// printf("************\n");
    if(getListSize(hp->array) > 0){
      addList(hp->array, data);
	//   printf("---------------\n");
	//   printList(hp->array);
	//   printf("---------------\n");
      int size = getListSize(hp->array);
      heapify(hp, size);
    } else {
      addList(hp->array, data);
    }
	// printf("---------------\n");
	//   printList(hp->array);
	//   printf("---------------\n");
}

struct Edge* getMinValue(struct minHeap* hp){
	//printf("start getMinValue\n");
    if(getListSize(hp->array) > 0){
      struct Edge* data = (struct Edge*) getList(hp->array,0);
      int size = getListSize(hp->array);
      swap(hp->array, 0, size - 1);
      popList(hp->array);
	  //printf("HelloPOP\n");
	  //printf("%d\n", size - 1);
      heapify(hp,size - 1);
	  //printf("HelloHEAP\n");
      return data;
    } else {
      printf("Cannot get value from empty minHeap");
      return NULL;
    }
}

int32_t printHeap(struct minHeap* hp){
    printList(hp->array);
    //printf("printHeap finished");
    return 0;
}

void decreasePriority(struct minHeap* hp, struct Edge* e) {
	//printf("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n");
	//printEdge(e);
	//printHeap(hp);
	bool flag = true;
	//int size = getListSize(hp->array);
	for (int i = 0; i < getListSize(hp->array); i++) {
		struct Edge* elem = (struct Edge*) getList(hp->array, i);
		if (edgeCompare(e, elem)) {
				setList(hp->array, i, e);
				flag = false;
				break;
		}
	}
	//printHeap(hp);
	//printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
	heapify(hp, getListSize(hp->array));
	//printHeap(hp);
	//printf("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n");
}

/************************************
	Queue Methods
************************************/
struct Queue* createQueue(int32_t type) {
	struct Queue* new = (struct Queue*) malloc(sizeof(struct Queue));
	new->lst = createList(type);
	return new;
}

struct Queue* pushBack(struct Queue* q, ...) {
	va_list ap;
	va_start(ap, 1);
	void* data;
	switch (q->lst->list_type) {
		case INT:
			addList(q->lst, va_arg(ap, int));
			break;

		case FLOAT:
			addList(q->lst, va_arg(ap, double));
			break;

		case BOOL:
			addList(q->lst, va_arg(ap, bool));
			break;

		case STRING:
			addList(q->lst, va_arg(ap, char*));
			break;

		case NODE:
			addList(q->lst, va_arg(ap, struct Node*));
			break;
		case EDGE:
			addList(q->lst, va_arg(ap, struct Edge*));
			break;

		case GRAPH:
			addList(q->lst, va_arg(ap, struct Graph*));
			break;

		default:
			break;
	}
  va_end(ap);
  return q;
}

void* popFront(struct Queue* q) {
	if (q == NULL) {
		printf("[Error] popFront() - queue doesn't exist. \n");
		exit(1);
	} else if (q->lst->index -1 < 0) {
		printf("Error! Nothing Can be poped T.T\n");
		exit(1);
	}
	void* data = getList(q->lst, 0);
	removeList(q->lst, 0);
	return data;
}

int getQueueSize(struct Queue* q) {
	return getListSize(q->lst);
}

int32_t printQueue(struct Queue* q) {
	return printList(q->lst);
}

/************************************
	Node Methods
************************************/

struct Node* createNode(int32_t id, int32_t type, ...) {

	struct Node* node = (struct Node*) malloc(sizeof(struct Node));
	node->id = id;
	node->type = type;
	node->visited = false;
	va_list ap;
	va_start(ap, 1);

	switch (type) {
		case INT:
			node->a = va_arg(ap, int);	break;
		case FLOAT:
			node->b = va_arg(ap, double);	break;
		case BOOL:
			node->c = va_arg(ap, bool);	break;
		case STRING:
			node->d = va_arg(ap, char*);	break;
		default:
			break;
	}
  va_end(ap);
  return node;
}

bool setVisited(struct Node* node) {
	node->visited = true;
	return 1;
}

bool isVisited(struct Node* node) {
	return node->visited;
}

void* nodeGetValue(struct Node* node, int32_t type) {
		if (node == NULL) {
			printf("[Error] Node doesn't exist!\n");
			exit(1);
		}
		void* res;
		switch (type) {
			case INT:
				if (node->type == INT)
					res = InttoVoid(node->a);
				else if (node->type == FLOAT)
					res = InttoVoid((int)node->b);
				else if (node->type == BOOL)
					res = InttoVoid( node->c ? 1 : 0 );
				else {
					res = InttoVoid(0);
				}
				break;
			case FLOAT:
				if (node->type == INT)
					res = FloattoVoid((double)node->a);
				else if (node->type == FLOAT)
					res = FloattoVoid(node->b);
				else if (node->type == BOOL)
					res = FloattoVoid( node->c ? 1 : 0 );
				else {
					res = FloattoVoid(0);
				}
				break;
			case BOOL:
				if (node->type == INT)
					res = BooltoVoid(node->a != 0);
				else if (node->type == FLOAT)
					res = BooltoVoid(node->b != 0);
				else if (node->type == BOOL)
					res = BooltoVoid(node->c);
				else {
					res = BooltoVoid(false);
				}
				break;
			case STRING:
				if (node->type == STRING)
					res = StringtoVoid(node->d);
				else{
					res = StringtoVoid("");
				}
				break;
			default:
				printf("[Error] Edge Value Type Error!\n");
				exit(1);
				break;
		}
		return res;
}

int32_t printNode(struct Node * node) {
	if (node == NULL) {
		printf("(null)\n");
		return 0;
	}
	switch (node->type) {
		case 0:
			printf("node %d\n", node->a);
			break;
		case 1:
			printf("node %f\n", node->b);
			break;
		case 2:
			printf("node %s\n", node->c ? "true" : "false");
			break;
		case 3:
			printf("node %s\n", node->d);
			break;
		default:
			printf("node%3d\n", node->id);
			break;
	}
	return 0;
}


/************************************
	Edge Methods
************************************/

struct Edge createEdge(
	struct Node* sour,
	struct Node* dest,
	int32_t type,
	int32_t a,
	double b,
	bool c,
	char* d
) {

	struct Edge * newE = malloc(sizeof(struct Edge));
	newE->sour = sour;
	newE->dest = dest;
	newE->type = type;
	newE->a = a;
	newE->b = b;
	newE->c = c;
	newE->d = d;
	return (*newE);
}

struct Edge* createEdgeP(
	struct Node* sour,
	struct Node* dest,
	int32_t type,
	int32_t a,
	double b,
	bool c,
	char* d
) {
	// struct Edge e = {sour, dest, type, a, b, c, d};
	// return e;
	struct Edge * newE = malloc(sizeof(struct Edge));
	newE->sour = sour;
	newE->dest = dest;
	newE->type = type;
	newE->a = a;
	newE->b = b;
	newE->c = c;
	newE->d = d;
	return newE;
}

void* edgeGetValue(struct Edge* edge, int32_t type) {
	if (edge == NULL) {
		printf("[Error] Edge doesn't exist!\n");
		exit(1);
	}
	void* res;
	switch (type) {
		case INT:
			if (edge->type == INT)
				res = InttoVoid(edge->a);
			else if (edge->type == FLOAT)
				res = InttoVoid((int)edge->b);
			else if (edge->type == BOOL)
				res = InttoVoid( edge->c ? 1 : 0 );
			else {
				res = InttoVoid(0);
			}
			break;
		case FLOAT:
			if (edge->type == INT)
				res = FloattoVoid((double)edge->a);
			else if (edge->type == FLOAT)
				res = FloattoVoid(edge->b);
			else if (edge->type == BOOL)
				res = FloattoVoid( edge->c ? 1 : 0 );
			else {
				res = FloattoVoid(0);
			}
			break;
		case BOOL:
			if (edge->type == INT)
				res = BooltoVoid(edge->a != 0);
			else if (edge->type == FLOAT)
				res = BooltoVoid(edge->b != 0);
			else if (edge->type == BOOL)
				res = BooltoVoid(edge->c);
			else {
				res = BooltoVoid(false);
			}
			break;
		case STRING:
			if (edge->type == STRING)
				res = StringtoVoid(edge->d);
			else {
				res = StringtoVoid("");
			}
			break;
		default:
			printf("[Error] Edge Value Type Error!\n");
			exit(1);
			break;
	}
	return res;
}

int32_t printEdge(struct Edge * edge) {
	if (edge == NULL) {
		printf("(null)\n");
		return 0;
	}
	switch (edge->sour->type) {
		// case 0:
		// 	printf("edge %3d->%d\n$%3d", edge->sour->id, edge->a, edge->dest->id);
		// 	break;
		// case 1:
		// 	printf("edge %3d->%f\n$%3d", edge->sour->id, edge->b, edge->dest->id);
		// 	break;
		// case 2:
		// 	printf("edge %3d->%s\n$%3d", edge->sour->id, edge->c ? "true" : "false", edge->dest->id);
		// 	break;
		// case 3:
		// 	printf("edge %3d->%s\n$%3d", edge->sour->id, edge->d, edge->dest->id);
		// 	break;
		// default:
		// 	printf("edge %3d->node%3d\n", edge->sour->id, edge->dest->id);
		// 	break;
		case 0:
			printf("edge %d ->%d: %d\n", edge->sour->a, edge->dest->a, edge->a);
			break;
		case 1:
			printf("edge %f ->%f: %d\n", edge->sour->b, edge->dest->b, edge->a);
			break;
		case 2:
			printf("edge %s ->%s: %d\n", edge->sour->c? "true" : "false", edge->dest->c? "true" : "false", edge->a);
			break;
		case 3:
			printf("edge %s ->%s: %d\n", edge->sour->d, edge->dest->d, edge->a);
			break;
		default:
			printf("edge %3d ->%3d: 0\n", edge->sour->id, edge->dest->id);
			break;
	}
	return 0;
}

int32_t printEdgeValue(struct Edge * edge) {
	if (edge == NULL) {
		printf("(null)\n");
		return 0;
	}
	switch (edge->type) {
		case 0:
			printf("%d\n", edge->a);
			break;
		case 1:
			printf("%f\n", edge->b);
			break;
		case 2:
			printf("%s\n", edge->c ? "true" : "false");
			break;
		case 3:
			printf("%s\n", edge->d);
			break;
		default:
			printf("[Error] Unknown Edge Value Type!\n");
			exit(1);
			break;
	}
	return 0;
}

/************************************
	Graph Methods
************************************/

int32_t graphAddEdgeHelper(struct Graph* g, struct Edge e) {
	if (g == NULL) exit(1);
	int i;
	for (i=0; i < g->en; i++) {
		if (g->edges[i].sour == e.sour && g->edges[i].dest == e.dest) {
			g->edges[i] = e;
			return 0;
		}
	}
	g->edges[i] = e;
	g->en ++;
	return 0;
}

int32_t graphAddEdgeP( struct Graph* g, struct Node* sour, struct Node* dest, int32_t type, ...) {
	if (g == NULL) {
		printf("[Error] Graph doesn't exist!\n");
		exit(1);
	}
	if (sour == dest) return 0;
	if (g->en + 1 >= g->en_len) {
		printf("[Error] # Graph Edges reach the limit!\n");
		exit(1);
	}
	if (graphAddNode(g, sour) > 0) exit(1);
	if (graphAddNode(g, dest) > 0) exit(1);

	// Assign the Edge Value
	struct Edge e = createEdge(sour, dest, type, 0, 0, 0, NULL);
	va_list ap;
	va_start(ap, 1);
	void* tmp = va_arg(ap, void*);
	switch (type) {
		case INT:
			e.a = *((int*)tmp);	break;
		case FLOAT:
			e.b = *((double*)tmp);	break;
		case BOOL:
			e.c = *((bool*)tmp);	break;
		case STRING:
			e.d = ((char*)tmp);	break;
		default:
			break;
	}
  va_end(ap);

	int i;
	// Edges already exist in the graph
	for (i=0; i<g->en; i++) {
		if (g->edges[i].sour == sour && g->edges[i].dest == dest) {
			g->edges[i] = e;
			return 0;
		}
	}
	g->edges[i] = e;
	g->en++;
	return 0;
}

int32_t graphAddEdge(
	struct Graph* g,
	struct Node* sour,
	struct Node* dest,
	int32_t type,
	int32_t a,
	double b,
	bool c,
	char* d
) {
	if (g == NULL) {
		printf("[Error] Graph doesn't exist!\n");
		exit(1);
	}
	if (sour == dest) return 0;
	if (g->en + 1 >= g->en_len) {
		printf("[Error] # Graph Edges reach the limit!\n");
		exit(1);
	}
	if (graphAddNode(g, sour) > 0) exit(1);
	if (graphAddNode(g, dest) > 0) exit(1);
	int i;
	// Edges already exist in the graph
	for (i=0; i<g->en; i++) {
		if (g->edges[i].sour == sour && g->edges[i].dest == dest) {
			g->edges[i].type = type;
			g->edges[i].a = a;
			g->edges[i].b = b;
			g->edges[i].c = c;
			g->edges[i].d = d;
			return 0;
		}
	}
	struct Edge e = createEdge(sour, dest, type, a, b, c, d);
	g->edges[i] = e;
	g->en++;
	return 0;
}

bool graphEdgeExist(struct Graph* g, struct Node* sour, struct Node* dest) {
	if (g == NULL) {
		printf("[Error] Graph doesn't exist!\n");
		exit(1);
	}
	int i;
	for (i=0; i<g->en; i++) {
		if (g->edges[i].sour == sour && g->edges[i].dest == dest) {
			return true;
		}
	}
	return false;
}
struct Edge* graphGetEdge(struct Graph* g, struct Node* sour, struct Node* dest) {
	if (g == NULL) {
		printf("[Error] Graph doesn't exist!\n");
		exit(1);
	}
	int i;
	for (i=0; i<g->en; i++) {
		if (g->edges[i].sour == sour && g->edges[i].dest == dest) {
			return &g->edges[i];
		}
	}
	return NULL;
}

/*
	Split the graph into a list of graphs, in which all graphs are connected.
 */
struct List* splitGraph(struct Graph * gh) {
	struct List* l = createList(GRAPH);
	if (gh == NULL) return l;

	gh = copyGraph(gh);
	struct Node* root = gh->root;
	struct Graph* gh_tmp = NULL;
	int vn = gh->vn, en = gh->en, max_vn = gh->vn, max_en = gh->en;
	int i, j, k;
	struct List* queue = createList(NODE);
	struct Node* node = NULL, *node_tmp = NULL;

	while (vn > 0) {
		gh_tmp = createGraph();
		for (i=0; i<max_vn; i++) {
			if (gh->nodes[i] != NULL) break;
		}
		addList(queue, gh->nodes[i]);
		while (getListSize(queue) > 0) {
			node = (struct Node*) getList(queue, 0);
			removeList(queue, 0);
			graphAddNode(gh_tmp, node);
			for (k=0; k<max_vn; k++) {
				if (gh->nodes[k] == node) {
					gh->nodes[k] = NULL;
					vn--;
					break;
				}
			}
			if (k == max_vn) continue;
			for (j=0; j<max_en; j++) {
				if (gh->edges[j].type != -9 && gh->edges[j].sour == node) {
					node_tmp = gh->edges[j].dest;
				} else if (gh->edges[j].type != -9 && gh->edges[j].dest == node) {
					node_tmp = gh->edges[j].sour;
				} else {
					node_tmp = NULL;
				}
				if (node_tmp == NULL ) continue;
				addList(queue, node_tmp);
				graphAddEdgeHelper(gh_tmp, gh->edges[j]);
				gh->edges[j].type = -9;
			}
		}
		// Adjust the root to the original one
		bool hasRoot = false;
		for (i=0; i<gh_tmp->vn; i++) {
			if (gh_tmp->nodes[i] == root) {
				gh_tmp -> root = root;
				hasRoot = true;
				break;
			}
		}
		// Make sure the subgrpah with original root is the first in the list
		if (hasRoot && getListSize(l) > 0) {
			addList(l, (struct Graph*)getList(l, 0));
			setList(l, 0, gh_tmp);
		} else {
			addList(l, gh_tmp);
		}
	}
	free(gh);
	return l;
}

struct Graph* createGraph() {
	struct Graph* g = (struct Graph*) malloc( sizeof(struct Graph) );
	g->vn = 0;
	g->en = 0;
	g->vn_len = 32;
	g->en_len = 128;
	g->root = NULL;
	g->nodes = (struct Node**) malloc( sizeof(struct Node*) * 16 );
	g->edges = (struct Edge*) malloc( sizeof(struct Edge) * 64 );
	return g;
}
struct Graph* copyGraph(struct Graph* a) {
	if (a == NULL) return NULL;
	struct Graph* g = (struct Graph*) malloc( sizeof(struct Graph) );
	memcpy(g, a, sizeof(struct Graph));
	g->nodes = (struct Node**) malloc( sizeof(struct Node*) * a->vn_len );
	g->edges = (struct Edge*) malloc( sizeof(struct Edge) * a->en_len );
	int i;
	for (i=0; i<a->vn; i++) {
		g->nodes[i] = a->nodes[i];
	}
	struct Edge* tmp;
	for (i=0; i<a->en; i++) {
		tmp = (struct Edge*) malloc( sizeof(struct Edge) );
		memcpy(tmp, &a->edges[i], sizeof(struct Edge));
		g->edges[i] = *tmp;
	}
	return g;
}

struct Graph* mergeGraph(struct Graph* a, struct Graph* b) {
	if (b == NULL) return copyGraph(a);
	if (a == NULL) return copyGraph(b);

	struct Graph* gh = copyGraph(a);
	// Check whether two graph have shared nodes
	int i; int j;
	bool hasShared = false;
	for (i=0; i < a->vn; i++) {
		for (j=0; j < b->vn; j++) {
			if (a->nodes[i] == b->nodes[j]) {
				hasShared = true;
				break;
			}
		}
		if (hasShared) break;
	}
	if (!hasShared) return gh; // Return the copy of graph a

	for (i=0; i< b->vn; i++) {
		graphAddNode(gh, b->nodes[i]);
	}
	for (i=0; i< b->en; i++) {
		graphAddEdgeHelper(gh, b->edges[i]);
	}
	return gh;
}
struct Node* graphGetRoot(struct Graph* g) {
	if (g == NULL) {
		printf("[Error] Graph doesn't exist!\n");
		exit(1);
	}
	return g->root;
}
int32_t graphSetRoot(struct Graph* g, struct Node * root) {
	if (g == NULL) {
		printf("[Error] Graph doesn't exist!\n");
		exit(1);
	}
	if (root == NULL) {
		printf("[Error] Root node doesn't exist!\n");
		exit(1);
	}
	int i;
	for (i=0; i<g->vn; i++) {
		if (g->nodes[i] == root) {
			g->root = root;
			return 0;
		}
	}
	printf("[Error] Root doesn't exist in the graph!\n");
	exit(1);
}

struct List* subGraph(struct Graph* a, struct Graph* b) {
	if (a == NULL) {
		printf("[Error] Graph doesn't exist!\n");
		exit(1);
	}
	struct Graph* gh = copyGraph(a);
	if (b == NULL || b->en <= 0) {
		struct List* l = createList(GRAPH);
		addList(l, gh);
		return l;
	}
	int i, j, k;
	for (i = 0; i < b->en; i++) {
		struct Edge e = b->edges[i];
		for (j = 0; j < gh->en; j++) {
			if (gh->edges[j].sour == e.sour && gh->edges[j].dest == e.dest) {
				gh->edges[j] = gh->edges[gh->en-1];
				gh->en --;
				break;
			}
		}
	}
	return splitGraph(gh);
}

int32_t graphAddList(struct Graph* g, int direction, struct List * l, struct List * edges) {
	if (g == NULL || g->root == NULL || l == NULL) {
		printf("[Error] Graph or List doesn't exist!\n");
		exit(1);
	}
	int i, j, lsize = l->index, rsize = edges == NULL ? 0 : edges->index;
	if (lsize != rsize && rsize > 1) {
		printf("[Error] Edge List Not Compatible with Node/Graph List!\n");
		exit(1);
	}
	for (i=0; i<lsize; i++) {
		struct Node * node = NULL;
		if (l->list_type == GRAPH) {
			// Merge the graph
			struct Graph * gh_tmp = (struct Graph*)l->stored_data[i];
			node = gh_tmp->root;
			for (j=0; j< gh_tmp->vn; j++) {
				graphAddNode(g, gh_tmp->nodes[j]);
			}
			for (j=0; j< gh_tmp->en; j++) {
				graphAddEdgeHelper(g, gh_tmp->edges[j]);
			}
		} else if (l->list_type == NODE) {
			node = (struct Node*)l->stored_data[i];
		} else {
			printf("[Error] GraphAddList List Type doesn't supported!!\n");
			exit(1);
		}

		if (node == NULL) continue;
		if (edges != NULL && edges->index > 0) {
			int edgePos = edges->index == 1 ? 0 : i;
			switch (direction) {
				case RIGHT_LINK:
					graphAddEdgeP(g, g->root, node, edges->list_type, edges->stored_data[edgePos]); break;
				case LEFT_LINK:
					graphAddEdgeP(g, node, g->root, edges->list_type, edges->stored_data[edgePos]); break;
				case DOUBLE_LINK:
					graphAddEdgeP(g, g->root, node, edges->list_type, edges->stored_data[edgePos]);
					graphAddEdgeP(g, node, g->root, edges->list_type, edges->stored_data[edgePos]);
					break;
				default:
					break;
			}
		} else {
			switch (direction) {
				case RIGHT_LINK:
					graphAddEdgeP(g, g->root, node, -1, NULL); break;
				case LEFT_LINK:
					graphAddEdgeP(g, node, g->root, -1, NULL); break;
				case DOUBLE_LINK:
					graphAddEdgeP(g, g->root, node, -1, NULL);
					graphAddEdgeP(g, node, g->root, -1, NULL);
					break;
				default:
					break;
			}
		}
	}
	return 0;
}

int32_t graphAddNode(struct Graph* g, struct Node * node) {
	if (g == NULL) {
		printf("[Error] Graph doesn't exist!\n");
		exit(1);
	}
	if (g->vn + 1 >= g->vn_len) {
		printf("[Warning] # Graph Nodes reach the limit!\n");
		exit(1);
	}
	int i;
	// Nodes already exist in the graph
	for (i=0; i<g->vn; i++) {
		if (g->nodes[i] == node) return 0;
	}
	// Update the root if the graph is empty
	if (g->root == NULL) {
		g->root = node;
	}
	g->nodes[i] = node;
	g->vn++;
	return 0;
}

struct List* graphRemoveNode(struct Graph* gh, struct Node * node) {
	if (gh == NULL) {
		printf("[Error] Graph doesn't exist!\n");
		exit(1);
	}
	gh = copyGraph(gh);
	int i, j;
	// Remove Node
	for (i=0; i<gh->vn; i++) {
		if (gh->nodes[i] == node) {
			for (j=i; j<gh->vn-1; j++) {
				gh->nodes[j] = gh->nodes[j+1];
			}
			gh->nodes[j] = NULL;
			gh->vn--;
		}
	}
	if (gh->root == node) {
		gh->root = gh->vn == 0 ? NULL : gh->nodes[0];
	}
	// Remove Edges
	for (i=0, j=gh->en-1; i<=j;) {
		if (gh->edges[i].sour == node || gh->edges[i].dest == node) {
			gh->edges[i] = gh->edges[j];
			gh->en--;
			j--;
		} else {
			i++;
		}
	}
	return splitGraph(gh);
}

struct List* graphGetAllNodes(struct Graph* g) {
	if (g == NULL) {
		printf("[Error] Graph doesn't exist!\n");
		exit(1);
	}
	struct List* ret = createList(NODE);
	int i;
	for (i=0; i < g->vn; i++) {
		addList(ret, g->nodes[i]);
	}
	return ret;
}

int32_t graphNumOfNodes(struct Graph* g) {
	if (g == NULL) {
		printf("[Error] Graph doesn't exist!\n");
		exit(1);
	}
	return g->vn;
}

int32_t graphNumOfEdges(struct Graph* g) {
	if (g == NULL) {
		printf("[Error] Graph doesn't exist!\n");
		exit(1);
	}
	return g->en;
}

struct List* graphGetChildNodes(struct Graph* g, struct Node* rt) {
	if (g == NULL) {
		printf("[Error] Graph doesn't exist!\n");
		exit(1);
	}
	struct List* children = createList(NODE);
	if (rt == NULL) return children;
	int i;
	for (i=0; i< g->en; i++) {
		if (g->edges[i].sour == rt) {
			addList(children, g->edges[i].dest);
		}
	}
	return children;
}

bool containsNode(struct Graph* g, struct Node* n) {
	if (g == NULL) {
		printf("[Error] Graph doesn't exist!\n");
		exit(1);
	}
	int i;
	for (i = 0; i < g->vn; i++) {
		if (g->nodes[i] == n) {
			return true;
		}
	}
	return false;
}

int32_t printGraph(struct Graph* g) {
	if (g == NULL) {
		printf("(null)\n");
		return 0;
	}
	printf("--------------------------------------\n");
	int i;
	for (i=0; i<g->vn; i++) {
		printNode(g->nodes[i]);
	}
	for (i=0; i<g->en; i++) {
		printEdge(&g->edges[i]);
	}
	printf("--------------------------------------\n");
	return 0;
}

bool setAllUnvisited(struct Graph* g) {
	if (g == NULL) {
		printf("[Error] Graph doesn't exist!\n");
		exit(1);
	}
	int i;
	for (i = 0; i < g->vn; i++) {
		g->nodes[i]->visited = false;
	}
	return true;
}


struct List* dfs(struct Graph* g, struct Node* n) {
	bool flag = true;
	struct List* path = createList(NODE);
	if (g == NULL) {
		printf("[Error] Graph doesn't exist!\n");
		exit(1);
	} else if (!containsNode(g, n)) {
		printf("[Error] Graph doesn't contain source node!\n");
		exit(1);
	} else {
		//printf("-------------------------- DFS BEGIN -------------------------\n");
		//setAllUnvisited(g);
		struct List* lst = createList(NODE);
		addList(lst, n);
		while (getListSize(lst) != 0) {
			struct Node* tmp = (struct Node*) popList(lst);
			if (tmp->visited == true) {
				flag = false;
				continue;
			} else {
				tmp->visited = true;
				addList(path, tmp);
				struct List* childs = graphGetChildNodes(g, tmp);
				lst = concatList(lst, childs);
			}
		}
		//printf("-------------------------- DFS END -------------------------\n");
	}
	// if (!flag) {
	// 	printf("graph has cycle in it\n");
	// }
	// return flag;
	//printList(path);
	return path;
}

struct List* bfs(struct Graph* g, struct Node* n) {
	bool flag = true;
	struct List* path = createList(NODE);
	if (g == NULL) {
		printf("[Error] Graph doesn't exist!\n");
		exit(1);
	} else if (!containsNode(g, n)) {
		printf("[Error] Graph doesn't contain source node!\n");
		exit(1);
	} else {
		//printf("-------------------------- BFS BEGIN -------------------------\n");
		//setAllUnvisited(g);
		struct Queue* q = createQueue(NODE);
		pushBack(q, n);
		while (getQueueSize(q) != 0) {
			struct Node* tmp = (struct Node*) popFront(q);
			if (tmp->visited) {
				flag = false;
				continue;
			} else {
				tmp->visited = true;
				//printNode(tmp);
				addList(path, tmp);
				struct List* childs = graphGetChildNodes(g, tmp);
				concatList(q->lst, childs);
			}
		}
		//printf("-------------------------- BFS END -------------------------\n");
	}
	// if (!flag) {
	// 	printf("graph has cycle in it\n");
	// }
	// return flag;
	return path;
}

struct List* dijkstra(struct Graph* g, struct Node* sour, struct Node* dest) {
	setAllUnvisited(g);
	struct hashmap_map* dist = hashmap_new(NODE, INT);
	struct hashmap_map* prev = hashmap_new(NODE, NODE);

	hashmap_put(dist, sour, 0);

	struct List* set = graphGetAllNodes(g);
	int graphSize = graphNumOfNodes(g);
	struct minHeap* minH = initList(INT);
	// printHeap(minH);
	for (int i = 0; i < graphSize; i++) {
		struct Node* v = (struct Node*) getList(set, i);
		if (v->id != sour->id) {
			hashmap_put(dist, v, 10000);
			hashmap_put(prev, v, NULL);
		}
		//printf("%d\n", (*(int*)hashmap_get(dist, v)));
		int tmp = (*(int*)hashmap_get(dist, v));
		struct Edge* eg = createEdgeP(sour, v, 0, tmp, 0.0, 0, NULL);
		insertData(minH, eg);
	}
	while (getListSize(minH->array) > 0) {
		//printf("WhileStart---------------------------------------\n");
		//printHeap(minH);
		//printf("1---------------------------------------\n");
		struct Edge* uEdge = getMinValue(minH);
		//printHeap(minH);
		//printf("2---------------------------------------\n");
		struct Node* u = uEdge->dest;
		setVisited(u);
		if (u->id == dest->id) {
			break;
		}
		struct List* ngbrs = graphGetChildNodes(g, u);
		int ngbrsSize = getListSize(ngbrs);

		for (int i = 0; i < ngbrsSize; i++) {
			//printf("I: %d, ngbrSize: %d\n", i, ngbrsSize);
			struct Node* v = getList(ngbrs, i);
			if (isVisited(v)) {
				continue;
			}
			int alt = graphGetEdge(g, u, v)->a + (*(int*)hashmap_get(dist, u));
			//printf("weight: ******************************\n");
			//printf("alt: %d, dist of v : %d", alt, *(int*)(hashmap_get(dist, v)));
		    //printHeap(minH);
			if (alt < (*(int*)(hashmap_get(dist, v)))) {
				//printf("update\n");
				// hashmap_print(dist);
				// hashmap_print(prev);
				hashmap_remove(dist, v);
				hashmap_remove(prev, v);
				hashmap_put(dist, v, alt);
				hashmap_put(prev, v, u);
				// hashmap_print(dist);
				// hashmap_print(prev);
				struct Edge* newE = createEdgeP(sour, v, INT, alt, 0.0, 0, NULL);
				decreasePriority(minH, newE);
			}
		}
	}
	//printGraph(g);
	//hashmap_print(prev);
	//hashmap_print(dist);
	struct List* path = createList(NODE);
	addList(path, dest);
	struct Node* paren = (struct Node*)hashmap_get(prev, dest);
	while (paren->id != sour->id) {
		addList(path, paren);
		paren = (struct Node*)hashmap_get(prev, paren);
	}
	addList(path, sour);
	int pathSize = getListSize(path);
	struct List* path2 = createList(NODE);
	int i;
	for (i = pathSize - 1; i >= 0; i--) {
		struct Node* tmp = (struct Node*) popList(path);
		addList(path2, tmp);
	}

	setAllUnvisited(g);
	return path2;
}

// int main() {
// 	struct Queue* q = createQueue(INT);
// 	pushBack(q, 1);
// 	pushBack(q, 2);
// 	pushBack(q, 3);
// 	printQueue(q);
// 	popFront(q);
// 	printQueue(q);
// 	popFront(q);
// 	printQueue(q);
// 	pushBack(q, 4);
// 	printQueue(q);
// }

// int main() {
// 	printf("%f", (float)1 );
// }

// int main(){

//    	 struct minHeap* mp = initList(INT);
//     	struct Node* sour = createNode(1, 0, 12);
//     	struct Node* dest = createNode(2, 0, 3);
//     //printNode(sour);
//     //printNode(dest);
//     	struct Node* s = createNode(3, 0, 6);
//     	struct Node* d = createNode(4, 0, 4);
//     	struct Edge e = createEdge(sour, dest, 0, 6, 0.0, 0, NULL);
//     	struct Edge edg = createEdge(s, d, 0, 3, 0.0, 0, NULL);
//         struct Edge e2 = createEdge(s, dest, 0, 2, 0.0, 0, NULL);
//         struct Edge e3 = createEdge(sour, d, 0, 1, 0.0, 0, NULL);
//     	struct Edge* e_ptr = &(e);
//     	struct Edge* e_ptr2 = &(edg);
//         //printEdge(e_ptr);
// 	//printEdge(e_ptr2);
//     	insertData(mp, e_ptr);
//     	int size = getListSize(mp->array);
//     	printf("size: %d \n",size);
//     	printHeap(mp);
// 	printf("------ \n");
//     	insertData(mp, e_ptr2);
//     	int size2 = getListSize(mp->array);
//     	printf("size: %d \n",size2);
// 	printHeap(mp);
//     printf("------ \n");
//     	insertData(mp, &e2);
//     	int size3 = getListSize(mp->array);
//     	printf("size: %d \n",size3);
// 	printHeap(mp);
//     printf("------ \n");
//     	insertData(mp, &e3);
//     	int size4 = getListSize(mp->array);
//     	printf("size: %d \n",size4);
// 	printHeap(mp);
	
// 	printf("------ \n");
// 	struct Edge* data = getMinValue(mp);
// 	printEdge(data);
	
// }
