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

#include "bst.h"
#include "queue.h"
/*
3. Двоичное дерево поиска
Узел — словарь: `{'val': '123', 'left': None, 'right': None}.`

Функции:

def bst_insert(root, name, phone) — рекурсивно или итеративно вставляет, возвращает новый корень (если корень меняется).

def bst_find(root, name) — поиск.

def bst_delete(root, name) — удаление, возвращает новый корень.

def bst_list_all(root) — центрированный обход (рекурсивно собирает записи в отсортированном порядке).
*/



bst_node* create_bst_node(char name[NAME_LEN], char phone[PHONE_LEN])
{
	bst_node* node = (bst_node*)malloc(sizeof(bst_node));

	strcpy(node->name, name);	
	strcpy(node->phone, phone);	

	node->left = NULL;
	node->right = NULL;

	return node;
}

bst_node* bst_minimum(bst_node* node)
{
	if (node->left == NULL)
		return node;
	return bst_minimum(node->left);
}

bst_node* bst_maximum(bst_node* node)
{
	if (node->right == NULL)
		return node;
	return bst_maximum(node->right);
}

void print_bst(bst_node node)
{
	//printf("value: %d\n", node.value);

	printf("name: %s, phone: %s\n", node.name, node.phone);
}

void bst_inorder_traversal(bst_node* HEAD)
{
	if (HEAD != NULL)
	{
		bst_inorder_traversal(HEAD->left);
		print_bst(*HEAD);
		bst_inorder_traversal(HEAD->right);
	}
}

void bst_preorder_traversal(bst_node* HEAD)
{
	if (HEAD != NULL)
	{
		print_bst(*HEAD);
		bst_preorder_traversal(HEAD->left);
		bst_preorder_traversal(HEAD->right);
	}
}

bst_node* bst_search(bst_node* HEAD, char target_name[NAME_LEN])
{
	/*
	Node search(x : Node, k : T):
   if x == null or k == x.key
      return x
   if k < x.key
      return search(x.left, k)
   else
      return search(x.right, k)
	*/

	if ((HEAD == NULL) || strcmp(HEAD->name, target_name) == 0)
	{
		return HEAD;
	}
	if (strcmp(target_name, HEAD->name) < 0)
	{
		return bst_search(HEAD->left, target_name);
	}
	else
	{
		return bst_search(HEAD->right, target_name);
	}
}

bst_node* bst_insert(bst_node* HEAD, char name[NAME_LEN], char phone[PHONE_LEN])
{
	/*
  Node insert(x : Node, z : T):               // x — корень поддерева, z — вставляемый ключ
   if x == null 
      return Node(z)                        // подвесим Node с key = z
   else if z < x.key
      x.left = insert(x.left, z)
   else if z > x.key
      x.right = insert(x.right, z)
   return x
	*/

	if (HEAD == NULL)
	{
		return create_bst_node(name, phone);
	}
	else if (strcmp(name, HEAD->name) < 0)
	{
		HEAD->left = bst_insert(HEAD->left, name, phone);
	}
	else if (strcmp(name, HEAD->name) > 0)
	{
		HEAD->right = bst_insert(HEAD->right, name, phone);
	}
	return HEAD;
}

bst_node* bst_delete(bst_node* root, char target_name[NAME_LEN])
{               // корень поддерева, удаляемый ключ
	if (root == NULL)
		return root;

	if (strcmp(target_name, root->name) < 0)
    	root->left = bst_delete(root->left, target_name);
	else if (strcmp(target_name, root->name) > 0)
    	root->right = bst_delete(root->right, target_name);
	else {
		if (root->left != NULL && root->right != NULL)
		{
			strcpy(root->name, bst_minimum(root->right)->name);
    		strcpy(root->phone, bst_minimum(root->right)->phone);

    		root->right = bst_delete(root->right, root->name);
		} 
		else 
		{
    		bst_node* temp = root;
			if (root->left != NULL)
				root = root->left;
			else
				root = root->right;
			free(temp);
		}
	}
  	return root;
}

void delete_bst(bst_node* root)
{
	if (root == NULL)
		return;
	else
	{
		delete_bst(root->left);
		delete_bst(root->right);
		free(root);
	}
}

void printTree(bst_node* node, int depth) {

    if (node == NULL) return;
    
    printTree(node->right, depth + 1);
    
    for (int i = 0; i < depth; i++)
        printf("\t");
    //printf("%d\n", node->value);
    print_bst(*node);

    printTree(node->left, depth + 1);
}

void treeLevelTraversal(bst_node* node) {
  	if (!node) return;

  	Queue q;
  	Queue* hq = &q;
  	queueInit(hq);

  	queuePush(hq, node);
  	while(!queueEmpty(hq)) 
  	{
    	bst_node* hn = queuePop(hq);
    	//printf("%d\n", hn->value);
    	print_bst(*hn);

		if(hn->left) 
			queuePush(hq, hn->left);
    	if(hn->right) 
			queuePush(hq, hn->right);

  	};
}; 
