#include <stdio.h>
#include <stdlib.h>
#include<string.h>
FILE *ifpr;
#define LH +1
#define EH 0
#define RH -1

bool fileOpen = false;
bool equal = false;
struct customer 
{
public:
	int id;
	double balance;
	char name[10], surname[10], idaccount[10];
	customer *left, *right;
	int bal;
	customer(int x=0) 
	{
		id=x;
		balance=x;
		left = right = NULL;
		bal = EH;
	}
};


class AvlTree 
{
private:
	int count;//,level;
	customer *root;
	void erase(customer *s);
	void preorder(customer *s);
	void chkorder(customer *s);
	void inorder(customer* s);
	void preload (customer* s);
	customer* createaccount(customer* s, customer* ptr, bool& taller);
	customer* leftBalance(customer *s, bool& taller);
	customer* rightBalance(customer *s, bool& taller);
	customer* rotateLeft(customer* s);
	customer* rotateRight(customer* s);
	customer* _delete(customer* root,char idacc[10], bool& shorter, bool& success);
	customer* dltLeftBalance (customer  *root, bool&  smaller);
	customer* dltRightBalance (customer *root, bool& shorter);
	customer* update(customer* root,char idacc[10], bool& success);
	customer* printinfo(customer *root, char idacc[10], bool& sucess);
public:
	AvlTree() {root = NULL;count =0;}
	~AvlTree() {erase(root);}
	bool createaccount(char[10],char[10],char[10], double, int);
	bool remove(char [10]);
	bool update(char [10]);
	bool printinfo(char [10]);
	void inorder();
	void preorder();
	void chkorder();
	void preload();
	


};

void menu()
{

	AvlTree A;
	char n[10],sn[10],idc[10];
	int id,c;
	double balance;
	bool repeat=true,fileEmpty=true;
	ifpr = fopen("bank.txt", "r+");/*here we have to change r with ????*/ /* error*/
	fileOpen=true;
	fscanf (ifpr,"%s%s%s%f%d",n,sn,idc,&balance,&id);
	while( !feof(ifpr) )
	{
		fileEmpty=false;
		A.createaccount(n,sn,idc,balance,id);
		fscanf (ifpr,"%s%s%s%f%d",n,sn,idc,&balance,&id);
	}
	if (!fileEmpty)
		A.createaccount(n,sn,idc,balance,id);
	fclose(ifpr);
	fileOpen=false;
  
	while (repeat)
	{
		printf("\n\nCHOOSE FROM THE MENU(1-5)\n");
		printf("\t1- CREATE ACCOUNTS.\n\t2- UPDATE ACCOUNTS.\n\t3- PRINT ACCOUNTS.\n\t4- DELETE ACCOUNTS\n\t5-EXIT\nYOUR CHOICE:  ");
		scanf("%d", &c);
		switch(c)
		{
			case 1:
				
				printf ("\nEnter Name:\t");
				scanf ("%s",n);
				printf ("\nEnter Surname:\t");
				scanf ("%s",sn);
				printf ("\nEnter id account:\t");
				scanf ("%s",idc);
				printf ("\nEnter Balance:\t");
				scanf ("%f",&balance);
				printf ("\nEnter id number:\t");
				scanf ("%d",&id);
				A.createaccount(n,sn,idc,balance,id);
				break;
			case 2:
				printf("enter the id of the customer u want to update its information:\n");
				scanf("%s", idc);
				A.update(idc);
				break;
			case 3:
				printf("enter the id of the customer to get information:\n");
				scanf("%s", idc);
				A.printinfo(idc);
				break;
			case 4:
				printf("enter the idaccount of the customer u want to delete:\n");
				scanf("%s", idc);
				if(A.remove (idc))
					printf ("\nDelete customer done successfully\n");
				else
					printf ("\nCustomer not available\n");
				break;
			case 5:
				A.preload();
				printf("\nTHANKS BYE\n\n");
				repeat=false;
				break;
		}
	}
}



int main()
{
	menu();
	return 0;
}

