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

#ifdef _WIN32
#include <string.h>
#define strcasecmp _stricmp
#endif

// Define maximum lengths for strings
#define MAX_TITLE 256
#define MAX_AUTHORS 256
#define MAX_GENRE 100
#define MAX_LINE 1024

typedef struct Book {
    char title[MAX_TITLE];
    char authors[MAX_AUTHORS];
    int year;
    double rating;
    double price;
    char genre[MAX_GENRE];
} Book;

typedef struct AVLNode {
    Book book;
    struct AVLNode* left;
    struct AVLNode* right;
    int height;
} AVLNode;

// Enum for command types
typedef enum {
    CMD_ADD,
    CMD_DELETE,
    CMD_SEARCH,
    CMD_EDIT,
    CMD_LNRPRINTTREE,
    CMD_NLRPRINTTREE,
    CMD_LRNPRINTTREE,
    CMD_HELP,
    CMD_INVALID
} CommandType;

// Function prototypes
int max_int(int a, int b);
int height_node(AVLNode* N);
AVLNode* newNode(Book book);
AVLNode* rightRotate(AVLNode* y);
AVLNode* leftRotate(AVLNode* x);
int getBalance(AVLNode* N);
int compareBooks(const Book* a, const Book* b);
AVLNode* insertNode(AVLNode* node, Book book, int* added);
AVLNode* minValueNode(AVLNode* node);
AVLNode* deleteNode(AVLNode* root, char* title, int* deleted);
int searchTree(AVLNode* root, char* field, char* value);
void inorderTraversal(AVLNode* root);
void preorderTraversal(AVLNode* root);
void postorderTraversal(AVLNode* root);
void printBook(Book book);
void trim(char* str);
CommandType identify_command(const char* input_line);
int compare_nocase(const char* a, const char* b, size_t n);
void handle_add(AVLNode** root);
void handle_delete(AVLNode** root, char* params);
void handle_search(AVLNode* root, char* params);
void handle_edit(AVLNode** root);
void handle_lnrprinttree(AVLNode* root);
void handle_nlrprinttree(AVLNode* root);
void handle_lrnprinttree(AVLNode* root);
void handle_help();
void free_avl_tree(AVLNode* root);

// Implementations

// Helper function for case-insensitive comparison
int compare_nocase(const char* a, const char* b, size_t n) {
    for (size_t i = 0; i < n; i++) {
        char ca = tolower((unsigned char)a[i]);
        char cb = tolower((unsigned char)b[i]);
        if (ca != cb)
            return ca - cb;
        if (ca == '\0')
            return 0;
    }
    return 0;
}

int max_int(int a, int b) {
    return (a > b) ? a : b;
}

int height_node(AVLNode* N) {
    if (N == NULL)
        return 0;
    return N->height;
}

AVLNode* newNode(Book book) {
    AVLNode* node = (AVLNode*)malloc(sizeof(AVLNode));
    if (!node) {
        perror("Failed to allocate memory");
        exit(EXIT_FAILURE);
    }
    node->book = book;
    node->left = node->right = NULL;
    node->height = 1; // New node is initially added at leaf
    return node;
}

AVLNode* rightRotate(AVLNode* y) {
    AVLNode* x = y->left;
    AVLNode* T2 = x->right;

    // Perform rotation
    x->right = y;
    y->left = T2;

    // Update heights
    y->height = max_int(height_node(y->left), height_node(y->right)) + 1;
    x->height = max_int(height_node(x->left), height_node(x->right)) + 1;

    // Return new root
    return x;
}

AVLNode* leftRotate(AVLNode* x) {
    AVLNode* y = x->right;
    AVLNode* T2 = y->left;

    // Perform rotation
    y->left = x;
    x->right = T2;

    // Update heights
    x->height = max_int(height_node(x->left), height_node(x->right)) + 1;
    y->height = max_int(height_node(y->left), height_node(y->right)) + 1;

    // Return new root
    return y;
}

int getBalance(AVLNode* N) {
    if (N == NULL)
        return 0;
    return height_node(N->left) - height_node(N->right);
}

// Compare books by title for AVL tree
int compareBooks(const Book* a, const Book* b) {
    return strcmp(a->title, b->title);
}

