// File: /workspace/github_cpp_makefile_star2_O2/Ahhgust[P]STRaitRazor/trie.cpp
// Function: Trie::makeTrieFromConfig(std::vector<Config, std::allocator<Config>>*, unsigned int, unsigned char, unsigned char)
void
Trie::makeTrieFromConfig(vector<Config> *c, unsigned numStrs, unsigned char distance, unsigned char motifDistance) {
  unsigned i, nf, nr, memNeeded=0;

  if (distance >2) {
    cerr << "Sorry, the max anchor distance supported with trie-search is 2; " << distance   << " is too big!" << endl;
    exit(EXIT_FAILURE);
  } else if (motifDistance > 1) {
    cerr << "Sorry, the max motif distance supported with trie-search is 1; " << motifDistance   << " is too big!" << endl;
    exit(EXIT_FAILURE);
  }

  // make a table of IUPAC codes
  char IUPAC[255][2];
  memset(IUPAC, 0, 255+255);
  IUPAC[ (int)'R'][0] = 'A';
  IUPAC[ (int)'R'][1] = 'G';

  IUPAC[ (int)'Y'][0] = 'C';
  IUPAC[ (int)'Y'][1] = 'T';

  IUPAC[ (int)'S'][0] = 'G';
  IUPAC[ (int)'S'][1] = 'C';

  IUPAC[ (int)'W'][0] = 'A';
  IUPAC[ (int)'W'][1] = 'T';

  IUPAC[ (int)'K'][0] = 'G';
  IUPAC[ (int)'K'][1] = 'T';

  IUPAC[ (int)'M'][0] = 'A';
  IUPAC[ (int)'M'][1] = 'C';

  // compute an (upper-bound) on the number of nodes in the trie
  for (i=0; i < numStrs; ++i) {
    // math for the memory needed for a hamming distance of 1:
    // N = length of string + 1 (ie, including \0)
    // entering that string requires at most N nodes.
    // entering all the 1-base substitutions on that string requires
    // 3*N for all the substitutions on the 0th positoin
    // 3*(N-1) for all of the substutitions on the 1st position (previous position 0 is already in the trie)
    // 3*(N-2) for all of the subs on the second position (previous 2 positions are in the trie) 
    // ...
    // 3 
    // which is equal to:
    // N + 3N + (3(N)(N-1))/2
    //memNeeded += (2*c[i].forwardLength + 2) + (3* (c[i].reverseLength+2)* (c[i].reverseLength+3))/2;
    //memNeeded += (2*c[i].reverseLength + 2) + (3* (c[i].forwardLength+2)* (c[i].forwardLength+3))/2;

    // we have the forwardFlank twice (8N) (+ and - strand)
    // and again for the reverse flank
    nf = (8*((*c)[i].forwardLength+1)) + 3* ((*c)[i].forwardLength)*((*c)[i].forwardLength-1);
    nr = (8*((*c)[i].reverseLength+1)) + 3* ((*c)[i].reverseLength)*((*c)[i].reverseLength-1);


    const char *s = (*c)[i].forwardFlank.c_str();
    unsigned nfAmbig=0;
    for (unsigned j = 0; j < (*c)[i].forwardLength; ++j, ++s) { // adjust the memory for IUPAC codes (double the memory for each IUPAC code)
      if ( IUPAC[(int)*s][0] != 0) {
        nf = nf + nf;
        ++nfAmbig;
      }
    }

    if (nfAmbig > 1) {
      cerr << endl << "At most 1 ambiguity code is supported per anchor." << endl 
           << "Problem with locus: " << (*c)[i].locusName << " Anchor " << (*c)[i].forwardFlank << endl << endl;
      exit(EXIT_FAILURE);
    }

    s = (*c)[i].reverseFlank.c_str();
    unsigned nrAmbig=0;
    for (unsigned j = 0; j < (*c)[i].reverseLength; ++j, ++s) { // adjust the memory for IUPAC codes (double the memory for each IUPAC code)
      if ( IUPAC[(int)*s][0] != 0) {
        nr = nr + nr;
        ++nrAmbig;
      }
    }



    if (nrAmbig > 1) {
      cerr << endl << "At most 1 ambiguity code is supported per anchor." << endl <<
        "Problem with locus: " << (*c)[i].locusName << " Anchor " << (*c)[i].reverseFlank << endl << endl;
      exit(EXIT_FAILURE);
    }
    
    if (distance == 0) {
      memNeeded += ((*c)[i].forwardLength+1)*(2*(nfAmbig+1)) + ((*c)[i].reverseLength+1)*(2*(nrAmbig+1));
    } else if (distance == 1) {
      memNeeded += nf + nr;
    } else if (distance == 2) {
      // got lazy with this one; wolfram alpha was used to simplify the sum:
      // sum i=1 to N (i)(i-1)
      // which is the (worst-case) memory needed to add a word of length N and all 2-permutations of it
      memNeeded += (nfAmbig*nfAmbig+1)*6*((*c)[i].forwardLength)*((*c)[i].forwardLength+1)*((*c)[i].forwardLength+2);
      memNeeded += (nrAmbig*nrAmbig+1)*6*((*c)[i].reverseLength)*((*c)[i].reverseLength+1)*((*c)[i].reverseLength-1);
    }

    memNeeded += ((*c)[i].motifLength+1) *2; // the motifs are also added
    if (motifDistance == 1) {
      memNeeded += (8*((*c)[i].motifLength+1)) + 3* ((*c)[i].motifLength)*((*c)[i].motifLength-1);
    }
  }

  initMem(memNeeded);

  for (i=0; i < numStrs; ++i) {

    int numAmbig=0;
    string s =  (*c)[i].forwardFlank;
    for (unsigned j= 0; j < (*c)[i].forwardLength; ++j) {
      if ( IUPAC[(int)s.at(j)][0] != 0) {

        int iupac = (int)s.at(j);

        s[j] = IUPAC[ iupac ][0]; // overwrite the ambiguity code with the first form, then add to trie
        addPermutations(s, (*c)[i].forwardLength, i, (unsigned char) FORWARDFLANK,
                        (unsigned char) FORWARDFLANK_RC, distance);
        
        
        s[j] = IUPAC[ iupac ][1]; // overwrite the ambiguity code with the second form, then add to trie
        addPermutations(s, (*c)[i].forwardLength, i, (unsigned char) FORWARDFLANK,
                        (unsigned char) FORWARDFLANK_RC, distance);
        
        ++numAmbig;
        break;
      }
    }
    
    if (numAmbig==0) {

      addPermutations((*c)[i].forwardFlank, (*c)[i].forwardLength, i, (unsigned char) FORWARDFLANK,
                      (unsigned char) FORWARDFLANK_RC, distance);
    }
    numAmbig=0;
    s =  (*c)[i].reverseFlank;
    for (unsigned j= 0; j < (*c)[i].reverseLength; ++j) {
      if ( IUPAC[(int)s.at(j)][0] != 0) {

        int iupac = (int)s.at(j);

        s[j] = IUPAC[ iupac ][0]; // overwrite the ambiguity code with the first form, then add to trie
        addPermutations(s, (*c)[i].reverseLength, i, (unsigned char) REVERSEFLANK, 
                        (unsigned char) REVERSEFLANK_RC, distance);
        
        s[j] = IUPAC[ iupac ][1]; // overwrite the ambiguity code with the second form, then add to trie
        addPermutations(s, (*c)[i].reverseLength, i, (unsigned char) REVERSEFLANK, 
                        (unsigned char) REVERSEFLANK_RC, distance);
        
        ++numAmbig;
        break;
      }
    }


    // and the reverse flank (and its RC)
    if (numAmbig==0)
      addPermutations((*c)[i].reverseFlank, (*c)[i].reverseLength, i, (unsigned char) REVERSEFLANK, 
                      (unsigned char) REVERSEFLANK_RC, distance);
    
    if (motifDistance==0) {
    // add the motif (no degeneracy in this)
      addWord((*c)[i].strMotif.c_str(), (*c)[i].motifLength, i, MOTIF);
      addWordRC((*c)[i].strMotif.c_str(), (*c)[i].motifLength, i, MOTIF_RC);
    } else {
      addPermutations((*c)[i].strMotif, (*c)[i].motifLength, i, (unsigned char) MOTIF, (unsigned char) MOTIF_RC, motifDistance);
    }
  } 
  
  //  cerr << memNeeded << " bytes asked for ; Mem unused: " << memNeeded - (mem-root) << endl;

  if (mem-root > (int) memNeeded) {
    cerr << "Error with the maths. Email the author (August) to fix this!" << endl;
    exit(1);
  }
  
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x348, %rsp            # imm = 0x348
movl %edx, 0x30(%rsp)
movq %rdi, 0x20(%rsp)
movzbl %cl, %eax
movl %eax, 0x14(%rsp)
movl %ecx, 0x38(%rsp)
cmpb $0x3, %cl
jae 0x9554
movl %r8d, %r15d
movzbl %r15b, %eax
movl %eax, 0x2c(%rsp)
cmpb $0x2, %r15b
jae 0x9570
movq %rsi, %rbx
leaq 0x140(%rsp), %r13
xorl %r14d, %r14d
movl $0x1fe, %edx            # imm = 0x1FE
movq %r13, %rdi
xorl %esi, %esi
callq 0x3170
movw $0x5443, 0xb2(%r13)     # imm = 0x5443
movl $0x43474741, 0xa4(%r13) # imm = 0x43474741
movw $0x5441, 0xae(%r13)     # imm = 0x5441
movw $0x5447, 0x96(%r13)     # imm = 0x5447
movw $0x4341, 0x9a(%r13)     # imm = 0x4341
xorl %eax, %eax
movl %r15d, 0x28(%rsp)
cmpl 0x30(%rsp), %eax
je 0x909b
movq %r14, %r9
movl %eax, %ecx
movq (%rbx), %r10
imulq $0xb8, %rcx, %r13
leaq (%r10,%r13), %rdx
movl 0xa0(%r10,%r13), %esi
leal (%rsi,%rsi,2), %r8d
addl $0x5, %r8d
imull %esi, %r8d
addl $0x8, %r8d
movl 0xa4(%r10,%r13), %edi
leal -0x1(%rdi), %ecx
movl %ecx, 0x18(%rsp)
leal (%rdi,%rdi,2), %r11d
addl $0x5, %r11d
imull %edi, %r11d
movq 0x40(%r10,%r13), %r15
xorl %r14d, %r14d
xorl %r10d, %r10d
cmpl %r14d, %esi
je 0x8fb3
movsbq (%r15,%r14), %rbp
xorl %ecx, %ecx
cmpb $0x0, 0x140(%rsp,%rbp,2)
setne %cl
addl %ecx, %r10d
shll %cl, %r8d
incq %r14
jmp 0x8f91
cmpl $0x1, %r10d
ja 0x947e
addl $0x8, %r11d
movq 0x60(%rdx), %r15
xorl %r14d, %r14d
xorl %ebp, %ebp
cmpl %r14d, %edi
je 0x8fec
movsbq (%r15,%r14), %r12
xorl %ecx, %ecx
cmpb $0x0, 0x140(%rsp,%r12,2)
setne %cl
shll %cl, %r11d
addl %ecx, %ebp
incq %r14
jmp 0x8fca
cmpl $0x1, %ebp
ja 0x94da
cmpb $0x1, 0x38(%rsp)
movl 0x28(%rsp), %r15d
je 0x902a
cmpl $0x0, 0x14(%rsp)
jne 0x9032
incl %esi
leal 0x2(,%r10,2), %r8d
imull %esi, %r8d
incl %edi
leal 0x2(,%rbp,2), %ecx
imull %edi, %ecx
addl %r9d, %r8d
addl %ecx, %r8d
jmp 0x9070
addl %r9d, %r8d
addl %r11d, %r8d
jmp 0x9070
imull %r10d, %r10d
imull $0x6, %r10d, %ecx
addl $0x6, %ecx
leal 0x1(%rsi), %r8d
imull %esi, %r8d
addl $0x2, %esi
imull %r8d, %esi
imull %ecx, %esi
addl %r9d, %esi
imull %ebp, %ebp
imull $0x6, %ebp, %ecx
addl $0x6, %ecx
leal 0x1(%rdi), %r8d
imull %edi, %r8d
imull 0x18(%rsp), %r8d
imull %ecx, %r8d
addl %esi, %r8d
movl 0xa8(%rdx), %ecx
leal (%r8,%rcx,2), %r14d
addl $0x2, %r14d
cmpb $0x1, %r15b
jne 0x9094
leal (%rcx,%rcx,2), %edx
addl $0x5, %edx
imull %ecx, %edx
addl %edx, %r14d
addl $0x8, %r14d
incl %eax
jmp 0x8f36
movq 0x20(%rsp), %rdi
movq %r14, 0x38(%rsp)
movl %r14d, %esi
callq 0x889c
movl 0x30(%rsp), %eax
movq %rax, 0x30(%rsp)
xorl %ecx, %ecx
leaq 0x40(%rsp), %r14
leaq 0x60(%rsp), %r12
cmpq 0x30(%rsp), %rcx
je 0x944a
movq (%rbx), %rax
movq %rcx, 0x18(%rsp)
imulq $0xb8, %rcx, %rbp
leaq (%rax,%rbp), %rsi
addq $0x40, %rsi
movq %r14, %rdi
callq 0x3320
pushq $-0x1
popq %r13
incq %r13
movq (%rbx), %rax
movl 0xa0(%rax,%rbp), %ecx
cmpq %rcx, %r13
jae 0x91eb
movq %r14, %rdi
movq %r13, %rsi
callq 0x34b0
movsbq (%rax), %rax
cmpb $0x0, 0x140(%rsp,%rax,2)
je 0x90f0
movq %r14, %rdi
movq %r13, %rsi
callq 0x34b0
movsbq (%rax), %r15
movb 0x140(%rsp,%r15,2), %al
movq 0x40(%rsp), %rcx
movb %al, (%rcx,%r13)
leaq 0x120(%rsp), %rdi
movq %r14, %rsi
callq 0x3320
movq (%rbx), %rax
movl 0xa0(%rax,%rbp), %edx
movl 0x14(%rsp), %eax
movl %eax, (%rsp)
movq 0x20(%rsp), %rdi
leaq 0x120(%rsp), %r12
movq %r12, %rsi
movq 0x18(%rsp), %rcx
xorl %r8d, %r8d
pushq $0x1
popq %r9
callq 0x8bc6
movq %r12, %rdi
callq 0x3110
movb 0x141(%rsp,%r15,2), %al
movq 0x40(%rsp), %rcx
movb %al, (%rcx,%r13)
leaq 0x100(%rsp), %rdi
movq %r14, %rsi
callq 0x3320
movq (%rbx), %rax
movl 0xa0(%rax,%rbp), %edx
movl 0x14(%rsp), %eax
movl %eax, (%rsp)
movq 0x20(%rsp), %rdi
leaq 0x100(%rsp), %r15
movq %r15, %rsi
movq 0x18(%rsp), %rcx
xorl %r8d, %r8d
pushq $0x1
popq %r9
callq 0x8bc6
movq %r15, %rdi
movl 0x28(%rsp), %r15d
leaq 0x60(%rsp), %r12
jmp 0x9235
leaq (%rax,%rbp), %rsi
addq $0x40, %rsi
leaq 0xe0(%rsp), %rdi
callq 0x3320
movq (%rbx), %rax
movl 0xa0(%rax,%rbp), %edx
movl 0x14(%rsp), %eax
movl %eax, (%rsp)
movq 0x20(%rsp), %rdi
leaq 0xe0(%rsp), %r13
movq %r13, %rsi
movq 0x18(%rsp), %rcx
xorl %r8d, %r8d
pushq $0x1
popq %r9
callq 0x8bc6
movq %r13, %rdi
callq 0x3110
movq (%rbx), %rax
leaq (%rax,%rbp), %rsi
addq $0x60, %rsi
movq %r14, %rdi
callq 0x3160
pushq $-0x1
popq %r13
incq %r13
movq (%rbx), %rax
movl 0xa4(%rax,%rbp), %ecx
cmpq %rcx, %r13
jae 0x934e
movq %r14, %rdi
movq %r13, %rsi
callq 0x34b0
movsbq (%rax), %rax
cmpb $0x0, 0x140(%rsp,%rax,2)
je 0x9251
movq %r14, %rdi
movq %r13, %rsi
callq 0x34b0
movsbq (%rax), %r15
movb 0x140(%rsp,%r15,2), %al
movq 0x40(%rsp), %rcx
movb %al, (%rcx,%r13)
leaq 0xc0(%rsp), %rdi
movq %r14, %rsi
callq 0x3320
movq (%rbx), %rax
movl 0xa4(%rax,%rbp), %edx
movl 0x14(%rsp), %eax
movl %eax, (%rsp)
movq 0x20(%rsp), %rdi
leaq 0xc0(%rsp), %r12
movq %r12, %rsi
movq 0x18(%rsp), %rcx
pushq $0x3
popq %r8
pushq $0x2
popq %r9
callq 0x8bc6
movq %r12, %rdi
callq 0x3110
movb 0x141(%rsp,%r15,2), %al
movq 0x40(%rsp), %rcx
movb %al, (%rcx,%r13)
leaq 0xa0(%rsp), %rdi
movq %r14, %rsi
callq 0x3320
movq (%rbx), %rax
movl 0xa4(%rax,%rbp), %edx
movl 0x14(%rsp), %eax
movl %eax, (%rsp)
movq 0x20(%rsp), %rdi
leaq 0xa0(%rsp), %r15
movq %r15, %rsi
movq 0x18(%rsp), %rcx
pushq $0x3
popq %r8
pushq $0x2
popq %r9
callq 0x8bc6
movq %r15, %rdi
movl 0x28(%rsp), %r15d
leaq 0x60(%rsp), %r12
jmp 0x9399
leaq (%rax,%rbp), %rsi
addq $0x60, %rsi
leaq 0x80(%rsp), %rdi
callq 0x3320
movq (%rbx), %rax
movl 0xa4(%rax,%rbp), %edx
movl 0x14(%rsp), %eax
movl %eax, (%rsp)
movq 0x20(%rsp), %rdi
leaq 0x80(%rsp), %r13
movq %r13, %rsi
movq 0x18(%rsp), %rcx
pushq $0x3
popq %r8
pushq $0x2
popq %r9
callq 0x8bc6
movq %r13, %rdi
callq 0x3110
movq (%rbx), %rax
testb %r15b, %r15b
je 0x93ee
leaq (%rax,%rbp), %rsi
addq $0x80, %rsi
movq %r12, %rdi
callq 0x3320
movq (%rbx), %rax
movl 0xa8(%rax,%rbp), %edx
movl 0x2c(%rsp), %eax
movl %eax, (%rsp)
movq 0x20(%rsp), %rdi
movq %r12, %rsi
movq 0x18(%rsp), %rcx
pushq $0x4
popq %r8
pushq $0x5
popq %r9
callq 0x8bc6
movq %r12, %rdi
callq 0x3110
jmp 0x9435
movq 0x80(%rax,%rbp), %rsi
movl 0xa8(%rax,%rbp), %edx
movq 0x20(%rsp), %rdi
movq 0x18(%rsp), %rcx
pushq $0x4
popq %r8
callq 0x88de
movq (%rbx), %rax
movq 0x80(%rax,%rbp), %rsi
movl 0xa8(%rax,%rbp), %edx
movq 0x20(%rsp), %rdi
movq 0x18(%rsp), %rcx
pushq $0x5
popq %r8
callq 0x8a14
movq %r14, %rdi
callq 0x3110
movq 0x18(%rsp), %rcx
incq %rcx
jmp 0x90c2
movq 0x20(%rsp), %rcx
movq 0x8(%rcx), %rax
subq (%rcx), %rax
pushq $0x30
popq %rcx
cqto
idivq %rcx
movslq 0x38(%rsp), %rcx
cmpq %rcx, %rax
jg 0x959b
addq $0x348, %rsp            # imm = 0x348
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x5b6b(%rip), %rdi      # 0xeff0
callq 0x3130
leaq 0x1aa1(%rip), %rsi      # 0xaf32
movq %rax, %rdi
callq 0x3240
movq %rax, %rdi
callq 0x3130
leaq 0x1abc(%rip), %rsi      # 0xaf64
movq %rax, %rdi
callq 0x3240
movq (%rbx), %rsi
addq %r13, %rsi
movq %rax, %rdi
callq 0x3220
leaq 0x1ab4(%rip), %rsi      # 0xaf79
movq %rax, %rdi
callq 0x3240
movq (%rbx), %rcx
leaq (%rcx,%r13), %rsi
addq $0x40, %rsi
jmp 0x9534
movq 0x5b0f(%rip), %rdi      # 0xeff0
callq 0x3130
leaq 0x1a45(%rip), %rsi      # 0xaf32
movq %rax, %rdi
callq 0x3240
movq %rax, %rdi
callq 0x3130
leaq 0x1a60(%rip), %rsi      # 0xaf64
movq %rax, %rdi
callq 0x3240
movq (%rbx), %rsi
addq %r13, %rsi
movq %rax, %rdi
callq 0x3220
leaq 0x1a58(%rip), %rsi      # 0xaf79
movq %rax, %rdi
callq 0x3240
movq (%rbx), %rcx
leaq (%rcx,%r13), %rsi
addq $0x60, %rsi
movq %rax, %rdi
callq 0x3220
movq %rax, %rdi
callq 0x3130
movq %rax, %rdi
callq 0x3130
pushq $0x1
popq %rdi
callq 0x32e0
movq 0x5a95(%rip), %rdi      # 0xeff0
leaq 0x1942(%rip), %rsi      # 0xaea4
callq 0x3240
movq %rax, %rdi
movl 0x14(%rsp), %esi
jmp 0x958a
movq 0x5a79(%rip), %rdi      # 0xeff0
leaq 0x1974(%rip), %rsi      # 0xaef2
callq 0x3240
movq %rax, %rdi
movl 0x2c(%rsp), %esi
callq 0x33a0
leaq 0x194f(%rip), %rsi      # 0xaee5
movq %rax, %rdi
jmp 0x95a9
movq 0x5a4e(%rip), %rdi      # 0xeff0
leaq 0x19d9(%rip), %rsi      # 0xaf82
callq 0x3240
jmp 0x9544
movq %rax, %rbx
leaq 0xc0(%rsp), %rdi
jmp 0x9606
movq %rax, %rbx
leaq 0xa0(%rsp), %rdi
jmp 0x9606
movq %rax, %rbx
leaq 0x120(%rsp), %rdi
jmp 0x9606
movq %rax, %rbx
leaq 0x100(%rsp), %rdi
jmp 0x9606
movq %rax, %rbx
leaq 0x80(%rsp), %rdi
jmp 0x9606
movq %rax, %rbx
leaq 0xe0(%rsp), %rdi
jmp 0x9606
movq %rax, %rbx
leaq 0x60(%rsp), %rdi
callq 0x3110
jmp 0x9618
jmp 0x9615
jmp 0x9615
jmp 0x9615
jmp 0x9615
movq %rax, %rbx
leaq 0x40(%rsp), %rdi
callq 0x3110
movq %rbx, %rdi
callq 0x3440