#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>

#ifndef _LIB_H_
#define _LIB_H_

void printBool(bool a);

/************************************
	Type Declaration
************************************/

#define INT 0
#define FLOAT 1
#define BOOL 2
#define STRING 3
#define NODE 4
#define GRAPH 5
#define LIST 6
#define DICT 7
#define EDGE 8

#define RIGHT_LINK 0
#define LEFT_LINK 1
#define DOUBLE_LINK 2

#define MAP_MISSING -3 
#define MAP_FULL -2 	
#define MAP_OMEM -1 	
#define MAP_OK 0 	

#define INITIAL_SIZE (256)
#define MAX_CHAIN_LENGTH (8)

struct List {

	int32_t index;
	int32_t size;
	void* *stored_data;
	int32_t list_type;
};


struct Node {
	int32_t id;
	int32_t type;
	int32_t a;
	double b;
	bool c;
	char* d;
	bool visited;
};

struct Edge {
	struct Node* sour;
	struct Node* dest;
	int32_t type;
	int32_t a;
	double b;
	bool c;
	char* d;
};

struct Graph {
	int32_t vn;
	int32_t en;
	int32_t vn_len;
 	int32_t en_len;
	struct Node* root;
	struct Node** nodes;
	struct Edge* edges;
};

struct Queue {
	struct List* lst;
};

struct minHeap {
    //int size;
    int32_t type;
    struct List* array;
};

struct hashmap_element{
	char* key;
	int in_use;
	void* data[2];
};

struct hashmap_map{
	int table_size;
	int size;
	int32_t keytype;
	int32_t valuetype;
	struct hashmap_element *data;
};

/************************************
	Hashmap Methods
************************************/

typedef int (*Func)(void*, void*, void*);

extern struct hashmap_map* hashmap_new(int32_t keytyp,int32_t valuetyp);
extern int hashmap_iterate(struct hashmap_map* m, Func f);
extern int hashmap_print(struct hashmap_map* m);
extern bool hashmap_haskey(struct hashmap_map* m,...);
extern struct List* hashmap_keys(struct hashmap_map* m);
extern struct hashmap_map* hashmap_put(struct hashmap_map* m,...);
extern void* hashmap_get(struct hashmap_map* m,...);
extern struct hashmap_map* hashmap_remove(struct hashmap_map* m,...);
extern void hashmap_free(struct hashmap_map* m);

extern int hashmap_length(struct hashmap_map* m);
extern int32_t hashmap_keytype(struct hashmap_map* m);
extern int32_t hashmap_valuetype(struct hashmap_map* m);

/************************************
	Heap Methods
************************************/

struct minHeap* initList(int32_t type);
void swap(struct List* list, int index1, int index2);
int eCompare(struct minHeap* hp, struct Edge* lchild, struct Edge* rchild);
void heapify(struct minHeap* hp, int size);
void insertData(struct minHeap* hp, struct Edge* data);
struct Edge* getMinValue(struct minHeap* hp);
int32_t printHeap(struct minHeap* hp);
void decreasePriority(struct minHeap* hp, struct Edge* e);

/************************************
	cast methods
************************************/

int32_t VoidtoInt(void* add);
double VoidtoFloat(void* add);
bool VoidtoBool(void* add);
char* VoidtoString(void* add);
struct Node* VoidtoNode(void* add);
struct Graph* VoidtoGraph(void* add);
struct Edge* VoidtoEdge (void* add);

void* InttoVoid(int32_t val);
void* FloattoVoid(double val);
void* BooltoVoid(bool val);
void* StringtoVoid(char* val);
void* NodetoVoid(struct Node* val);
void* GraphtoVoid(struct Graph* val);
void* EdgetoVoid(struct Edge* val);

bool isInt(int32_t d);
bool isFloat(int32_t d);
bool isBool(int32_t d);
bool isString(int32_t d);
bool isNode(int32_t d);
bool isEdge(int32_t d);
bool isGraph(int32_t d);

/************************************
	List
/************************************/

int32_t rangeHelper(int size, int index);
struct List* createList( int32_t type);
struct List* addListHelper( struct List * list, void* addData);
struct List* concatList(struct List* list1, struct List* list2);
struct List* pushList(struct List* list, ...);
struct List* addList(struct List* list, ...);
void* getList(struct List* list, int index);
void* popList(struct List* list);
int32_t setList(struct List* list, int index, ...);
int getListSize(struct List* list);
int32_t removeList(struct List* list, int index);
int32_t printList(struct List * list);
bool listContains(struct List *list, ...);
struct List* removeData(struct List* list, ...);

/************************************
	Queue Methods
************************************/
struct Queue* createQueue(int32_t type);
struct Queue* pushBack(struct Queue* q, ...);
void* popFront(struct Queue* q);
int getQueueSize(struct Queue* q);
int32_t printQueue(struct Queue* q);
/************************************
	Node Methods
************************************/

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

void* nodeGetValue(struct Node* node, int32_t type);
int32_t printNode(struct Node * node);
bool setVisited(struct Node* node);
bool isVisited(struct Node* node);
/************************************
	Edge Methods
************************************/

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

int32_t printEdge(struct Edge * edge);
int32_t printEdgeValue(struct Edge * edge);
void* edgeGetValue(struct Edge* edge, int32_t type);

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

struct Graph* createGraph();
struct Graph* copyGraph(struct Graph* a);
struct Graph* mergeGraph(struct Graph* a, struct Graph* b);
struct List* subGraph(struct Graph* a, struct Graph* b);
struct Node* graphGetRoot(struct Graph* g);
int32_t graphSetRoot(struct Graph* g, struct Node * root);
int32_t graphAddList(struct Graph* g, int direction, struct List * l, struct List * edges);
int32_t graphAddNode(struct Graph* g, struct Node * node);
struct List* graphGetAllNodes(struct Graph* g);
struct List* graphRemoveNode(struct Graph* g, struct Node * node);
int32_t graphAddEdgeP( struct Graph* g, struct Node* sour, struct Node* dest, int32_t type, ...);
int32_t graphAddEdge(
	struct Graph* g,
	struct Node* sour,
	struct Node* dest,
	int32_t type,
	int32_t a,
	double b,
	bool c,
	char* d
);
bool graphEdgeExist(struct Graph* g, struct Node* sour, struct Node* dest);
struct Edge* graphGetEdge(struct Graph* g, struct Node* sour, struct Node* dest);
int32_t graphNumOfNodes(struct Graph* g);
int32_t graphNumOfEdges(struct Graph* g);
struct List* graphGetChildNodes(struct Graph* g, struct Node* rt);
int32_t printGraph(struct Graph* g);
bool setAllUnvisited(struct Graph* g);
struct List* dfs(struct Graph* g, struct Node* n);
struct List* bfs(struct Graph* g, struct Node* n);
bool containsNode(struct Graph* g, struct Node* n);
struct List* dijkstra(struct Graph* g, struct Node* sour, struct Node* dest);
#endif /* #ifndef _LIB_H_ */