AVLNode* insertNode(AVLNode* node, Book book, int* added) {
    if (node == NULL) {
        *added = 1;
        return newNode(book);
    }

    int cmp = compareBooks(&book, &node->book);
    if (cmp < 0)
        node->left = insertNode(node->left, book, added);
    else if (cmp > 0)
        node->right = insertNode(node->right, book, added);
    else {
        // Duplicate title
        *added = 0;
        return node;
    }

    // Update height
    node->height = 1 + max_int(height_node(node->left), height_node(node->right));

    // Get balance factor
    int balance = getBalance(node);

    // Balance the tree
    // Left Left Case
    if (balance > 1 && compareBooks(&book, &node->left->book) < 0)
        return rightRotate(node);

    // Right Right Case
    if (balance < -1 && compareBooks(&book, &node->right->book) > 0)
        return leftRotate(node);

    // Left Right Case
    if (balance > 1 && compareBooks(&book, &node->left->book) > 0) {
        node->left = leftRotate(node->left);
        return rightRotate(node);
    }

    // Right Left Case
    if (balance < -1 && compareBooks(&book, &node->right->book) < 0) {
        node->right = rightRotate(node->right);
        return leftRotate(node);
    }

    return node;
}

AVLNode* minValueNode(AVLNode* node) {
    AVLNode* current = node;
    while (current->left != NULL)
        current = current->left;
    return current;
}

AVLNode* deleteNode(AVLNode* root, char* title, int* deleted) {
    if (root == NULL) {
        *deleted = 0;
        return root;
    }

    int cmp = strcmp(title, root->book.title);
    if (cmp < 0)
        root->left = deleteNode(root->left, title, deleted);
    else if (cmp > 0)
        root->right = deleteNode(root->right, title, deleted);
    else {
        // Node with only one child or no child
        if ((root->left == NULL) || (root->right == NULL)) {
            AVLNode* temp = root->left ? root->left : root->right;
            if (temp == NULL) {
                // No child
                temp = root;
                root = NULL;
            } else {
                // One child
                *root = *temp;
            }
            free(temp);
            *deleted = 1;
        } else {
            // Node with two children
            AVLNode* temp = minValueNode(root->right);
            root->book = temp->book;
            root->right = deleteNode(root->right, temp->book.title, deleted);
        }
    }

    if (root == NULL)
        return root;

    // Update height
    root->height = 1 + max_int(height_node(root->left), height_node(root->right));

    // Get balance factor
    int balance = getBalance(root);

    // Balance the tree
    // Left Left Case
    if (balance > 1 && getBalance(root->left) >= 0)
        return rightRotate(root);

    // Left Right Case
    if (balance > 1 && getBalance(root->left) < 0) {
        root->left = leftRotate(root->left);
        return rightRotate(root);
    }

    // Right Right Case
    if (balance < -1 && getBalance(root->right) <= 0)
        return leftRotate(root);

    // Right Left Case
    if (balance < -1 && getBalance(root->right) > 0) {
        root->right = rightRotate(root->right);
        return leftRotate(root);
    }

    return root;
}

// Function to search by field and value
int searchTree(AVLNode* root, char* field, char* value) {
    if (root == NULL)
        return 0;

    // Check current node
    int match = 0;
    if (strcasecmp(field, "Название книги") == 0 || strcasecmp(field, "Title") == 0) {
        match = (strcmp(root->book.title, value) == 0);
    } else if (strcasecmp(field, "Автор/Авторы") == 0 || strcasecmp(field, "Authors") == 0) {
        // Check if any author matches
        char authors_copy[MAX_AUTHORS];
        strcpy(authors_copy, root->book.authors);
        char* token = strtok(authors_copy, ",");
        while (token) {
            while (isspace((unsigned char)*token)) token++;
            if (strcmp(token, value) == 0) {
                match = 1;
                break;
            }
            token = strtok(NULL, ",");
        }
    } else if (strcasecmp(field, "Год выпуска") == 0 || strcasecmp(field, "Year") == 0) {
        char year_str[10];
        sprintf(year_str, "%d", root->book.year);
        match = (strcmp(year_str, value) == 0);
    } else if (strcasecmp(field, "Оценка читателей") == 0 || strcasecmp(field, "Rating") == 0) {
        char rating_str[10];
        sprintf(rating_str, "%.2lf", root->book.rating);
        match = (strcmp(rating_str, value) == 0);
    } else if (strcasecmp(field, "Цена книги") == 0 || strcasecmp(field, "Price") == 0) {
        char price_str[20];
        sprintf(price_str, "%.2lf", root->book.price);
        match = (strcmp(price_str, value) == 0);
    } else if (strcasecmp(field, "Жанр") == 0 || strcasecmp(field, "Genre") == 0) {
        match = (strcmp(root->book.genre, value) == 0);
    }

    if (match)
        return 1;

    // Recurse to left and right
    return searchTree(root->left, field, value) || searchTree(root->right, field, value);
}