bool AvlTree::createaccount(char name[10],char surname[10],char idaccount[10], double balance, int id)
{
	equal = false;
	customer *ptr;
	bool taller;
	/*we need to check for dublicate data, before inserting into the customertree*/
	ptr=new customer;
	strcpy(ptr->name, name);
	strcpy(ptr->surname, surname);
	strcpy(ptr->idaccount, idaccount);
	ptr->balance = balance;
	ptr->id = id;
	if( root = createaccount( root, ptr, taller ) )
	{
		if((!fileOpen)&&(!equal))
				printf ("\n Customer Added successfully\n");
		return true;
	}
	return false;
}

void AvlTree::inorder()		{inorder(root);}

void AvlTree::preorder()	{preorder(root);}

void AvlTree::preload()
{
	//if(getcount()==0) return;
	ifpr = fopen("bank.txt","w");/*here we have to change w with something*/
	fileOpen=true;   /*error*/
	preload(root);
	fclose(ifpr);
	fileOpen=false;
}

void AvlTree::chkorder() 
{//	level = 0;
		chkorder(root);
}

void AvlTree::erase(customer *s) 
{
	if ( s != NULL) {		
		erase(s->left);
		erase(s->right);
		delete s;
	}
}

void AvlTree::preorder(customer *s) 
{
	if ( s != NULL) {
		printf("%s \n", s->idaccount);
		preorder(s->left);
		preorder(s->right);
	}
}

void AvlTree::preload(customer *s) 
{
	if ( s != NULL) {
		fprintf (ifpr,"%s %s %s %f %d\n",s->name,s->surname,s->idaccount,s->balance,s->id);
		preload(s->left);
		preload(s->right);
	}
}

void AvlTree::chkorder(customer *s) {
		static level;
		level++;
		if ( s != NULL) {
			for (int i=0; i < level;i++)
				printf("\t");
			printf("%d. %s\n",level,s->idaccount);
			chkorder(s->left);
			chkorder(s->right);
		}
		level--;
	}

void AvlTree::inorder(customer* s) {
		if ( s != NULL) {
			inorder(s->left);
			printf("%s  ",s->idaccount);
			inorder(s->right);
		}
	}

customer* AvlTree::createaccount(customer* s, customer* ptr, bool& taller) {
	/*ptr points to the new customer which will be inserted
	s initially will be pointing to the root, at each recursive call  
	it will point to the root of the subtreetaller is a boolean 
	operator indicating if the subtree height has increased, 
	false indicating the subtree has increased in size*/
	if(!s) 
	{
		s = ptr;
		taller = true;
		return s;
	}//if root is empty

	else if (strcmp(ptr->idaccount,s->idaccount)<0) 
	{
		s->left = createaccount(s->left, ptr, taller);
		if (taller) //left subtree is taller, so we have to check wether it is still AVL
			switch(s->bal) {
				case LH: //Was left high, so we need to rotate
					s = leftBalance(s, taller);
					break;
				case EH://was balanced, now it is left-high
					s->bal = LH;
					break;
				case RH: //was right high, now it is even high
					s->bal = EH;
					taller = false;
					break;
		}//switch
	}//if less
	else if(strcmp(ptr->idaccount, s->idaccount)==0){
		equal=true;
		printf ("\nCustomer NOT ADDED, The id is used, try again\n");
		taller=false; 
	}
	else {
			//new customer account number > current customer account number
			s->right = createaccount(s->right, ptr, taller);
				if (taller) 
					//right sub tree is taller
					switch(s->bal) {

						case LH: //Was left high, now EH
							s->bal = EH;
							taller = false;
							break;

						case EH: //was balanced, now RH
							s->bal = RH;
							break;

						case RH: //was right high, rotate
							s = rightBalance(s, taller);
							break;
					}//switch
				}//else data > s
		return s;
	}//the private create account member function

customer* AvlTree::leftBalance(customer *s, bool& taller) {
		customer *rightTree;
		customer *leftTree;

		leftTree = s->left;
		switch(leftTree->bal) {

			case LH: //Left high, Rotate Right
				s->bal = EH;
				leftTree->bal = EH;
				//rotate right
				s = rotateRight(s);
				taller = false;
				break;

			case EH: //This is an error
				printf("\n\n\aError in left Balance\n\n\n");
				exit(100);

			case RH: //Right high requires double rotation
				//first left, then right
				rightTree = leftTree->right;

				switch(rightTree->bal) {
					
					case LH:
						s->bal = RH;
						leftTree->bal = EH;
						break;
					
					case EH:
						s->bal = EH;
						leftTree->bal = EH;
						break;

					case RH:
						s->bal = EH;
						leftTree->bal = LH;
						break;

				}//switch rightTree
				
				rightTree->bal = EH;

				//rotate Left
				s->left = rotateLeft(leftTree);

				//rotate Right
				s = rotateRight(s);
					taller = false;
		}//switch leftTree

		return s;
	}//leftBalance

