// File: AlgoLab[P]bwt-lcp-parallel/bwt_lcp.cpp
// Function: main
int main(int argc, char *argv[]) {
  // Initialization
  gzFile fp;
  kseq_t *seq;

  // Error if no file is given as input
  if (argc < 2 || argc > 3) {
    std::cerr << "Usage: " << argv[0] << " <in.fasta> [<nthreads>]" << std::endl;
    return 1;
  }

  if (argc == 3) {
    int nthreads = std::atoi(argv[2]);
    if (nthreads <= 0) {
      std::cerr << "Usage: " << argv[0] << " <in.fasta> [<nthreads>]" << std::endl;
      std::cerr << "nthreads cannot be less than 1. Given: " << nthreads << std::endl;
      return 1;
    }
    concurrency_level = static_cast<unsigned>(nthreads);
  } else {
    unsigned ncores = std::thread::hardware_concurrency();
    concurrency_level = ncores == 0 ? 1 : std::min(ncores, 4u);
  }
  std::cout << "Using " << concurrency_level << " threads." << std::endl;

  fp = gzopen(argv[1], "r");
  seq = kseq_init(fp);

  strnum_t read_num = 0;
  int maxl = 0;

  {
    // int is required by library kseq
    int l = 0;

    // Calculate the length of the longest read
    while ((l = kseq_read(seq)) >= 0) {
      ++read_num;
      if (l > maxl) maxl = l;
    }

    if (maxl > 254) {
      std::cerr << "Input reads are too long! Current = "
                << maxl << ", max = 254"
                << std::endl;
      kseq_destroy(seq);
      gzclose(fp);
      return 1;
    }
  }

  const strlen_t read_max_length = static_cast<strlen_t>(maxl);

  std::cout << "longest read length = " << static_cast<fuint_t>(read_max_length) << std::endl;
  std::cout << "number of reads = " << read_num << std::endl;

  const fnames_t S_tpl= template_generator("supportfile-S%.3d.tmp", 0, read_max_length+1);
  const fnames_t B_tpl= template_generator("supportfile-B%.3d.tmp", 0, read_max_length+1);
  const fname_t IXk_name("supportfile-IXk.tmp");

  std::cout << "Preparing arrays S_l..." << std::endl;
  occ_countv_t occv(read_max_length+1);
  {
    multi_enc_fasta_writer_t S(S_tpl);
    kseq_rewind(seq);
    gzrewind(fp);

    int l = 0;
    while ((l = kseq_read(seq)) >= 0) {
      const strlen_t len = static_cast<strlen_t>(l);
      for (strlen_t i = 0; i <= len; ++i) {
        const enc_nucl_t c = encode(seq->seq.s[len-i]);
        S.write(i, c);
        ++occv[i][c];
      }
      for (strlen_t i = len+1; i <= read_max_length; ++i) {
        S.write(i, ALPHSIZE-1);
        ++occv[i][ALPHSIZE-1];
      }
    }

  }

  kseq_destroy(seq);
  gzclose(fp);

  std::cout << "Computing partial BWT..." << std::endl;
  compute_partial_BWT(read_max_length, read_num, S_tpl, B_tpl);
  remove_files(S_tpl);

  std::cout << "Computing interleave and LCP..." << std::endl;
  compute_interleave_LCP(read_max_length, read_num, occv, B_tpl, IXk_name);

  std::cout << "Computing BWT..." << std::endl;
  compute_BWT(read_max_length, read_num, B_tpl, IXk_name);

  std::cout << "Done." << std::endl;

  return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x1d0, %rsp            # imm = 0x1D0
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
cmpl $0x2, -0x8(%rbp)
jl 0x69c5
cmpl $0x3, -0x8(%rbp)
jle 0x6a11
movq 0x20624(%rip), %rdi     # 0x26ff0
leaq 0x127d8(%rip), %rsi     # 0x191ab
callq 0x3290
movq %rax, %rdi
movq -0x10(%rbp), %rax
movq (%rax), %rsi
callq 0x3290
movq %rax, %rdi
leaq 0x127c2(%rip), %rsi     # 0x191b3
callq 0x3290
movq %rax, %rdi
movq 0x205b8(%rip), %rsi     # 0x26fb8
callq 0x32d0
movl $0x1, -0x4(%rbp)
jmp 0x7262
cmpl $0x3, -0x8(%rbp)
jne 0x6ab5
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rdi
callq 0x3410
movl %eax, -0x24(%rbp)
cmpl $0x0, -0x24(%rbp)
jg 0x6aaa
movq 0x205b8(%rip), %rdi     # 0x26ff0
leaq 0x1276c(%rip), %rsi     # 0x191ab
callq 0x3290
movq %rax, %rdi
movq -0x10(%rbp), %rax
movq (%rax), %rsi
callq 0x3290
movq %rax, %rdi
leaq 0x12756(%rip), %rsi     # 0x191b3
callq 0x3290
movq %rax, %rdi
movq 0x2054c(%rip), %rsi     # 0x26fb8
callq 0x32d0
movq 0x20578(%rip), %rdi     # 0x26ff0
leaq 0x1274d(%rip), %rsi     # 0x191cc
callq 0x3290
movq %rax, %rdi
movl -0x24(%rbp), %esi
callq 0x3470
movq %rax, %rdi
movq 0x2051f(%rip), %rsi     # 0x26fb8
callq 0x32d0
movl $0x1, -0x4(%rbp)
jmp 0x7262
movl -0x24(%rbp), %eax
movl %eax, 0x207f5(%rip)     # 0x272a8
jmp 0x6af8
callq 0x33b0
movl %eax, -0x28(%rbp)
cmpl $0x0, -0x28(%rbp)
jne 0x6ad0
movl $0x1, %eax
movl %eax, -0x15c(%rbp)
jmp 0x6aec
movl $0x4, -0x2c(%rbp)
leaq -0x28(%rbp), %rdi
leaq -0x2c(%rbp), %rsi
callq 0xab50
movl (%rax), %eax
movl %eax, -0x15c(%rbp)
movl -0x15c(%rbp), %eax
movl %eax, 0x207b0(%rip)     # 0x272a8
movq 0x204d1(%rip), %rdi     # 0x26fd0
leaq 0x126ee(%rip), %rsi     # 0x191f4
callq 0x3290
movq %rax, %rdi
movl 0x20794(%rip), %esi     # 0x272a8
callq 0x3390
movq %rax, %rdi
leaq 0x126d8(%rip), %rsi     # 0x191fb
callq 0x3290
movq %rax, %rdi
movq 0x20486(%rip), %rsi     # 0x26fb8
callq 0x32d0
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdi
leaq 0x12bd4(%rip), %rsi     # 0x1971a
callq 0x33f0
movq %rax, -0x18(%rbp)
movq -0x18(%rbp), %rdi
callq 0x7280
movq %rax, -0x20(%rbp)
movl $0x0, -0x30(%rbp)
movl $0x0, -0x34(%rbp)
movl $0x0, -0x38(%rbp)
movq -0x20(%rbp), %rdi
callq 0x72c0
movl %eax, -0x38(%rbp)
cmpl $0x0, %eax
jl 0x6b9b
movl -0x30(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x30(%rbp)
movl -0x38(%rbp), %eax
cmpl -0x34(%rbp), %eax
jle 0x6b99
movl -0x38(%rbp), %eax
movl %eax, -0x34(%rbp)
jmp 0x6b71
cmpl $0xfe, -0x34(%rbp)
jle 0x6bfe
movq 0x20445(%rip), %rdi     # 0x26ff0
leaq 0x12653(%rip), %rsi     # 0x19205
callq 0x3290
movq %rax, %rdi
movl -0x34(%rbp), %esi
callq 0x3470
movq %rax, %rdi
leaq 0x1265e(%rip), %rsi     # 0x1922a
callq 0x3290
movq %rax, %rdi
movq 0x203dd(%rip), %rsi     # 0x26fb8
callq 0x32d0
movq -0x20(%rbp), %rdi
callq 0x76b0
movq -0x18(%rbp), %rdi
callq 0x3450
movl $0x1, -0x4(%rbp)
jmp 0x7262
movb -0x34(%rbp), %al
movb %al, -0x39(%rbp)
movq 0x203c5(%rip), %rdi     # 0x26fd0
movq %rdi, -0x178(%rbp)
leaq 0x1261d(%rip), %rsi     # 0x19236
callq 0x3290
movq %rax, %rdi
movzbl -0x39(%rbp), %eax
movl %eax, %esi
callq 0x3060
movq %rax, %rdi
movq 0x20382(%rip), %rsi     # 0x26fb8
movq %rsi, -0x170(%rbp)
callq 0x32d0
movq -0x178(%rbp), %rdi
leaq 0x125fd(%rip), %rsi     # 0x1924d
callq 0x3290
movq %rax, %rdi
movl -0x30(%rbp), %esi
callq 0x3390
movq -0x170(%rbp), %rsi
movq %rax, %rdi
callq 0x32d0
leaq -0x79(%rbp), %rdi
movq %rdi, -0x168(%rbp)
callq 0x3490
movq -0x168(%rbp), %rdx
leaq 0x125d3(%rip), %rsi     # 0x19260
leaq -0x78(%rbp), %rdi
callq 0x7fd0
jmp 0x6c98
movzbl -0x39(%rbp), %ecx
incl %ecx
leaq -0x58(%rbp), %rdi
leaq -0x78(%rbp), %rsi
xorl %edx, %edx
callq 0x3650
jmp 0x6caf
leaq -0x78(%rbp), %rdi
callq 0x3170
leaq -0x79(%rbp), %rdi
callq 0x3300
leaq -0xc9(%rbp), %rdi
movq %rdi, -0x180(%rbp)
callq 0x3490
movq -0x180(%rbp), %rdx
leaq 0x12594(%rip), %rsi     # 0x19276
leaq -0xc8(%rbp), %rdi
callq 0x7fd0
jmp 0x6cf0
movzbl -0x39(%rbp), %ecx
incl %ecx
leaq -0xa8(%rbp), %rdi
leaq -0xc8(%rbp), %rsi
xorl %edx, %edx
callq 0x3650
jmp 0x6d0d
leaq -0xc8(%rbp), %rdi
callq 0x3170
leaq -0xc9(%rbp), %rdi
callq 0x3300
leaq -0xf1(%rbp), %rdi
movq %rdi, -0x188(%rbp)
callq 0x3490
movq -0x188(%rbp), %rdx
leaq 0x12546(%rip), %rsi     # 0x1928c
leaq -0xf0(%rbp), %rdi
callq 0x7fd0
jmp 0x6d54
leaq -0xf1(%rbp), %rdi
callq 0x3300
movq 0x20269(%rip), %rdi     # 0x26fd0
leaq 0x12532(%rip), %rsi     # 0x192a0
callq 0x3290
movq %rax, -0x190(%rbp)
jmp 0x6d7c
movq -0x190(%rbp), %rdi
movq 0x2022e(%rip), %rsi     # 0x26fb8
callq 0x32d0
jmp 0x6d91
movzbl -0x39(%rbp), %eax
incl %eax
movq %rax, -0x1a0(%rbp)
leaq -0x111(%rbp), %rdi
movq %rdi, -0x198(%rbp)
callq 0xab90
movq -0x1a0(%rbp), %rsi
movq -0x198(%rbp), %rdx
leaq -0x110(%rbp), %rdi
callq 0xabb0
jmp 0x6dcd
leaq -0x111(%rbp), %rdi
callq 0xac20
leaq 0x12264(%rip), %rdx     # 0x19044
leaq -0x150(%rbp), %rdi
leaq -0x58(%rbp), %rsi
callq 0xac40
jmp 0x6df2
movq -0x20(%rbp), %rax
movq 0x68(%rax), %rax
movl $0x0, 0xc(%rax)
movq -0x20(%rbp), %rax
movq 0x68(%rax), %rax
movl $0x0, 0x8(%rax)
movq -0x20(%rbp), %rax
movq 0x68(%rax), %rax
movl $0x0, 0x10(%rax)
movq -0x20(%rbp), %rax
movl $0x0, 0x60(%rax)
movq -0x18(%rbp), %rdi
callq 0x3330
jmp 0x6e35
movl $0x0, -0x154(%rbp)
movq -0x20(%rbp), %rdi
callq 0x72c0
movl %eax, -0x1a4(%rbp)
jmp 0x6e50
movl -0x1a4(%rbp), %eax
movl %eax, -0x154(%rbp)
cmpl $0x0, %eax
jl 0x70b6
movl -0x154(%rbp), %eax
movb %al, -0x155(%rbp)
movb $0x0, -0x156(%rbp)
movzbl -0x156(%rbp), %eax
movzbl -0x155(%rbp), %ecx
cmpl %ecx, %eax
jg 0x703c
movq -0x20(%rbp), %rax
movq 0x40(%rax), %rax
movzbl -0x155(%rbp), %ecx
movzbl -0x156(%rbp), %edx
subl %edx, %ecx
movslq %ecx, %rcx
movsbl (%rax,%rcx), %edi
callq 0x18c60
movb %al, -0x1a5(%rbp)
jmp 0x6eba
movb -0x1a5(%rbp), %al
movb %al, -0x157(%rbp)
movzbl -0x156(%rbp), %esi
movzbl -0x157(%rbp), %edx
leaq -0x150(%rbp), %rdi
callq 0xacc0
jmp 0x6ee2
movzbl -0x156(%rbp), %eax
movl %eax, %esi
leaq -0x110(%rbp), %rdi
callq 0xad00
movq %rax, %rdi
movzbl -0x157(%rbp), %eax
movl %eax, %esi
callq 0xad20
movq (%rax), %rcx
addq $0x1, %rcx
movq %rcx, (%rax)
movb -0x156(%rbp), %al
addb $0x1, %al
movb %al, -0x156(%rbp)
jmp 0x6e78
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x88(%rbp)
movl %eax, -0x8c(%rbp)
jmp 0x6f54
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x88(%rbp)
movl %eax, -0x8c(%rbp)
leaq -0x78(%rbp), %rdi
callq 0x3170
leaq -0x79(%rbp), %rdi
callq 0x3300
jmp 0x726e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x88(%rbp)
movl %eax, -0x8c(%rbp)
jmp 0x6f94
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x88(%rbp)
movl %eax, -0x8c(%rbp)
leaq -0xc8(%rbp), %rdi
callq 0x3170
leaq -0xc9(%rbp), %rdi
callq 0x3300
jmp 0x7257
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x88(%rbp)
movl %eax, -0x8c(%rbp)
leaq -0xf1(%rbp), %rdi
callq 0x3300
jmp 0x724b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x88(%rbp)
movl %eax, -0x8c(%rbp)
jmp 0x723f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x88(%rbp)
movl %eax, -0x8c(%rbp)
leaq -0x111(%rbp), %rdi
callq 0xac20
jmp 0x723f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x88(%rbp)
movl %eax, -0x8c(%rbp)
jmp 0x7233
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x88(%rbp)
movl %eax, -0x8c(%rbp)
leaq -0x150(%rbp), %rdi
callq 0xad50
jmp 0x7233
movzbl -0x155(%rbp), %eax
addl $0x1, %eax
movb %al, -0x158(%rbp)
movzbl -0x158(%rbp), %eax
movzbl -0x39(%rbp), %ecx
cmpl %ecx, %eax
jg 0x70b1
movzbl -0x158(%rbp), %esi
leaq -0x150(%rbp), %rdi
movl $0x5, %edx
callq 0xacc0
jmp 0x7075
movzbl -0x158(%rbp), %eax
movl %eax, %esi
leaq -0x110(%rbp), %rdi
callq 0xad00
movq %rax, %rdi
movl $0x5, %esi
callq 0xad20
movq (%rax), %rcx
addq $0x1, %rcx
movq %rcx, (%rax)
movb -0x158(%rbp), %al
addb $0x1, %al
movb %al, -0x158(%rbp)
jmp 0x704c
jmp 0x6e3f
leaq -0x150(%rbp), %rdi
callq 0xad50
movq -0x20(%rbp), %rdi
callq 0x76b0
jmp 0x70cd
movq -0x18(%rbp), %rdi
callq 0x3450
jmp 0x70d8
movq 0x1fef1(%rip), %rdi     # 0x26fd0
leaq 0x121d2(%rip), %rsi     # 0x192b8
callq 0x3290
movq %rax, -0x1b0(%rbp)
jmp 0x70f4
movq -0x1b0(%rbp), %rdi
movq 0x1feb6(%rip), %rsi     # 0x26fb8
callq 0x32d0
jmp 0x7109
movzbl -0x39(%rbp), %edi
movl -0x30(%rbp), %esi
leaq -0x58(%rbp), %rdx
leaq -0xa8(%rbp), %rcx
callq 0x3910
jmp 0x7122
leaq -0x58(%rbp), %rdi
callq 0x3860
movq 0x1fe9e(%rip), %rdi     # 0x26fd0
leaq 0x12198(%rip), %rsi     # 0x192d1
callq 0x3290
movq %rax, -0x1b8(%rbp)
jmp 0x7147
movq -0x1b8(%rbp), %rdi
movq 0x1fe63(%rip), %rsi     # 0x26fb8
callq 0x32d0
jmp 0x715c
movzbl -0x39(%rbp), %edi
movl -0x30(%rbp), %esi
leaq -0x110(%rbp), %rdx
leaq -0xa8(%rbp), %rcx
leaq -0xf0(%rbp), %r8
callq 0x4e80
jmp 0x717f
movq 0x1fe4a(%rip), %rdi     # 0x26fd0
leaq 0x12164(%rip), %rsi     # 0x192f1
callq 0x3290
movq %rax, -0x1c0(%rbp)
jmp 0x719b
movq -0x1c0(%rbp), %rdi
movq 0x1fe0f(%rip), %rsi     # 0x26fb8
callq 0x32d0
jmp 0x71b0
movzbl -0x39(%rbp), %edi
movl -0x30(%rbp), %esi
leaq -0xa8(%rbp), %rdx
leaq -0xf0(%rbp), %rcx
callq 0x6730
jmp 0x71cc
movq 0x1fdfd(%rip), %rdi     # 0x26fd0
leaq 0x12128(%rip), %rsi     # 0x19302
callq 0x3290
movq %rax, -0x1c8(%rbp)
jmp 0x71e8
movq -0x1c8(%rbp), %rdi
movq 0x1fdc2(%rip), %rsi     # 0x26fb8
callq 0x32d0
jmp 0x71fd
movl $0x0, -0x4(%rbp)
leaq -0x110(%rbp), %rdi
callq 0xad80
leaq -0xf0(%rbp), %rdi
callq 0x3170
leaq -0xa8(%rbp), %rdi
callq 0x7e90
leaq -0x58(%rbp), %rdi
callq 0x7e90
jmp 0x7262
leaq -0x110(%rbp), %rdi
callq 0xad80
leaq -0xf0(%rbp), %rdi
callq 0x3170
leaq -0xa8(%rbp), %rdi
callq 0x7e90
leaq -0x58(%rbp), %rdi
callq 0x7e90
jmp 0x726e
movl -0x4(%rbp), %eax
addq $0x1d0, %rsp            # imm = 0x1D0
popq %rbp
retq
movq -0x88(%rbp), %rdi
callq 0x3480
nopw (%rax,%rax)