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

typedef struct _node {
  struct _node* right;
  struct _node* child;
  long lvl;
  long key;
} node;

typedef struct _list {
  node *node;
  struct _list *next;
} list;

void visit_node_post_order(node *q, void (*callback)(node *)) {
  if (!q) {
    return;
  }

  visit_node_post_order(q->child, callback);
  visit_node_post_order(q->right, callback);
  callback(q);
}

void visit_node_pre_order(node *q, void (*callback)(node *)) {
  if (!q) {
    return;
  }

  callback(q);
  visit_node_post_order(q->right, callback);
  visit_node_post_order(q->child, callback);
}


void node_destroy(list *q) {
  void (*func)(node *) = (void (*)(node *))free;
  list *t = q;
  list *prev = NULL;
  while (t) {
    visit_node_post_order(t->node, func);
    prev = t;
    t = t->next;
    free(prev);
  }
}

node* node_create(long key) {
  node *res = (node *)malloc(sizeof(node));
  res->lvl = 0;
  res->key = key;
  res->right = NULL;
  res->child = NULL;
  return res;
}

node* node_union_same_lvl(node* l, node* r) {
  if (!l) {
    return r;
  }

  if (!r) {
    return l;
  }

  if (l->lvl != r->lvl) {
    fprintf(stderr, "L lvl %d and R lvl %d do mismatch. Returning NULL\n", l->lvl, r->lvl);
    return NULL;
  }

  node* item;
  node* subitem;

  if (l->key > r->key) {
    // l main
    item = l;
    subitem = r;
  } else {
    // r main
    item = r;
    subitem = l;
  }

  if (item->child) {
    node *t = item->child;
    while (t->right != NULL) {
      t = t->right;
    }
    t->right = subitem;
  } else {
    item->child = subitem;
  }
  item->lvl++; // we merged two same lvl binomial heap nodes and created on lvl bigger

  return item;
}

void dump_node(node *q) {
  printf("%d ", q->key);
}

void dump_heap(list *q) {
  list *t = q;
  while (t) {
    printf("Binom lvl %d\n", t->node->lvl);
    visit_node_pre_order(t->node, dump_node);
    printf("\n");
    t = t->next;
  }
}

list* node_add(list *q, long key) {
  list *c = NULL;
  list *a = q;
  node *b = node_create(key);
  list *bl;

  if (!q) {
    a = (list*)malloc(sizeof(list));
    a->node = b;
    return a;
  }

  while (a) {
    if (a->node->lvl > b->lvl) { // it a always will be bigger or equal
      list *el = (list*)malloc(sizeof(list));
      el->node = b;
      el->next = a;
      return el;
    } else {
      c = a->next;
      a->node = node_union_same_lvl(a->node, b);
      bl = a;
      b = a->node;
      a = c;
    }
  }

  return bl;

}

int node_del(node *q) {
  // TODO
  return -1;
}


const int MAX_BUFFER = 0x1000;

int main() {
  char cmd[MAX_BUFFER];
  list *q = NULL;
  while (1) {

    fgets(cmd, MAX_BUFFER, stdin);
    printf("Got command %s\n", cmd);

    if (strlen(cmd) == 0 || cmd[0] == '\n') {
      printf("Finished reading\n");
      break;
    } else if (memcmp(cmd, "ADD", 3) == 0) {
      // handle command add
      int x = atoi(cmd + 4);
       
      q = node_add(q, x);

      printf("Added number: %d\n", x);
  
    } else if (memcmp(cmd, "DEL", 3) == 0) {
      // handle command del
      if (!q) {
        fprintf(stderr, "There is nothing to delete - heap is empty\n");
        continue;
      }
      // TODO: long key = node_del(q);
      // printf("Removed element: %d\n", key);
    } else {
      // handle unknown command
      fprintf(stderr, "Got unknown command %s\n", cmd);
    }

    dump_heap(q);

  }

  if (!q) {
    node_destroy(q);
  }

  return 0;
}