void inorderTraversal(AVLNode* root) {
    if (root != NULL) {
        inorderTraversal(root->left);
        printBook(root->book);
        printf("\n"); // Add newline for better readability
        inorderTraversal(root->right);
    }
}

void preorderTraversal(AVLNode* root) {
    if (root != NULL) {
        printBook(root->book);
        printf("\n");
        preorderTraversal(root->left);
        preorderTraversal(root->right);
    }
}

void postorderTraversal(AVLNode* root) {
    if (root != NULL) {
        postorderTraversal(root->left);
        postorderTraversal(root->right);
        printBook(root->book);
        printf("\n");
    }
}

void printBook(Book book) {
    printf("\"%s\" \"%s\" \"%d\" \"%.2lf\" \"%.2lf\" \"%s\"",
           book.title, book.authors, book.year, book.rating, book.price, book.genre);
}

void trim(char* str) {
    // Trim leading space
    char* start = str;
    while (isspace((unsigned char)*start)) start++;

    // If all spaces
    if (*start == 0) {
        str[0] = '\0';
        return;
    }

    // Trim trailing space
    char* end = start + strlen(start) - 1;
    while (end > start && isspace((unsigned char)*end)) end--;

    // Write new null terminator
    *(end + 1) = '\0';

    // Shift trimmed string to the beginning
    if (start != str)
        memmove(str, start, end - start + 2);
}

// Function to identify the command type (case-insensitive)
CommandType identify_command(const char* input_line) {
    // Skip leading spaces
    while (isspace((unsigned char)*input_line)) input_line++;

    // Define command strings
    const char* cmd_add = "ADD";
    const char* cmd_delete = "DELETE";
    const char* cmd_search = "SEARCH";
    const char* cmd_edit = "EDIT";
    const char* cmd_lnrprinttree = "LNRPRINTTREE";
    const char* cmd_nlrprinttree = "NLRPRINTTREE";
    const char* cmd_lrnprinttree = "LRNPRINTTREE";
    const char* cmd_help = "HELP";

    // Compare commands case-insensitively
    if (strcasecmp(input_line, cmd_add) == 0 || 
        (strncasecmp(input_line, cmd_add, 3) == 0 && isspace((unsigned char)input_line[3]))) {
        return CMD_ADD;
    }
    else if (strcasecmp(input_line, cmd_delete) == 0 || 
             (strncasecmp(input_line, cmd_delete, 6) == 0 && isspace((unsigned char)input_line[6]))) {
        return CMD_DELETE;
    }
    else if (strcasecmp(input_line, cmd_search) == 0 || 
             (strncasecmp(input_line, cmd_search, 6) == 0 && isspace((unsigned char)input_line[6]))) {
        return CMD_SEARCH;
    }
    else if (strcasecmp(input_line, cmd_edit) == 0 || 
             (strncasecmp(input_line, cmd_edit, 4) == 0 && isspace((unsigned char)input_line[4]))) {
        return CMD_EDIT;
    }
    else if (strcasecmp(input_line, cmd_lnrprinttree) == 0 || 
             (strncasecmp(input_line, cmd_lnrprinttree, 11) == 0 && 
              (input_line[11] == '\0' || isspace((unsigned char)input_line[11])))) {
        return CMD_LNRPRINTTREE;
    }
    else if (strcasecmp(input_line, cmd_nlrprinttree) == 0 || 
             (strncasecmp(input_line, cmd_nlrprinttree, 11) == 0 && 
              (input_line[11] == '\0' || isspace((unsigned char)input_line[11])))) {
        return CMD_NLRPRINTTREE;
    }
    else if (strcasecmp(input_line, cmd_lrnprinttree) == 0 || 
             (strncasecmp(input_line, cmd_lrnprinttree, 11) == 0 && 
              (input_line[11] == '\0' || isspace((unsigned char)input_line[11])))) {
        return CMD_LRNPRINTTREE;
    }
    else if (strcasecmp(input_line, cmd_help) == 0) {
        return CMD_HELP;
    }
    else {
        return CMD_INVALID;
    }
}

