#include "liss_caduceus_set.h"

extern int strcmp (__const char *__s1, __const char *__s2);

// creates a new set with the values that are in array
set newSet(sElem array[], int dim)
{
	int i;
	set s = NULL, aux = NULL, new = NULL;

	if (dim > 0)
		s = newNodeSet(array[0]);
	
	for (i=1; i<dim; i++)
	{
		new = newNodeSet(array[i]);
		aux = addElemSet(s);

		if (aux->left == NULL)
			aux->left = new;
		else
			aux->right = new;
	}

	return s;
}

// returns a poiter to the node in set s, where the next value will be added
set addElemSet(set s)
{
	set res = NULL;
	
	if(isOperator(s->value))
	{
		if(s->left == NULL)
			res = s;
		else
		{
			res = addElemSet(s->left);
			if(res == NULL)
			{
				if(s->right == NULL)
					res = s;
				else
					res = addElemSet(s->right);
			}
		}
	}

	return res;
}

// checks if op is an operator
int isOperator(char * op)
{
	int res = 0;

	// strcmp returns 0 when the strings are equal
	if (
		!strcmp(op, "&&") ||
		!strcmp(op, "||") ||
		!strcmp(op, ">")  ||
		!strcmp(op, "<")  ||
		!strcmp(op, ">=") ||
		!strcmp(op, "<=") ||
		!strcmp(op, "==") ||
		!strcmp(op, "!=")
	)
		res = 1;

	return res;
}

// creates a new node with value=var, left=null and right=null and returns a pointer to the node
set newNodeSet(sElem val)
{
	set tnode = malloc(sizeof(tNode));

	tnode -> value = val;
	tnode -> left = NULL;
	tnode -> right = NULL;

	return tnode;
}

// creates a new set s_dest equal to set s_orig
void assignSet(set s_orig, set * s_dest)
{
	cleanSet(s_dest);
	*s_dest = duplicateSet(s_orig);
}

// returns a new set equal to set s
set duplicateSet(set s)
{
	set new = NULL;
	
	if(s != NULL)
	{
		new = newNodeSet(s->value);
		new->left = duplicateSet(s->left);
		new->right = duplicateSet(s->right);
	}

	return new;
}

// cleans a Set
void cleanSet(set * s)
{
	if(*s != NULL)
	{
		cleanSet(&( (*s)->left ));
		cleanSet(&( (*s)->right ));
		free(*s);
		*s = NULL;
	}
}

// checks if element val belongs to set s
int isInSet(int val, set s)
{
	int res = 0;

	if (s != NULL)
	{
		if( isOperator(s->value) )
			res = calcBoolSet(isInSet(val, s->left), s->value, isInSet(val, s->right));
		else
		// strcmp returns 0 when the strings are equal
			if(!strcmp(s->value, "x"))
				res = val;
			else
				res = atoi(s->value);
	}

	return res;
}

// returns the logic value of operation op between values val1 and val2
int calcBoolSet(int val1, char * op, int val2)
{
	int res;

	// strcmp returns 0 when the strings are equal
		if (!strcmp(op, "&&")) res = (val1 && val2);
	else 	if (!strcmp(op, "||")) res = (val1 || val2);
	else 	if (!strcmp(op, "<") ) res = (val1 < val2);
	else 	if (!strcmp(op, ">") ) res = (val1 > val2);
	else 	if (!strcmp(op, "<=")) res = (val1 <= val2);
	else 	if (!strcmp(op, ">=")) res = (val1 >= val2);
	else 	if (!strcmp(op, "==")) res = (val1 == val2);
	else 	if (!strcmp(op, "!=")) res = (val1 != val2);

	return res;
}

// intercepts two sets
set interceptionSet(set s1, set s2)
{
	set new = NULL, aux = newNodeSet("&&");

	aux->left = s1;
	aux->right = s2;

	new = duplicateSet(aux);
	free(aux);

	return new;
}

// unifies two sets
set unionSet(set s1, set s2)
{
	set new = NULL, aux = newNodeSet("||");

	aux->left = s1;
	aux->right = s2;

	new = duplicateSet(aux);
	free(aux);

	return new;
}
