#include "tNode.h"

#define S_FALSE 0
#define S_TRUE 1
#define S_DONTCARE 2

#define S_LEFT 0
#define S_MID 1
#define S_RIGHT 2

tNode * tRoot;

void tNode::add (STable * table)
{
	Symbol * smb;
	tNode * ptr = this;
	
	
	while (true)
	{
		smb = table->get();
		if (smb == NULL) break;
		
		if (smb->valid)
		{
			{
				if (smb->value == 1)
				{
					if (ptr->right == NULL)
					{
						ptr->right = new tNode();
					}
					ptr = ptr->right;
				}
				else
				{
					if (ptr->left == NULL)
					{
						ptr->left = new tNode();
					}
					ptr = ptr->left;
				}
			}
		}
		else
		{
			if (ptr->mid == NULL)
			{
				ptr->mid = new tNode();
			}
			ptr = ptr->mid;
		}
	}
}

void tNode::expand (unsigned int depth)
{
	if (depth == treeArray->symbNames->count)
	{
		if (mid != NULL)
		{
			if (left == NULL)
			{
				left = new tNode();
			}
			if (right == NULL)
			{
				right = new tNode();
			}
			/*delete mid;
			mid = NULL;*/
			return;
		}
		
		if ((left != NULL) && (right != NULL))
		{
			mid = new tNode();
			return;
		}
		return;
	}
	else
	{
		depth++;
		if (left != NULL) {left->expand(depth);}
		if (mid != NULL) {mid->expand(depth);}
		if (right != NULL) {right->expand(depth);}
		return;
	}
}


void tNode::reduce (unsigned int depth)
{
	if (depth == treeArray->symbNames->count)
	{
		if (mid != NULL)
		{
			if (left != NULL)
			{
				delete left;
				left = NULL;
			}
			if (right != NULL)
			{
				delete right;
				right = NULL;
			}
			return;
		}
		
		if ((left != NULL) && (right != NULL))
		{
			delete left;
			left = NULL;
			delete right;
			right = NULL;
			mid = new tNode();
			return;
		}
		return;
	}
	else
	{
		depth++;
		if (left != NULL) {left->reduce(depth);}
		if (mid != NULL) {mid->reduce(depth);}
		if (right != NULL) {right->reduce(depth);}
		return;
	}
}

tNode * tNode::switchroot ()
{
	tNode * newroot = NULL;
	
	if (left != NULL) {left->addnode(1,S_LEFT);}
	if (mid != NULL) {mid->addnode(1,S_MID);}
	if (right != NULL) {right->addnode(1,S_RIGHT);}
	
	newroot = join(left,mid);
	newroot = join(newroot,right);
	
	left = mid = right = NULL;
	if (newroot != NULL)
	{
		delete this;
		return newroot;
	}
	return this;
}

tNode * tNode::join (tNode * l, tNode * r)
{
	if (r == NULL) return l;
	if (l == NULL)
	{
		l = r;
	}
	else
	{
		l->left = join(l->left,r->left);
		l->mid = join(l->mid,r->mid);
		l->right = join(l->right,r->right);
		r->left = r->mid = r->right = NULL;
		delete r;
	}
	return l;
}

void tNode::addnode(unsigned int depth, int type)
{
	//pokud je list
	if (depth == (treeArray->symbNames->count))
	{
		switch (type)
		{
			case S_LEFT:
			{
				left = new tNode();
				break;
			}
			case S_MID:
			{
				mid = new tNode();
				break;
			}
			case S_RIGHT:
			{
				right = new tNode();
				break;
			}
		
		}
		return;
	}
	
	depth++;
	if (left != NULL) {left->addnode(depth,type);}
	if (mid != NULL) {mid->addnode(depth,type);}
	if (right != NULL) {right->addnode(depth,type);}
	return;
}

void tNode::print (ostream& out)
{
	if (left != NULL) {out<<"0"; left->print(out); }
	if (mid != NULL) {out<<"-"; mid->print(out); }  
	if (right != NULL) {out<<"1"; right->print(out); }
}

Node * tNode::transform (Node * ptr, tNode * tptr, unsigned int depth)
{
	Node * newnode = NULL;
	Node * parent = NULL;
	tNode * ntnode = NULL;
	Symbol * smb = NULL;
	tNode * tleaf = NULL;
	
	//pokud je to list
	if (depth == (treeArray->symbNames->count))
	{
		treeArray->terms++;
		if (ptr == NULL) {ptr = new VectNode(1,1);}
		
		if (absorbtion)
		{
			
			if  (tRoot->contains(tptr, false, 0))
			{
				delete ptr;
				ptr = new VectNode(0,1);
				treeArray->terms--;
			}	
			/*else
			{
				int dp = tRoot->absorb(tptr,0);
				//cout<<" "<<dp<<" ";
				if ( dp != 0 )
				{
					tptr->change(dp-1);
					delete ptr;
					ptr = tptr->transform(NULL, NULL, 0);
				}
			}*/
			
			
		}
		delete tptr;
		return ptr;
	}
	
	smb = treeArray->symbNames->find(depth);
	depth++;
	
	if (left != NULL)
	{
		if (ptr != NULL ) 
		{
			newnode = new BNode(ptr->copy(), new UNode (new IdentNode(smb->name), S_NOT), S_AND);
		}
		else newnode = new UNode (new IdentNode(smb->name), S_NOT);
		
		
		if (tptr != NULL ) ntnode = tptr->copy(&tleaf);
		else 
		{
			ntnode = new tNode();
			tleaf = ntnode;
		}
		tleaf->left = new tNode(); 
		
		if (parent == NULL)
		{
			parent = left->transform(newnode,ntnode,depth);
		}
		else parent = new BNode(parent, left->transform(newnode,ntnode,depth) , S_OR);
		
	}
	
	if (mid != NULL)
	{
		if (ptr != NULL)
		{
			newnode = ptr->copy();
		}
		else newnode = NULL;
		
		
		if (tptr != NULL ) ntnode = tptr->copy(&tleaf);
		else 
		{
			ntnode = new tNode();
			tleaf = ntnode;
		}
		tleaf->mid = new tNode(); 
		
		if (parent == NULL )
		{
			parent = mid->transform(newnode,ntnode,depth);
		}
		else parent = new BNode(parent, mid->transform(newnode,ntnode,depth) , S_OR);
	}
	
	if (right != NULL)
	{
		if (ptr != NULL)
		{	
			newnode = new BNode(ptr->copy(), new IdentNode(smb->name), S_AND);
		}
		else newnode = new IdentNode(smb->name);
		
		
		if (tptr != NULL ) ntnode = tptr->copy(&tleaf);
		else 
		{
			ntnode = new tNode();
			tleaf = ntnode;
		}
		tleaf->right = new tNode(); 
		
		if (parent == NULL )
		{
			parent = right->transform(newnode,ntnode,depth);
		}
		else parent = new BNode(parent, right->transform(newnode,ntnode,depth) , S_OR);
	}
	
	
	delete ptr;
	delete tptr;
	//if (parent == NULL) {parent = new VectNode(1,1);} //nemelo by nastat
	return parent;
}

