// File: elarielcl[P]ArielsSequitur/Dictionary.cpp
// Function: Dictionary::putUnique(Node*)
void Dictionary::putUnique(Node* node) {
  Node** insertAt = this->get(node);
  if ((*insertAt) == NULL || (*insertAt) ->isGuard()){ // is there a better way?
    *insertAt = node;
    this->a++;
  }
  else {
    Node* m = *insertAt;
    if (m->digramOverlap(node)) return;

    if (m->prev->isGuard() && m->next->next->isGuard()) {

      this->grammar->grammarSize--;

      Rule* existentRule = m->prev->rule;
      existentRule->usage++;

      //Create one new node
      Node* one = new Node(existentRule, existentRule->symbol);

      // remove existent digrams in the index
      if (!node->prev->isGuard())
        this->remove(node->prev);
      if (!node->next->next->isGuard())
        this->remove(node->next);

      //Insert one
      node->prev->connect(one);
      one->connect(node->next->next);

      // put new digrams in the index
      if (!one->prev->isGuard())
        this->putUnique(one->prev);
      if (!one->next->isGuard())
        this->putUnique(one);

        //DELETING
        delete node->next;
        delete node;
        //DELETING

        // delete deprecatedOcurrences
        Node* dOcc = existentRule->guard->next; //deprecatedOccurrence
        while (!dOcc->isGuard()) {
          if(dOcc->symbol>=this->grammar->M) {
            dOcc->rule->usage--;
            if (dOcc->rule->usage <= 1) {
              this->grammar->numberOfRules--;
              this->grammar->grammarSize--;

              // remove existent digrams in the index
              if (!dOcc->prev->isGuard())
                this->remove(dOcc->prev);
              if (!dOcc->next->isGuard())
                this->remove(dOcc);

              // restructure pointers
              dOcc->prev->connect(dOcc->rule->guard->next);
              dOcc->rule->guard->prev->connect(dOcc->next);

              // put new digrams in the index
              if (!dOcc->next->isGuard())
                this->putUnique(dOcc->next->prev);
              if (!dOcc->prev->isGuard())
                this->putUnique(dOcc->prev);

              Node* next = dOcc->next;

              //DELETING
              delete dOcc->rule->guard;
              delete dOcc->rule;
              delete dOcc;
              //DELETING
              dOcc = next;
            }else dOcc = dOcc->next;
          }else dOcc = dOcc->next;
      }
    }else {
      this->grammar->numberOfRules++;
      int ruleName = (this->grammar->nextRuleName ++); // Another idea?
      Rule* newRule = new Rule(ruleName, this->grammar);
      newRule->usage = 2;

      //Create two new nodes
      Node* one = new Node(newRule, ruleName);
      Node* two = new Node(newRule, ruleName);

      // remove existent digrams in the index
      if (!node->prev->isGuard())
        this->remove(node->prev);
      if (!node->next->next->isGuard())
        this->remove(node->next);

      //Insert one
      node->prev->connect(one);
      one->connect(node->next->next);

      //Here put in the index the new digram (case not before)
      if (!one->prev->isGuard())
        this->put(one->prev); //Not recursive
      if (!one->next->isGuard())
        this->put(one); //Not recursive

      // remove existent digrams in the index
      if (!m->prev->isGuard())
        this->remove(m->prev);
      if (!m->next->next->isGuard())
        this->remove(m->next);

      //Insert two
      m->prev->connect(two);
      two->connect(m->next->next);

      //Here put in the index the new digrams (case not before)
      if (!two->prev->isGuard())
        this->put(two->prev); //Not recursive
      if (!two->next->isGuard())
        this->put(two); //Not recursive

      //Put the symbols in the new rule
      newRule->guard->connect(m);
      m->next->connect(newRule->guard);

      //DELETING
      delete node->next;
      delete node;
      //DELETING

      // delete deprecatedOcurrences
      Node* dOcc = newRule->guard->next; //deprecatedOccurrence
      while (!dOcc->isGuard()) {
        if(dOcc->symbol>=this->grammar->M) {
          dOcc->rule->usage--;
          if (dOcc->rule->usage <= 1) {
            this->grammar->grammarSize--;
            this->grammar->numberOfRules--;

            // remove existent digrams in the index
            if (!dOcc->prev->isGuard())
              this->remove(dOcc->prev);
            if (!dOcc->next->isGuard())
              this->remove(dOcc);

            // restructure pointers
            dOcc->prev->connect(dOcc->rule->guard->next);
            dOcc->rule->guard->prev->connect(dOcc->next);

            // put new digrams in the index
            if (!dOcc->next->isGuard())
              this->putUnique(dOcc->next->prev);
            if (!dOcc->prev->isGuard())
              this->putUnique(dOcc->prev);

            Node* next = dOcc->next;

            //DELETING
            delete dOcc->rule->guard;
            delete dOcc->rule;
            delete dOcc;
            //DELETING
            dOcc = next;
          }else dOcc = dOcc->next;
        }else dOcc = dOcc->next;
      }
    }
  }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x100, %rsp            # imm = 0x100
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq -0x8(%rbp), %rdi
movq %rdi, -0x88(%rbp)
movq -0x10(%rbp), %rsi
callq 0x23e0
movq %rax, -0x18(%rbp)
movq -0x18(%rbp), %rax
cmpq $0x0, (%rax)
je 0x1ad7
movq -0x18(%rbp), %rax
movq (%rax), %rdi
callq 0x3610
testb $0x1, %al
jne 0x1ad7
jmp 0x1af7
movq -0x88(%rbp), %rax
movq -0x10(%rbp), %rdx
movq -0x18(%rbp), %rcx
movq %rdx, (%rcx)
movl 0x14(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x14(%rax)
jmp 0x23c2
movq -0x18(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x20(%rbp)
movq -0x20(%rbp), %rdi
movq -0x10(%rbp), %rsi
callq 0x3660
testb $0x1, %al
jne 0x1b15
jmp 0x1b1a
jmp 0x23c2
movq -0x20(%rbp), %rax
movq 0x10(%rax), %rdi
callq 0x3610
testb $0x1, %al
jne 0x1b30
jmp 0x1ec3
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rax
movq 0x8(%rax), %rdi
callq 0x3610
testb $0x1, %al
jne 0x1b4a
jmp 0x1ec3
movq -0x88(%rbp), %rax
movq (%rax), %rax
movl 0x10(%rax), %ecx
decl %ecx
movl %ecx, 0x10(%rax)
movq -0x20(%rbp), %rax
movq 0x10(%rax), %rax
movq 0x18(%rax), %rax
movq %rax, -0x28(%rbp)
movq -0x28(%rbp), %rax
movl 0x8(%rax), %ecx
incl %ecx
movl %ecx, 0x8(%rax)
movl $0x20, %edi
callq 0x10d0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x90(%rbp)
movq -0x28(%rbp), %rsi
movl 0xc(%rsi), %edx
callq 0x35e0
jmp 0x1b9d
movq -0x90(%rbp), %rax
movq %rax, -0x30(%rbp)
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rdi
callq 0x3610
testb $0x1, %al
jne 0x1bf1
movq -0x88(%rbp), %rdi
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rsi
callq 0x2520
jmp 0x1bf1
movq -0x90(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
movl $0x20, %esi
callq 0x10e0
jmp 0x23cb
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rax
movq 0x8(%rax), %rdi
callq 0x3610
testb $0x1, %al
jne 0x1c1a
movq -0x88(%rbp), %rdi
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rsi
callq 0x2520
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rdi
movq -0x30(%rbp), %rsi
callq 0x36a0
movq -0x30(%rbp), %rdi
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rax
movq 0x8(%rax), %rsi
callq 0x36a0
movq -0x30(%rbp), %rax
movq 0x10(%rax), %rdi
callq 0x3610
testb $0x1, %al
jne 0x1c65
movq -0x88(%rbp), %rdi
movq -0x30(%rbp), %rax
movq 0x10(%rax), %rsi
callq 0x1a90
movq -0x30(%rbp), %rax
movq 0x8(%rax), %rdi
callq 0x3610
testb $0x1, %al
jne 0x1c86
movq -0x88(%rbp), %rdi
movq -0x30(%rbp), %rsi
callq 0x1a90
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x98(%rbp)
cmpq $0x0, %rax
je 0x1cac
movq -0x98(%rbp), %rdi
movl $0x20, %esi
callq 0x10e0
movq -0x10(%rbp), %rax
movq %rax, -0xa0(%rbp)
cmpq $0x0, %rax
je 0x1cce
movq -0xa0(%rbp), %rdi
movl $0x20, %esi
callq 0x10e0
movq -0x28(%rbp), %rax
movq (%rax), %rax
movq 0x8(%rax), %rax
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rdi
callq 0x3610
xorb $-0x1, %al
testb $0x1, %al
jne 0x1cf1
jmp 0x1ebe
movq -0x88(%rbp), %rcx
movq -0x48(%rbp), %rax
movl (%rax), %eax
movq (%rcx), %rcx
cmpl 0x20(%rcx), %eax
jl 0x1ead
movq -0x48(%rbp), %rax
movq 0x18(%rax), %rax
movl 0x8(%rax), %ecx
addl $-0x1, %ecx
movl %ecx, 0x8(%rax)
movq -0x48(%rbp), %rax
movq 0x18(%rax), %rax
cmpl $0x1, 0x8(%rax)
jg 0x1e9f
movq -0x88(%rbp), %rax
movq (%rax), %rcx
movl 0x18(%rcx), %edx
addl $-0x1, %edx
movl %edx, 0x18(%rcx)
movq (%rax), %rax
movl 0x10(%rax), %ecx
addl $-0x1, %ecx
movl %ecx, 0x10(%rax)
movq -0x48(%rbp), %rax
movq 0x10(%rax), %rdi
callq 0x3610
testb $0x1, %al
jne 0x1d71
movq -0x88(%rbp), %rdi
movq -0x48(%rbp), %rax
movq 0x10(%rax), %rsi
callq 0x2520
movq -0x48(%rbp), %rax
movq 0x8(%rax), %rdi
callq 0x3610
testb $0x1, %al
jne 0x1d92
movq -0x88(%rbp), %rdi
movq -0x48(%rbp), %rsi
callq 0x2520
movq -0x48(%rbp), %rax
movq 0x10(%rax), %rdi
movq -0x48(%rbp), %rax
movq 0x18(%rax), %rax
movq (%rax), %rax
movq 0x8(%rax), %rsi
callq 0x36a0
movq -0x48(%rbp), %rax
movq 0x18(%rax), %rax
movq (%rax), %rax
movq 0x10(%rax), %rdi
movq -0x48(%rbp), %rax
movq 0x8(%rax), %rsi
callq 0x36a0
movq -0x48(%rbp), %rax
movq 0x8(%rax), %rdi
callq 0x3610
testb $0x1, %al
jne 0x1df3
movq -0x88(%rbp), %rdi
movq -0x48(%rbp), %rax
movq 0x8(%rax), %rax
movq 0x10(%rax), %rsi
callq 0x1a90
movq -0x48(%rbp), %rax
movq 0x10(%rax), %rdi
callq 0x3610
testb $0x1, %al
jne 0x1e18
movq -0x88(%rbp), %rdi
movq -0x48(%rbp), %rax
movq 0x10(%rax), %rsi
callq 0x1a90
movq -0x48(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x50(%rbp)
movq -0x48(%rbp), %rax
movq 0x18(%rax), %rax
movq (%rax), %rax
movq %rax, -0xa8(%rbp)
cmpq $0x0, %rax
je 0x1e4d
movq -0xa8(%rbp), %rdi
movl $0x20, %esi
callq 0x10e0
movq -0x48(%rbp), %rax
movq 0x18(%rax), %rax
movq %rax, -0xb0(%rbp)
cmpq $0x0, %rax
je 0x1e73
movq -0xb0(%rbp), %rdi
movl $0x18, %esi
callq 0x10e0
movq -0x48(%rbp), %rax
movq %rax, -0xb8(%rbp)
cmpq $0x0, %rax
je 0x1e95
movq -0xb8(%rbp), %rdi
movl $0x20, %esi
callq 0x10e0
movq -0x50(%rbp), %rax
movq %rax, -0x48(%rbp)
jmp 0x1eab
movq -0x48(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x48(%rbp)
jmp 0x1eb9
movq -0x48(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x48(%rbp)
jmp 0x1cdd
jmp 0x23c0
movq -0x88(%rbp), %rax
movq (%rax), %rcx
movl 0x18(%rcx), %edx
incl %edx
movl %edx, 0x18(%rcx)
movq (%rax), %rcx
movl 0x1c(%rcx), %eax
movl %eax, %edx
incl %edx
movl %edx, 0x1c(%rcx)
movl %eax, -0x54(%rbp)
movl $0x18, %edi
callq 0x10d0
movq %rax, %rdi
movq -0x88(%rbp), %rax
movq %rdi, %rcx
movq %rcx, -0xc0(%rbp)
movl -0x54(%rbp), %esi
movq (%rax), %rdx
callq 0x2760
jmp 0x1f10
movq -0xc0(%rbp), %rax
movq %rax, -0x60(%rbp)
movq -0x60(%rbp), %rax
movl $0x2, 0x8(%rax)
movl $0x20, %edi
callq 0x10d0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0xc8(%rbp)
movq -0x60(%rbp), %rsi
movl -0x54(%rbp), %edx
callq 0x35e0
jmp 0x1f4b
movq -0xc8(%rbp), %rax
movq %rax, -0x68(%rbp)
movl $0x20, %edi
callq 0x10d0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0xd0(%rbp)
movq -0x60(%rbp), %rsi
movl -0x54(%rbp), %edx
callq 0x35e0
jmp 0x1f7b
movq -0xd0(%rbp), %rax
movq %rax, -0x70(%rbp)
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rdi
callq 0x3610
testb $0x1, %al
jne 0x2013
movq -0x88(%rbp), %rdi
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rsi
callq 0x2520
jmp 0x2013
movq -0xc0(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
movl $0x18, %esi
callq 0x10e0
jmp 0x23cb
movq -0xc8(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
movl $0x20, %esi
callq 0x10e0
jmp 0x23cb
movq -0xd0(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
movl $0x20, %esi
callq 0x10e0
jmp 0x23cb
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rax
movq 0x8(%rax), %rdi
callq 0x3610
testb $0x1, %al
jne 0x203c
movq -0x88(%rbp), %rdi
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rsi
callq 0x2520
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rdi
movq -0x68(%rbp), %rsi
callq 0x36a0
movq -0x68(%rbp), %rdi
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rax
movq 0x8(%rax), %rsi
callq 0x36a0
movq -0x68(%rbp), %rax
movq 0x10(%rax), %rdi
callq 0x3610
testb $0x1, %al
jne 0x2087
movq -0x88(%rbp), %rdi
movq -0x68(%rbp), %rax
movq 0x10(%rax), %rsi
callq 0x19e0
movq -0x68(%rbp), %rax
movq 0x8(%rax), %rdi
callq 0x3610
testb $0x1, %al
jne 0x20a8
movq -0x88(%rbp), %rdi
movq -0x68(%rbp), %rsi
callq 0x19e0
movq -0x20(%rbp), %rax
movq 0x10(%rax), %rdi
callq 0x3610
testb $0x1, %al
jne 0x20cd
movq -0x88(%rbp), %rdi
movq -0x20(%rbp), %rax
movq 0x10(%rax), %rsi
callq 0x2520
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rax
movq 0x8(%rax), %rdi
callq 0x3610
testb $0x1, %al
jne 0x20f6
movq -0x88(%rbp), %rdi
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rsi
callq 0x2520
movq -0x20(%rbp), %rax
movq 0x10(%rax), %rdi
movq -0x70(%rbp), %rsi
callq 0x36a0
movq -0x70(%rbp), %rdi
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rax
movq 0x8(%rax), %rsi
callq 0x36a0
movq -0x70(%rbp), %rax
movq 0x10(%rax), %rdi
callq 0x3610
testb $0x1, %al
jne 0x2141
movq -0x88(%rbp), %rdi
movq -0x70(%rbp), %rax
movq 0x10(%rax), %rsi
callq 0x19e0
movq -0x70(%rbp), %rax
movq 0x8(%rax), %rdi
callq 0x3610
testb $0x1, %al
jne 0x2162
movq -0x88(%rbp), %rdi
movq -0x70(%rbp), %rsi
callq 0x19e0
movq -0x60(%rbp), %rax
movq (%rax), %rdi
movq -0x20(%rbp), %rsi
callq 0x36a0
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rdi
movq -0x60(%rbp), %rax
movq (%rax), %rsi
callq 0x36a0
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0xd8(%rbp)
cmpq $0x0, %rax
je 0x21ac
movq -0xd8(%rbp), %rdi
movl $0x20, %esi
callq 0x10e0
movq -0x10(%rbp), %rax
movq %rax, -0xe0(%rbp)
cmpq $0x0, %rax
je 0x21ce
movq -0xe0(%rbp), %rdi
movl $0x20, %esi
callq 0x10e0
movq -0x60(%rbp), %rax
movq (%rax), %rax
movq 0x8(%rax), %rax
movq %rax, -0x78(%rbp)
movq -0x78(%rbp), %rdi
callq 0x3610
xorb $-0x1, %al
testb $0x1, %al
jne 0x21f1
jmp 0x23be
movq -0x88(%rbp), %rcx
movq -0x78(%rbp), %rax
movl (%rax), %eax
movq (%rcx), %rcx
cmpl 0x20(%rcx), %eax
jl 0x23ad
movq -0x78(%rbp), %rax
movq 0x18(%rax), %rax
movl 0x8(%rax), %ecx
addl $-0x1, %ecx
movl %ecx, 0x8(%rax)
movq -0x78(%rbp), %rax
movq 0x18(%rax), %rax
cmpl $0x1, 0x8(%rax)
jg 0x239f
movq -0x88(%rbp), %rax
movq (%rax), %rcx
movl 0x10(%rcx), %edx
addl $-0x1, %edx
movl %edx, 0x10(%rcx)
movq (%rax), %rax
movl 0x18(%rax), %ecx
addl $-0x1, %ecx
movl %ecx, 0x18(%rax)
movq -0x78(%rbp), %rax
movq 0x10(%rax), %rdi
callq 0x3610
testb $0x1, %al
jne 0x2271
movq -0x88(%rbp), %rdi
movq -0x78(%rbp), %rax
movq 0x10(%rax), %rsi
callq 0x2520
movq -0x78(%rbp), %rax
movq 0x8(%rax), %rdi
callq 0x3610
testb $0x1, %al
jne 0x2292
movq -0x88(%rbp), %rdi
movq -0x78(%rbp), %rsi
callq 0x2520
movq -0x78(%rbp), %rax
movq 0x10(%rax), %rdi
movq -0x78(%rbp), %rax
movq 0x18(%rax), %rax
movq (%rax), %rax
movq 0x8(%rax), %rsi
callq 0x36a0
movq -0x78(%rbp), %rax
movq 0x18(%rax), %rax
movq (%rax), %rax
movq 0x10(%rax), %rdi
movq -0x78(%rbp), %rax
movq 0x8(%rax), %rsi
callq 0x36a0
movq -0x78(%rbp), %rax
movq 0x8(%rax), %rdi
callq 0x3610
testb $0x1, %al
jne 0x22f3
movq -0x88(%rbp), %rdi
movq -0x78(%rbp), %rax
movq 0x8(%rax), %rax
movq 0x10(%rax), %rsi
callq 0x1a90
movq -0x78(%rbp), %rax
movq 0x10(%rax), %rdi
callq 0x3610
testb $0x1, %al
jne 0x2318
movq -0x88(%rbp), %rdi
movq -0x78(%rbp), %rax
movq 0x10(%rax), %rsi
callq 0x1a90
movq -0x78(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x80(%rbp)
movq -0x78(%rbp), %rax
movq 0x18(%rax), %rax
movq (%rax), %rax
movq %rax, -0xe8(%rbp)
cmpq $0x0, %rax
je 0x234d
movq -0xe8(%rbp), %rdi
movl $0x20, %esi
callq 0x10e0
movq -0x78(%rbp), %rax
movq 0x18(%rax), %rax
movq %rax, -0xf0(%rbp)
cmpq $0x0, %rax
je 0x2373
movq -0xf0(%rbp), %rdi
movl $0x18, %esi
callq 0x10e0
movq -0x78(%rbp), %rax
movq %rax, -0xf8(%rbp)
cmpq $0x0, %rax
je 0x2395
movq -0xf8(%rbp), %rdi
movl $0x20, %esi
callq 0x10e0
movq -0x80(%rbp), %rax
movq %rax, -0x78(%rbp)
jmp 0x23ab
movq -0x78(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x78(%rbp)
jmp 0x23b9
movq -0x78(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x78(%rbp)
jmp 0x21dd
jmp 0x23c0
jmp 0x23c2
addq $0x100, %rsp            # imm = 0x100
popq %rbp
retq
movq -0x38(%rbp), %rdi
callq 0x1190
nopw %cs:(%rax,%rax)