// Function to get user input safely
int get_input(const char* prompt, char* buffer, int size) {
    printf("%s", prompt);
    if (fgets(buffer, size, stdin) == NULL)
        return 0;
    // Remove trailing newline
    buffer[strcspn(buffer, "\n")] = '\0';
    trim(buffer);
    return 1;
}

void handle_add(AVLNode** root) {
    Book new_book;
    char buffer[MAX_LINE];

    // Input Title
    if (!get_input("Введите название книги: ", buffer, MAX_TITLE)) {
        printf("Error parse\n");
        return;
    }
    strcpy(new_book.title, buffer);
    if (strlen(new_book.title) == 0) {
        printf("Error parse\n");
        return;
    }

    // Input Authors
    if (!get_input("Введите автора/авторов (разделяются запятыми): ", buffer, MAX_AUTHORS)) {
        printf("Error parse\n");
        return;
    }
    strcpy(new_book.authors, buffer);
    if (strlen(new_book.authors) == 0) {
        printf("Error parse\n");
        return;
    }

    // Input Year
    if (!get_input("Введите год выпуска: ", buffer, sizeof(buffer))) {
        printf("Error parse\n");
        return;
    }
    if (!isdigit((unsigned char)buffer[0])) {
        printf("Error parse\n");
        return;
    }
    new_book.year = atoi(buffer);

    // Input Rating
    if (!get_input("Введите оценку читателей: ", buffer, sizeof(buffer))) {
        printf("Error parse\n");
        return;
    }
    char* endptr;
    new_book.rating = strtod(buffer, &endptr);
    if (*endptr != '\0') {
        printf("Error parse\n");
        return;
    }

    // Input Price
    if (!get_input("Введите цену книги: ", buffer, sizeof(buffer))) {
        printf("Error parse\n");
        return;
    }
    new_book.price = strtod(buffer, &endptr);
    if (*endptr != '\0') {
        printf("Error parse\n");
        return;
    }

    // Input Genre
    if (!get_input("Введите жанр: ", buffer, MAX_GENRE)) {
        printf("Error parse\n");
        return;
    }
    strcpy(new_book.genre, buffer);
    if (strlen(new_book.genre) == 0) {
        printf("Error parse\n");
        return;
    }

    // Insert into AVL tree
    int added = 0;
    *root = insertNode(*root, new_book, &added);
    if (added)
        printf("ADD_DONE\n");
    else
        printf("ADD_ALREADY\n");
}

void handle_delete(AVLNode** root, char* params) {
    char* ptr = params;
    // Trim any leading spaces
    while (isspace((unsigned char)*ptr)) ptr++;

    // Expecting the title in quotes
    if (*ptr != '\"') {
        printf("Error parse\n");
        return;
    }

    // Extract the title
    ptr++; // Skip the opening quote
    char title[MAX_TITLE];
    int i = 0;
    while (*ptr != '\"' && *ptr != '\0' && i < MAX_TITLE - 1) {
        title[i++] = *ptr++;
    }
    if (*ptr != '\"') {
        printf("Error parse\n");
        return;
    }
    title[i] = '\0';

    // Proceed to delete
    int deleted = 0;
    *root = deleteNode(*root, title, &deleted);
    if (deleted)
        printf("DELETE_DONE\n");
    else
        printf("DELETE_CANNOT\n");
}

void handle_search(AVLNode* root, char* params) {
    char* ptr = params;
    // Trim leading spaces
    while (isspace((unsigned char)*ptr)) ptr++;

    // Expecting two quoted strings: field and value
    if (*ptr != '\"') {
        printf("Error parse\n");
        return;
    }

    // Extract field
    ptr++; // Skip opening quote
    char field[MAX_GENRE];
    int i = 0;
    while (*ptr != '\"' && *ptr != '\0' && i < MAX_GENRE - 1) {
        field[i++] = *ptr++;
    }
    if (*ptr != '\"') {
        printf("Error parse\n");
        return;
    }
    field[i] = '\0';
    ptr++; // Skip closing quote

    // Trim any spaces between field and value
    while (isspace((unsigned char)*ptr)) ptr++;

    // Expecting value in quotes
    if (*ptr != '\"') {
        printf("Error parse\n");
        return;
    }
    ptr++; // Skip opening quote
    char value[MAX_TITLE];
    i = 0;
    while (*ptr != '\"' && *ptr != '\0' && i < MAX_TITLE - 1) {
        value[i++] = *ptr++;
    }
    if (*ptr != '\"') {
        printf("Error parse\n");
        return;
    }
    value[i] = '\0';

    // Perform search
    int found = searchTree(root, field, value);
    printf("%s\n", found ? "YES" : "NO");
}