customer* AvlTree::rightBalance(customer *s, bool& taller) {
		
		customer *rightTree;
		customer *leftTree;

		rightTree = s->right;
		switch(rightTree->bal) {

		case LH: //Left high, requires double rotation
				//first right, then left
				leftTree= rightTree->left;
				switch(leftTree->bal){
					case LH:
						s->bal = EH;
						rightTree->bal = RH;
						break;
					case EH:
						s->bal = EH;
						rightTree->bal = EH;
						break;
					case RH:
						s->bal = LH;
						rightTree->bal = EH;
						break;
				}//switch leftTree
				leftTree->bal = EH;
				//rotateright
				s->right = rotateRight(rightTree);
				//rotateLeft
				s = rotateLeft(s);
				taller = false;
				break;
			case EH://This is an error
				printf("\n\n\aError in right Balance\n\n\n");
				exit(100);
			case RH://Right high, Rotate left
				s->bal = EH;
				rightTree->bal = EH;
				//rotate left
				s = rotateLeft(s);
				taller = false;
				break;

		}//switch rightTree*/
		return s;

	}//rightBalance

customer* AvlTree::rotateLeft(customer* s) {
		customer* tmp;

		tmp = s->right;
		s->right = tmp->left;
		tmp->left = s;

		return tmp;
	}//rotateLeft

customer* AvlTree::rotateRight(customer* s) {
		customer* tmp;

		tmp = s->left;
		s->left = tmp->right;
		tmp->right = s;

		return tmp;
	}//rotateRight

bool  AvlTree::remove(char x[10])
// -----------------------------------------------------------------
// Purpose: This function deletes a customer with all its information
// from the AVL tree and rebalances it if necessary. This functions 
// true if a customer has been deleted, otherwise false.
// -----------------------------------------------------------------
{

// The following are two objects that are shared through the 
// recursive execution of deleting a customer.
	bool shorter;
    bool success;
    customer *newRoot;
// Delete a customer within the tree having the value of dltKey.
      newRoot = _delete (root, x, shorter, success);
// If the customer was deleted, the root of the tree may have changed
// requiring that tree be assigned a new address for a root.
      if (success)
      {
         root = newRoot;
         count--;
		 return success;
	  }
	  else
	  {
		  //printf("SORRY!\nTHE DELETION FAILED\n");
		  return success;
	  }

}

 

 

customer*  AvlTree::_delete(customer* s,char idacc[10], bool& shorter, bool& success)

// -----------------------------------------------------------------
// Purpose: This function deletes a customer from the tree and rebalance
// it if necessary. Returns true if deleted, false if not found.
// -----------------------------------------------------------------

{

// The following are local pointers needed for deletion
// and interchanging of key and data values.

      customer *dltPtr;
	  customer *exchPtr;
	  customer *news;
	  
	  
	if (!s)// If no node to delete, return null.
     {
		  shorter = false;
          success = false;
		  printf ("\nSorry!\n\tThere is no customer");
          return NULL;
     }

	if (strcmp(idacc ,s->idaccount)<0)// Test if need is to delete a customer to the left of the s.
	  {
         s->left = _delete (s->left, idacc, shorter, success);
		 if (shorter)// Rebalance the tree if the tree has become shorter.
			s = dltRightBalance (s, shorter);
	 }

	else if (strcmp(idacc, s->idaccount)>0)// Test if need is to delete a customer to the right of the s.
     {
         s->right = _delete (s->right, idacc, shorter, success);
         if (shorter)// Rebalnce the tree if the tree has become shorter.
         s = dltLeftBalance (s, shorter);
     }

    else//Otherwise the node having the key has been found.
     {
         dltPtr  = s;
		 if (!s->right)//Check if the node to be deleted has no right child.
			{
			 news  = s->left;
			 success  = true;
			 shorter  = true;
			 delete (dltPtr);
			 return news;
			}
         
		 else if (!s->left)// Check if the node to be deleted has no left child.
		 {
			 news  = s->right;
			 success  = true;
			 shorter  = true;
			 delete (dltPtr);
			 return news;
		 }
		 
		 else// Otherwise node to be deleted has two children.
		 {
			 // Find the right most node from the left child of the
			 // node ready to be deleted.
			exchPtr = s->left;
			while (exchPtr->right)
				exchPtr = exchPtr->right;
			// Exchange data between the right most node and the
			// node to be deleted.
			strcmp(s->idaccount ,exchPtr->idaccount);
			// Delete the leaf node having the key given by exchPtr -> data.key.
			s->left = _delete (s->left, exchPtr->idaccount, shorter, success);
			if (shorter)// Rebalance the tree if it has become shorter.
				s = dltRightBalance (s, shorter);
		 }
	}
	return s;
}

