#include "basic_tree.h"
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <time.h>
// FCTs perso

struct queue *enqueue(struct queue *queue, struct node *node){

    //if (!queue || !node) return NULL;

    //struct queue *tmp = queue;
    // ajout en fin
    //while(tmp){
     //   tmp = tmp->next;
    //}
    
    struct queue *new_queue = malloc(sizeof(struct queue));
    if(!new_queue)return NULL;

    new_queue->node = node;
    new_queue->next = NULL;
        
    if(!queue) return new_queue;

    struct queue *tmp = queue;

    while(tmp->next) tmp = tmp->next;

    tmp->next = new_queue;

    return queue;
}

struct node *dequeue(struct queue **queue){

    if(!queue || !*queue) return NULL;

    // On suppr la head
    struct queue *tmp = *queue;
    struct node *node = tmp->node;
    *queue = tmp->next;
    free(tmp);

    return node;
}

void queue_destroy(struct queue *queue){

    while(queue){
    struct queue *tmp = queue;
    queue = queue->next;
    free(tmp);
    }
}

void delete_tree(struct node *root){
    
    if(!root) return;

    delete_tree(root->left);
    delete_tree(root->right);
    free(root);
}

int find(struct node *root, int value){

    // -1 : erreur, 0 : pas de leaf/node, x>0 : nombre trouvé
    if(!root)return -1;

    int found = 0;
    struct queue *queue = enqueue(NULL, root);
    
    while(queue != NULL){

        struct node *tmp = dequeue(&queue);

        //si tmp est une leaf
        if(!tmp->left && !tmp->right) {
           if(tmp->value == value) found ++;
        } 
        else {

            if(tmp->value == value) found ++;
            queue = enqueue(queue, tmp->left);
            queue = enqueue(queue, tmp->right);
        }
    }

    free (queue);
    return found;

}


//#################################################################
// FCTs sujet

struct node *insert(struct node *root, int value){

    // Parcours largeur

    struct node *node = malloc(sizeof(struct node));
    if(!node) return NULL;
    
    node->value = value;
    node->left = NULL;
    node->right = NULL;

    if (!root) return node;
    else{

        struct queue *queue = enqueue(NULL ,root);
        
        while(queue != NULL){
            
            struct node *tmp = dequeue(&queue);

            if(tmp->left == NULL) {
                tmp->left = node;
                queue_destroy(queue);
                break;
            }
            else if (tmp->right == NULL) {
                tmp->right = node;
                queue_destroy(queue);
                break;
            }
            else{

                queue = enqueue(queue, tmp->left);
                queue = enqueue(queue, tmp->right);
            }

        }
        
    }
    return root;
}

void delete_leaf(struct node *root, int value){

    if(!root || !value) return;


    if(root->left){

        // On regarde si c'est un noeud
        if(root->left || root->right){

            // On regarde si c'est une leaf
            if(!root->left->left && !root->left->right && root->left->value == value){
                free(root->left);
                root->left = NULL;
            }
            else delete_leaf(root->left, value);
        }
    }

    if(root->right){
        
    // On regarde si c'est un noeud
        
        if(root->left || root->right){

            // On regarde si c'est une leaf 
            if(!root->right->left && !root->right->right && root->right->value == value){
                free(root->right);
                root->right = NULL;
            }
            else delete_leaf(root->right, value);
        }    
    }
     
}
    
struct node *delete_node(struct node *root, int value){

    if(!root) return NULL;

    // 3 cas : 1 si le node a un child, 2 si le node a deux nodes, 3 si il en a pas

    // Si il a pas de child 
    if(!root->left && !root->right){
        if(root->value == value){
            free(root);
            return NULL;
        }
        return root;
    }
    
    struct node *targ = NULL;
    struct node *prec_child = NULL;
    struct node *prec_dad = NULL;

    struct queue *queue = enqueue(NULL, root);

    while(queue != NULL){

        struct node *tmp = dequeue(&queue);
        

        if (tmp->value == value && !targ) targ = tmp;
        
        if(tmp->left){
            prec_dad = tmp;
            queue = enqueue(queue, tmp->left);
            prec_child = tmp->left;
        }

        if(tmp->right){
            prec_dad = tmp;
            queue = enqueue(queue, tmp->right);
            prec_child = tmp->right;
        }
    }
    if(targ){

        targ->value = prec_child->value;

        if(prec_dad->right == prec_child) prec_dad->right = NULL;
        else prec_dad->left = NULL;
        free(prec_child);
    }
    
    return root;
}

void pretty_print(struct node *root){


    if(!root) return;
    struct queue *queue = enqueue(NULL, root);
    int index_l = 1;
    int index_n = 0;

    while(queue){

        struct node *tmp = dequeue(&queue);
        index_l--;

        printf("%d", tmp->value);

        if(tmp->left){
            queue = enqueue(queue, tmp->left);
            index_n++;
        }
        
        if(tmp->right){
            queue = enqueue(queue, tmp->right);
            index_n++;
        }
        if(index_l > 0) printf("\t");
        else{
            printf("\n");
            index_l = index_n;
            index_n = 0;
        }
    }
}

int main(int argc, char *argv[]) {
  if (argc == 1)
      return 1;
  
  struct node *root = NULL;
  for (int i = 1; i < argc; i++) {
      root = insert(root, atoi(argv[i]));
  }

  pretty_print(root);
  
  delete_tree(root);
  return 0;
}



/*
int main() {
  struct node *root = insert(NULL, 0);
  root = insert(root, 1);
  root = insert(root, 2);
  root = delete_node(root, 0);
  printf("%d, %d\n", root->value, root->left->value); // 2, 1
}
*/

/*
int main() {
  struct node *root = insert(NULL, 0);
  root = insert(root, 1);
  root = insert(root, 2);
  delete_leaf(root, 2);
  printf("%d, %d\n", root->value, root->left->value); // 0, 1

}i*/


/*
int main() {
  struct node *root = insert(NULL, 0);
  root = insert(root, 1);
  root = insert(root, 2);
  printf("%d, %d, %d\n", root->value, root->left->value, root->right->value); // 0, 1, 2
    
}
*/