void handle_edit(AVLNode** root) {
    char buffer[MAX_LINE];

    // Input existing title
    if (!get_input("Введите название книги для редактирования: ", buffer, MAX_TITLE)) {
        printf("Error parse\n");
        return;
    }
    char existing_title[MAX_TITLE];
    strcpy(existing_title, buffer);
    if (strlen(existing_title) == 0) {
        printf("Error parse\n");
        return;
    }

    // Find the book in the tree
    AVLNode* current = *root;
    while (current != NULL) {
        int cmp = strcmp(existing_title, current->book.title);
        if (cmp < 0)
            current = current->left;
        else if (cmp > 0)
            current = current->right;
        else
            break;
    }

    if (current == NULL) {
        printf("EDIT_CANNOT\n");
        return;
    }

    Book updated_book = current->book;
    int any_change = 0;

    while (1) {
        printf("\nВыберите поле для редактирования:\n");
        printf("1. Название книги\n");
        printf("2. Автор/Авторы\n");
        printf("3. Год выпуска\n");
        printf("4. Оценка читателей\n");
        printf("5. Цена книги\n");
        printf("6. Жанр\n");
        printf("7. Завершить редактирование\n");
        printf("Введите номер команды: ");

        char choice_str[10];
        if (fgets(choice_str, sizeof(choice_str), stdin) == NULL) {
            printf("Error parse\n");
            return;
        }

        int choice = atoi(choice_str);
        if (choice == 7)
            break;

        char input_buffer[MAX_LINE];
        switch (choice) {
            case 1:
                if (!get_input("Введите новое название книги: ", input_buffer, MAX_TITLE)) {
                    printf("Error parse\n");
                    return;
                }
                if (strlen(input_buffer) == 0) {
                    printf("Error parse\n");
                    return;
                }
                // Check if new title already exists
                {
                    AVLNode* temp = *root;
                    int exists = 0;
                    while (temp != NULL) {
                        int cmp = strcmp(input_buffer, temp->book.title);
                        if (cmp < 0)
                            temp = temp->left;
                        else if (cmp > 0)
                            temp = temp->right;
                        else {
                            exists = 1;
                            break;
                        }
                    }
                    if (exists) {
                        printf("EDIT_CANNOT\n");
                        return;
                    }
                }
                strcpy(updated_book.title, input_buffer);
                any_change = 1;
                break;
            case 2:
                if (!get_input("Введите новых авторов (разделяются запятыми): ", input_buffer, MAX_AUTHORS)) {
                    printf("Error parse\n");
                    return;
                }
                if (strlen(input_buffer) == 0) {
                    printf("Error parse\n");
                    return;
                }
                strcpy(updated_book.authors, input_buffer);
                any_change = 1;
                break;
            case 3:
                if (!get_input("Введите новый год выпуска: ", input_buffer, sizeof(buffer))) {
                    printf("Error parse\n");
                    return;
                }
                if (!isdigit((unsigned char)input_buffer[0])) {
                    printf("Error parse\n");
                    return;
                }
                updated_book.year = atoi(input_buffer);
                any_change = 1;
                break;
            case 4:
                if (!get_input("Введите новую оценку читателей: ", input_buffer, sizeof(buffer))) {
                    printf("Error parse\n");
                    return;
                }
                {
                    char* endptr;
                    double rating = strtod(input_buffer, &endptr);
                    if (*endptr != '\0') {
                        printf("Error parse\n");
                        return;
                    }
                    updated_book.rating = rating;
                    any_change = 1;
                }
                break;
            case 5:
                if (!get_input("Введите новую цену книги: ", input_buffer, sizeof(buffer))) {
                    printf("Error parse\n");
                    return;
                }
                {
                    char* endptr;
                    double price = strtod(input_buffer, &endptr);
                    if (*endptr != '\0') {
                        printf("Error parse\n");
                        return;
                    }
                    updated_book.price = price;
                    any_change = 1;
                }
                break;
            case 6:
                if (!get_input("Введите новый жанр: ", input_buffer, MAX_GENRE)) {
                    printf("Error parse\n");
                    return;
                }
                if (strlen(input_buffer) == 0) {
                    printf("Error parse\n");
                    return;
                }
                strcpy(updated_book.genre, input_buffer);
                any_change = 1;
                break;
            default:
                printf("Неверный выбор. Пожалуйста, выберите число от 1 до 7.\n");
                break;
        }
    }

    if (any_change) {
        // If title has changed, need to delete old and insert new
        if (strcmp(existing_title, updated_book.title) != 0) {
            // Delete old
            int deleted = 0;
            *root = deleteNode(*root, existing_title, &deleted);
            if (!deleted) {
                printf("EDIT_CANNOT\n");
                return;
            }
            // Insert updated
            int added = 0;
            *root = insertNode(*root, updated_book, &added);
            if (added)
                printf("EDIT_DONE\n");
            else
                printf("EDIT_CANNOT\n");
        } else {
            // Title unchanged, just update the book
            current->book = updated_book;
            printf("EDIT_DONE\n");
        }
    } else {
        printf("EDIT_CANNOT\n");
    }
}