customer*  AvlTree::dltLeftBalance (customer  *s, bool&  shorter)

// -----------------------------------------------------------------
// Purpose: This function rebalances the AVL based upon the
//          assumption that the tree is shorter after a deletion
//          on the right of the s. This function will adjust
//          the balance factors and rotate the tree to the right
//          if it is necessary. Function returns a potential
//          new s.
// -----------------------------------------------------------------
{
// The following are local pointers needed to rebalance the tree.
      customer  *rightTree;
      customer *leftTree;
	  switch (s->bal)// Determine if the s node is LH, EH, or RH.
	  {
		  
	     case RH: // s was RH - now becomes EH.
			 s->bal   = EH;
			 break;
			 
		 case EH: // s was EH - now becomes LH.
			 s->bal  = LH;
			 shorter    = false;
			 break;
			 	 
		 case LH: // s was LH - remains LH. Requires rotate right.
			 leftTree = s->left;
			 switch (leftTree->bal)
			 {
			 case LH:
			 case EH: // Perform a single rotation to the right.
				 if (leftTree->bal  == EH)
				 {
					 s->bal     = LH;
					 leftTree->bal = RH;
					 shorter       = false;
				 }
				 else
				 {
					 s->bal     = EH;
					 leftTree->bal = EH;
				 }
				 s = rotateRight (s);
				 break;
			 case RH:  // Perform a double rotation.
				 rightTree = leftTree->right;
				 switch (rightTree->bal)
				 {
				 case LH:     
					 s->bal     = RH;
					 leftTree->bal = EH;
					 break;
				 case EH:     
					 s->bal     = EH;
					 leftTree->bal = EH;
					 break;
				 case RH:     
					 s->bal     = EH;
					 leftTree->bal = LH;
					 break;
				 }
				 rightTree->bal = EH;
				 s->left     = rotateLeft (leftTree);
				 s           = rotateRight (s);
				 break;
			 }
      }
	  
      return s;
}



customer*  AvlTree::dltRightBalance (customer* s, bool& shorter)

// -----------------------------------------------------------------
// Purpose: This function rebalances the AVL based upon the
//          assumption that the tree is shorter after a deletion
//          on the left of the s. This function will adjust
//          the balance factors and rotate the tree to the left
//          if it is necessary. Function returns a potential
//          new s.
// -----------------------------------------------------------------

{
// The following are local pointers needed to rebalance the tree.

      customer  *rightTree;
      customer  *leftTree;

	  switch (s -> bal) // Determine if the s node is LH, EH, or RH.
	  {
	  case LH: // s was LH - now becomes balanced (EH).
		  s -> bal  = EH;
		  break;

	  case EH: // s was EH - becomes RH but remains balanced.
		  s -> bal  = RH;
		  shorter    = false;
		  break;
		  
	  case RH: // s is RH and remains RH - requires rotate left.
		  rightTree = s -> right;
		  if( rightTree -> bal == LH )// Need to perform a double rotation.	  
		  {
			  leftTree  = rightTree -> left;	
			  switch (leftTree -> bal)
			  {
			  case LH:    
				  rightTree -> bal	= RH;
				  s -> bal 		= EH;
				  break;
			  
			  case EH:    
				  s -> bal		= EH;
				  rightTree -> bal	= EH;
				  break;
	  
			  case RH:    
				  s -> bal		= LH;
				  rightTree -> bal	= EH;
				  break;
			  }
			  leftTree -> bal	= EH;
			  // Rotate right and then left.
			  s -> right		= rotateRight( rightTree );
			  s				= rotateLeft( s );
		  }
		  else// Perform a single rotation only.
		  {
			switch (rightTree -> bal)
			{
			  case LH:
			  case RH: 
				  s -> bal 		= EH;
				  rightTree -> bal	= EH;
				  break;
				  
			  case EH: 
				  s -> bal 		= RH;
				  rightTree -> bal	= LH;
				  shorter 			= false;
				  break;
			}
			  s = rotateLeft( s ); 
		  }
		  
	 }
	 return s;	 
}