bool tNode::contains(tNode * tptr, bool diff, unsigned int depth)
{
	tNode * ntptr = NULL;
	
	//kdyz je list
	if (depth == (treeArray->symbNames->count)) return diff;
	
	depth++;
	
	if ( (tptr->left != NULL) && (left != NULL))
	{
		ntptr = tptr->left;
		if ( left->contains(ntptr, diff, depth) ) return true;
	}
	
	if ( (tptr->mid != NULL) && (mid != NULL))
	{
		ntptr = tptr->mid;
		if ( mid->contains(ntptr, diff, depth) ) return true;
	}
	
	if ( (tptr->right != NULL) && (right != NULL))
	{
		ntptr = tptr->right;
		if ( right->contains(ntptr, diff, depth) ) return true;
	}
	
	if ( (tptr->left != NULL) && (mid != NULL))
	{
		diff = true;
		ntptr = tptr->left;
		if ( mid->contains(ntptr, diff, depth) ) return true;
	}
	
	if ( (tptr->right != NULL) && (mid != NULL))
	{
		diff = true; 
		ntptr = tptr->right;
		if ( mid->contains(ntptr, diff, depth) ) return true;
	}
	
	return false;
}

unsigned int tNode::absorb(tNode * tptr, unsigned int depth)
{
	tNode * ntptr = NULL;
	int ret;
	
	//kdyz je list
	if (depth == (treeArray->symbNames->count)) return 0;
	
	depth++;
	
	if ( (tptr->left != NULL) && (left != NULL))
	{
		ntptr = tptr->left;
		ret = left->absorb(ntptr, depth);
		if ( ret ) return ret;
	}
	
	if ( (tptr->mid != NULL) && (mid != NULL))
	{
		ntptr = tptr->mid;
		ret = mid->absorb(ntptr, depth);
		if ( ret ) return ret;
	}
	
	if ( (tptr->right != NULL) && (right != NULL))
	{
		ntptr = tptr->right;
		ret = right->absorb(ntptr, depth);
		if ( ret ) return ret;
	}
	
	if ( (tptr->left != NULL) && (mid != NULL))
	{
		ntptr = tptr->left;
		ret = mid->absorb(ntptr, depth);
		if ( ret ) return ret;
	}
	
	if ( (tptr->right != NULL) && (mid != NULL))
	{ 
		ntptr = tptr->right;
		ret = mid->absorb(ntptr, depth);
		if ( ret ) return ret;
	}
	
	
	
	
	if ( (tptr->left != NULL) )
	{
		ntptr = tptr->left;
	
		if (right != NULL)
		{
			if (right->contains(ntptr, true, depth)) return depth;
		}
	}
	
	if ( (tptr->right != NULL) )
	{
		ntptr = tptr->right;
		
		if (left != NULL)
		{
			if (left->contains(ntptr, true, depth)) return depth;
		}
		
	}
	
	return 0;
}

void tNode::change(unsigned int depth)
{
	unsigned int actdp = 0;
	tNode * tptr = this;
	
	while (true)
	{
		if (depth == actdp)
		{
			
			if (tptr->left != NULL)
			{
				tptr->mid = tptr->left;
				tptr->left = NULL;
			}
			
			if (tptr->right != NULL)
			{
				
				tptr->mid = tptr->right;
				tptr->right = NULL;
			}
			
			return;
		}
		
		actdp++;
		if (tptr->left != NULL) {tptr = tptr->left;}
		else 
		{
			if (tptr->mid != NULL) {tptr = tptr->mid;}
			else if (tptr->right != NULL) {tptr = tptr->right;}
		}
	}
	
}

tNode * tNode::copy(tNode ** tptr)
{
	tNode * ptr = new tNode();
	if (left != NULL) ptr->left = left->copy(tptr);
	if (mid != NULL) ptr->mid = mid->copy(tptr);
	if (right != NULL) ptr->right = right->copy(tptr);
	if ((left == NULL) && (mid == NULL) && (right == NULL)) *tptr = ptr; 
	return ptr;
}

tNode::tNode(): left(NULL), mid(NULL), right(NULL) {}

tNode::~tNode()
{
	if (left!= NULL) delete left;
	if (mid != NULL) delete mid;
	if (right!= NULL) delete right;
}