void handle_lnrprinttree(AVLNode* root) {
    inorderTraversal(root);
    printf("\n");
}

void handle_nlrprinttree(AVLNode* root) {
    preorderTraversal(root);
    printf("\n");
}

void handle_lrnprinttree(AVLNode* root) {
    postorderTraversal(root);
    printf("\n");
}

void handle_help() {
    printf("\nДоступные команды:\n");
    printf("ADD - Добавить новую книгу\n");
    printf("DELETE \"Название книги\" - Удалить книгу по названию\n");
    printf("SEARCH \"Поле\" \"Значение\" - Поиск книги по полю и значению\n");
    printf("EDIT - Редактировать существующую книгу\n");
    printf("LNRPRINTTREE - Вывод дерева книг (Обход In-order)\n");
    printf("NLRPRINTTREE - Вывод дерева книг (Обход Pre-order)\n");
    printf("LRNPRINTTREE - Вывод дерева книг (Обход Post-order)\n");
    printf("HELP - Вывести список команд\n\n");
}

void free_avl_tree(AVLNode* root) {
    if (root == NULL)
        return;
    free_avl_tree(root->left);
    free_avl_tree(root->right);
    free(root);
}

// Main function
int main() {
    AVLNode* root = NULL;
    char line[MAX_LINE];

    printf("Добро пожаловать в базу данных книг!\n");
    printf("Введите команду. Для списка команд введите HELP.\n");

    while (fgets(line, sizeof(line), stdin)) {
        // Remove trailing newline
        line[strcspn(line, "\n")] = '\0';

        // Trim the line
        trim(line);

        // Handle empty lines
        if (line[0] == '\0')
            continue;

        // Identify command
        CommandType cmd = identify_command(line);

        // Pointer to parse the rest of the line
        char* ptr = line;

        // Advance pointer based on command
        switch (cmd) {
            case CMD_ADD:
                ptr += 3; // Move past "ADD"
                handle_add(&root);
                break;

            case CMD_DELETE:
                ptr += 6; // Move past "DELETE"
                handle_delete(&root, ptr);
                break;

            case CMD_SEARCH:
                ptr += 6; // Move past "SEARCH"
                handle_search(root, ptr);
                break;

            case CMD_EDIT:
                ptr += 4; // Move past "EDIT"
                handle_edit(&root);
                break;

            case CMD_LNRPRINTTREE:
                handle_lnrprinttree(root);
                break;

            case CMD_NLRPRINTTREE:
                handle_nlrprinttree(root);
                break;

            case CMD_LRNPRINTTREE:
                handle_lrnprinttree(root);
                break;

            case CMD_HELP:
                handle_help();
                break;

            default:
                printf("Error parse\n");
                break;
        }

        printf("Введите следующую команду или HELP для списка команд.\n");
    }

    // Cleanup: Free all allocated memory
    free_avl_tree(root);

    return 0;
}
 
Привет. Мне нужно чтобы поиск по полям был логарифмической сложности, но в этом коде логарифмическая сложность только у поиска по полям