bool  AvlTree::update(char x[10])

{
// The following are two objects that are shared through the recursive
// execution of updating a customer balance.
	bool success;
    customer *newRoot;
	newRoot = update(root, x, success);
	if (success)
 		return success;
	else 
	{
		printf("\n SORRY\n\tUPDATING FAILED\n");
		return false;
	}
}

customer*  AvlTree::update(customer* s,char idacc[10], bool& success)
// -----------------------------------------------------------------
// Purpose: This function update a customer balance.
// Returns true if updated, false if not found.
// -----------------------------------------------------------------

{

// The following is a local pointer needed for updating
// and interchanging of key and data values.
	customer *dltptr;
	if (!s)// If no node to delete, return null.
     {
		success = false;
        return NULL;
     }
	if (strcmp(idacc ,s->idaccount)<0)
		s->left = update(s->left, idacc, success);

	else if (strcmp(idacc, s->idaccount)>0)
		s->right = update(s->right, idacc, success);
         
	else// Otherwise the node having the key has been found.
	{
		dltptr=s;
		int choice;
		double balance;
		printf("choose the data u want to update:\n");
		printf("\t1-increase balance\n\t2-decreasing balance\n\t3-cancel\nyour choice:\t");
		scanf("%d", &choice);
		while((choice!=1)&&(choice!=2)&&(choice!=3))
		{
			printf("YOUR CHOICE MUST BE BETWEEN (1-3)\n");
			scanf("%d", &choice);
		}

		if(choice==1)
		{
			printf("ENTER THE AMOUNT YOU WANT TO ADD\n");
			scanf("%f", &balance);
			dltptr->balance+=balance;
		}
		else if(choice==2)
		{
			printf("ENTER THE AMOUNT YOU WANT TO DRAW\n");
			scanf("%f", &balance);
			while(balance > s->balance)
			{
				printf("\nSORRY!\nNOT REQUIRED\nYOUR BALANCE IS %d", s->balance);
				printf("ENTER ANOTHER AMOUNT:\t");
				scanf("%f", &balance);

			}
			dltptr->balance-=balance;

		}
		else
		{
			printf("\nNO CHANGE IN BALANCE\n");
		}

	}
	return s;
}
bool  AvlTree::printinfo(char x[10])

{

// The following are two objects that are shared through the recursive
// execution of printing information to a customer.
	bool success;
    customer *newRoot;
    
	if (newRoot = printinfo(root, x, success))
		  return success;
	else 
	{
		printf("\nSORRY!\n\tTHE CUSTOMER IS NOT AVAILABLE\n");
		return false;
	}
}

 

 

customer*  AvlTree::printinfo(customer* s,char idacc[10], bool& success)

// -----------------------------------------------------------------
// Purpose: This function print information 
// Returns true if printed, false if not found.
// -----------------------------------------------------------------

{
	if (!s)// If no node to delete, return null.
     {
          success = false;
		  printf ("\n There is no customer\n");
          return NULL;
     }
	if (strcmp(idacc ,s->idaccount)<0)// Test if need is to print informationa to the left customer of the s.
		s->left = printinfo(s->left, idacc, success);

	else if (strcmp(idacc, s->idaccount)>0)// Test if need is to print information to the right customer of the s.
		s->right = printinfo(s->right, idacc, success);
         

    else// Otherwise the node having the key has been found.
	{
		printf("\nTHE INFORMATION FOR CUSTOMER   %s:\n", s->idaccount);
		printf("\tNAME:\t%s\n\tSURNAME\t%s\n\tACCOUNT NUMBER \t%s\n\tBALANCE:\t%f\n\tIDNUMBERE\t%d\n", s->name, s->surname, s->idaccount, s->balance, s->id);
	}
	return s;
}
