// File: /workspace/github_c_makefile_star2_O1/sheneman[P]clearcut/fasta.c
// Function: NJ_read_fasta
NJ_alignment *
NJ_read_fasta(NJ_ARGS *nj_args) {

  FILE *fp  = NULL;
  char *buf = NULL;
  char *ptr = NULL;
  NJ_alignment *alignment = NULL;

  char c;
  int state;
  long int index, x, seq;
  long int i;
  long int bufsize, nseqs = NJ_INITIAL_NSEQS;
  int first_sequence_flag;


  

  /* 
   * In this function, we implement a FASTA alignment parser which
   * reads in an alignment character-by-character, maintaining state
   * information which guides the parser.
   *
   * The program reads either DNA or Protein alignments.  All title lines
   * and sequences can be arbitrarily long.  Gaps can be represented by 
   * "-" or "." characters.  
   *
   * Ambiguity codes are also handled.
   * 
   */

  /* 
   * We can't handle reading fasta input unless the user explicity 
   * specifies the input type...just to be sure.
   */
  if( (!nj_args->dna_flag && !nj_args->protein_flag) ||
      (nj_args->dna_flag  &&  nj_args->protein_flag) ) {
    fprintf(stderr, "Clearcut: Explicitly specify protein or DNA\n");
    goto XIT_BAD;
  }

  /* open specified fasta file here */
  if(nj_args->stdin_flag) {
    fp = stdin;
  } else {
    fp = fopen(nj_args->infilename, "r");
    if(!fp) {
      fprintf(stderr, "Clearcut: Failed to open input FASTA file: %s\n", nj_args->infilename);
      perror("Clearcut");
      goto XIT_BAD;
    }
  }

  /* allocate the initial buffer */
  bufsize = NJ_INITIAL_BUFFER_SIZE;
  buf = (char *)calloc(bufsize, sizeof(char));
  
  /* allocate the alignment container here */
  alignment = (NJ_alignment *)calloc(1, sizeof(NJ_alignment));
  
  /* allocate initial title array */
  //  printf("allocating initial title array\n");
  alignment->titles = (char **)calloc(NJ_INITIAL_NSEQS, sizeof(char *));

  /* make sure that we successfully allocated memory */
  if(!buf || !alignment || !alignment->titles) {
    fprintf(stderr, "Clearcut: Memory allocation error in NJ_read_fasta()\n");
    goto XIT_BAD;
  }

  /* a flag */
  first_sequence_flag = 1;  
  
  index  = 0;  /* tracks the position in buffer     */
  x      = 0;  /* tracks the position on sequence   */
  seq    = 0;  /* tracks the active sequence        */

  /* intitial state of state machine */
  state  = NJ_FASTA_MODE_UNKNOWN;

  while(1) {
    
    /* get the next character */
    c = fgetc(fp);
    if(feof(fp)) {

      if(state == NJ_FASTA_MODE_SEQUENCE) {
	buf[index+1] = '\0';

	/* copy buf to alignment */
	for(i=1;i<=alignment->length;i++) {
	  alignment->data[seq*alignment->length+i-1] = buf[i];
	}
      }

      break;
    }

    /* make sure our dynamic buffer is big enough */
    if(index >= bufsize) {
      bufsize *= 2;
      buf = (char *)realloc(buf, bufsize);
      if(!buf) {
	fprintf(stderr, "Clearcut: Memory allocation error in NJ_read_fasta()\n");
	goto XIT_BAD;
      }
    }

    switch(state) {
      
    case NJ_FASTA_MODE_UNKNOWN:
      
      if(!NJ_is_whitespace(c)) {
	if(c == '>') {
	  state = NJ_FASTA_MODE_TITLE;
	  buf[0] = '>';
	} else {
	  goto XIT_BAD;
	}
      }

      break;

    case NJ_FASTA_MODE_TITLE:

      if( c == '\n' ||
	  c == '\r' ) {

	buf[index] = '\0';
	state = NJ_FASTA_MODE_SEQUENCE;
	index = 0;
	x     = -1;

	/* make sure we've allocated enough space for titles and sequences */
	if(seq == nseqs) {

	  //	  printf("realloc().  seq = %d, nseqs = %d\n", seq, nseqs);

	  nseqs *= 2;

	  alignment->titles = (char **)realloc(alignment->titles, nseqs*sizeof(char *));
	  if(!alignment->titles) {
	    fprintf(stderr, "Clearcut:  Memory allocation error in NJ_read_fasta()\n");
	    goto XIT_BAD;
	  }

	  alignment->data = (char *)realloc(alignment->data, alignment->length*nseqs*sizeof(char));
	  if(!alignment->data) {
	    fprintf(stderr, "Clearcut: Allocation error in NJ_read_fasta()\n");
	    goto XIT_BAD;
	  }
	}

	// printf("Allocating %d bytes for title %d: %s\n", (int)strlen(buf), (int)seq, buf);

	alignment->titles[seq] = (char *)calloc(strlen(buf), sizeof(char));
	if(!alignment->titles[seq]) {
	  fprintf(stderr, "Clearcut:  Memory allocation error in NJ_read_fasta()\n");
	  goto XIT_BAD;
	}

	/* lets forward to the first non-space (space/tab) character after the '>' */

	if(first_sequence_flag) {
	  ptr = buf;
	} else {
	  ptr = &buf[1];
	}
	while(*ptr == '\t' || *ptr == ' ') {
	  ptr++;
	}
	sscanf(ptr, "%s", alignment->titles[seq]);  /* get the first word and use as the title */

	alignment->nseq++;
      }
	
      buf[index++] = c;

      break;


    case NJ_FASTA_MODE_SEQUENCE:

      if(c == '>') {

	if(first_sequence_flag) {
	  first_sequence_flag = 0;

	  /* allocate our alignment data section here */
	  alignment->length = index-1;

	  nseqs = NJ_INITIAL_NSEQS;
	  alignment->data = (char *)calloc(alignment->length*nseqs, sizeof(char));
	  if(!alignment->data) {
	    fprintf(stderr, "Clearcut: Allocation error in NJ_read_fasta()\n");
	    goto XIT_BAD;
	  }
	} 
	
	if(!first_sequence_flag) {
	  if(index-1 < alignment->length) {
	    fprintf(stderr, "Clearcut: Sequences must be of uniform length in alignment at sequence %ld\n", seq);
	    goto XIT_BAD;
	  }
	}

	/* re-allocate if necessary */
	/*
	if(seq >= nseqs) {
	  nseqs *= 2;
	  alignment->data = (char *)realloc(alignment->data, alignment->length*nseqs*sizeof(char));
	  if(!alignment->data) {
	    fprintf(stderr, "Clearcut: Allocation error in NJ_read_fasta()\n");
	    goto XIT_BAD;
	  }
	}
	*/

	/* copy buf to alignment */
	for(i=1;i<=alignment->length;i++) {
	  alignment->data[seq*alignment->length+i-1] = buf[i];
	}
	  
	state = NJ_FASTA_MODE_TITLE;
	index = 1;
	x     = 1;
	  
	buf[0] = c;
	
	seq++;

      } else {
	  
	if(NJ_is_whitespace(c)) {
	  break;
	}
		
	if(!first_sequence_flag) {
	  if(index-1 >= alignment->length) {
	    fprintf(stderr, "Clearcut: Sequences must be of uniform length in alignment at sequence %ld\n", seq);
	    goto XIT_BAD;
	  }
	}


	/* 
	 * Here we check to make sure that the symbol read is appropriate
	 * for the type of data the user specified.  (dna or protein).
	 * We also handle ambiguity codes by converting them to a specific
	 * assigned ambiguity code character.  Ambiguity codes are ignored
	 * when computing distances
	 */

	if(nj_args->dna_flag) {
	  if(NJ_is_dna(c)) {
	    buf[index++] = toupper(c);
	  } else {
	    if(NJ_is_dna_ambiguity(c)) {
	      buf[index++] = NJ_AMBIGUITY_CHAR;
	    } else {
	      fprintf(stderr, "Clearcut: Unknown symbol '%c' in nucleotide sequence %ld.\n", c, seq);
	      goto XIT_BAD;
	    }
	  }
	} else if(nj_args->protein_flag) {
	  if(NJ_is_protein(c)) {
	    buf[index++] = toupper(c);
	  } else {
	    if(NJ_is_protein_ambiguity(c)) {
	      buf[index++] = NJ_AMBIGUITY_CHAR;
	    } else {
	      fprintf(stderr, "Clearcut: Unknown symbol '%c' in protein sequence %ld.\n", c, seq);
	      goto XIT_BAD;
	    }
	  }
	}

      }

      break;
	
    default:
      goto XIT_BAD;
	
      break;

    }
  }
  
  if(index-1 != alignment->length) {
    fprintf(stderr, "Clearcut: Sequences must be of uniform length in alignment at sequence %ld\n", seq);
    goto XIT_BAD;
  }
  
  /* check for duplicate taxon labels */
  if(!NJ_taxaname_unique(alignment)) {
    goto XIT_BAD;
  }
  
  return(alignment);

  
 XIT_BAD:

  if(fp) {
    fprintf(stderr, "Clearcut: Fatal error parsing FASTA file at file offset %ld.\n", ftell(fp));
  }
  
  if(buf) {
    free(buf);
  }
  
  NJ_free_alignment(alignment);

  return(NULL);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x38, %rsp
movq %rdi, %r13
movl 0x40(%rdi), %eax
testl %eax, %eax
jne 0x5e43
cmpl $0x0, 0x44(%r13)
je 0x62d3
testl %eax, %eax
je 0x5e4e
cmpl $0x0, 0x44(%r13)
jne 0x62d3
cmpl $0x0, 0x28(%r13)
je 0x5e61
movq 0x717c(%rip), %rax      # 0xcfd8
movq (%rax), %r14
jmp 0x5e7d
movq (%r13), %rdi
leaq 0x2dbd(%rip), %rsi      # 0x8c29
callq 0x2200
movq %rax, %r14
testq %rax, %rax
je 0x62fb
movl $0x200, %edi            # imm = 0x200
movl $0x1, %esi
callq 0x2160
movq %rax, %r15
movl $0x1, %edi
movl $0x20, %esi
callq 0x2160
movq %rax, %rbx
movl $0x40, %edi
movl $0x8, %esi
callq 0x2160
movq %rax, 0x10(%rbx)
testq %r15, %r15
je 0x62da
testq %rbx, %rbx
je 0x62da
testq %rax, %rax
je 0x62da
movq %r14, %rdi
callq 0x2130
movl %eax, %r12d
movq %r14, %rdi
callq 0x21a0
testl %eax, %eax
je 0x5ef2
xorl %eax, %eax
xorl %r13d, %r13d
xorl %edx, %edx
jmp 0x6283
movq %r13, 0x28(%rsp)
movq %r14, (%rsp)
movl $0x67, %r14d
movl $0x200, %ebp            # imm = 0x200
movl $0x40, %eax
movq %rax, 0x20(%rsp)
movl $0x1, 0x1c(%rsp)
movq $0x0, 0x10(%rsp)
xorl %r13d, %r13d
cmpq %rbp, %r13
jl 0x5f43
addq %rbp, %rbp
movq %r15, %rdi
movq %rbp, %rsi
callq 0x21e0
movq %rax, %r15
testq %rax, %rax
je 0x630d
cmpl $0x64, %r14d
movq %rbp, 0x30(%rsp)
je 0x601b
cmpl $0x65, %r14d
je 0x5f7d
cmpl $0x67, %r14d
jne 0x6350
movzbl %r12b, %eax
leal -0x9(%rax), %ecx
cmpl $0x5, %ecx
jae 0x6112
movl $0x67, %r14d
jmp 0x612f
movl %r12d, %eax
shll $0x18, %eax
cmpl $0x3e000000, %eax       # imm = 0x3E000000
jne 0x60ef
cmpl $0x0, 0x1c(%rsp)
movq 0x20(%rsp), %rcx
je 0x5fc2
leaq -0x1(%r13), %rdi
movq %rdi, 0x8(%rbx)
shlq $0x6, %rdi
movl $0x1, %esi
callq 0x2160
movq %rax, 0x18(%rbx)
movl $0x40, %ecx
testq %rax, %rax
je 0x634b
cmpq 0x8(%rbx), %r13
jle 0x631e
movq %rcx, 0x20(%rsp)
movq 0x8(%rbx), %rax
testq %rax, %rax
movq 0x10(%rsp), %rsi
jle 0x5ffd
xorl %ecx, %ecx
movb 0x1(%r15,%rcx), %dl
imulq %rsi, %rax
addq 0x18(%rbx), %rax
movb %dl, (%rcx,%rax)
movq 0x8(%rbx), %rax
incq %rcx
cmpq %rax, %rcx
jl 0x5fe1
movb %r12b, (%r15)
incq %rsi
movq %rsi, 0x10(%rsp)
movl $0x0, 0x1c(%rsp)
movl $0x1, %r13d
jmp 0x6129
cmpb $0xd, %r12b
je 0x602e
movzbl %r12b, %eax
cmpl $0xa, %eax
jne 0x6103
movb $0x0, (%r15,%r13)
movq 0x20(%rsp), %r14
cmpq %r14, 0x10(%rsp)
jne 0x607d
movq 0x10(%rbx), %rdi
movq %r14, %rsi
shlq $0x4, %rsi
callq 0x21e0
movq %rax, 0x10(%rbx)
testq %rax, %rax
je 0x633d
addq %r14, %r14
movq 0x18(%rbx), %rdi
movq 0x8(%rbx), %rsi
imulq %r14, %rsi
callq 0x21e0
movq %rax, 0x18(%rbx)
testq %rax, %rax
je 0x6344
movq %r15, %rdi
callq 0x20e0
movl $0x1, %esi
movq %rax, %rdi
callq 0x2160
movq 0x10(%rbx), %rcx
movq 0x10(%rsp), %rdx
movq %rax, (%rcx,%rdx,8)
movq 0x10(%rbx), %rax
movq (%rax,%rdx,8), %rdx
testq %rdx, %rdx
je 0x6317
cmpl $0x1, 0x1c(%rsp)
movq %r15, %rdi
adcq $0x0, %rdi
movzbl (%rdi), %eax
cmpl $0x20, %eax
je 0x60c9
cmpl $0x9, %eax
jne 0x60ce
incq %rdi
jmp 0x60bc
movq %r14, 0x20(%rsp)
leaq 0x2b9f(%rip), %rsi      # 0x8c79
xorl %eax, %eax
callq 0x21d0
incq (%rbx)
movl $0x65, %r14d
xorl %r13d, %r13d
jmp 0x6109
movzbl %r12b, %eax
leal -0x9(%rax), %ecx
cmpl $0x5, %ecx
jae 0x6158
movl $0x65, %r14d
jmp 0x612f
movl $0x64, %r14d
movb %r12b, (%r15,%r13)
incq %r13
jmp 0x612f
cmpl $0x20, %eax
je 0x5f72
cmpb $0x3e, %r12b
jne 0x6350
movb $0x3e, (%r15)
movl $0x64, %r14d
movq (%rsp), %rbp
movq %rbp, %rdi
callq 0x2130
movl %eax, %r12d
movq %rbp, %rdi
callq 0x21a0
testl %eax, %eax
movq 0x30(%rsp), %rbp
je 0x5f24
jmp 0x6273
cmpl $0x20, %eax
je 0x60fb
cmpl $0x0, 0x1c(%rsp)
jne 0x616e
cmpq 0x8(%rbx), %r13
jg 0x631e
movsbl %r12b, %ecx
movq 0x28(%rsp), %rax
cmpl $0x0, 0x40(%rax)
je 0x61e5
movl %ecx, 0xc(%rsp)
callq 0x2030
movq (%rax), %rcx
movsbq %r12b, %rax
movsbl (%rcx,%rax,4), %eax
xorl %edx, %edx
leaq 0x28f6(%rip), %r8       # 0x8a90
movsbl (%rdx,%r8), %esi
cmpl %esi, %eax
je 0x61b0
leaq 0x1(%rdx), %rdi
cmpq $0x4, %rdx
movq %rdi, %rdx
jne 0x619a
cmpl %esi, %eax
je 0x6226
movl $0x65, %r14d
xorl %ecx, %ecx
leaq 0x28d2(%rip), %rdi      # 0x8a95
movsbl (%rcx,%rdi), %edx
cmpl %edx, %eax
je 0x61d8
leaq 0x1(%rcx), %rsi
cmpq $0xd, %rcx
movq %rsi, %rcx
jne 0x61c3
cmpl %edx, %eax
je 0x6269
jmp 0x638c
cmpl $0x0, 0x44(%rax)
je 0x60fb
movl %ecx, 0xc(%rsp)
callq 0x2030
movq (%rax), %rcx
movsbq %r12b, %rax
movsbl (%rcx,%rax,4), %eax
xorl %edx, %edx
leaq 0x28a4(%rip), %r8       # 0x8ab0
movsbl (%rdx,%r8), %esi
cmpl %esi, %eax
je 0x6222
leaq 0x1(%rdx), %rdi
cmpq $0x13, %rdx
movq %rdi, %rdx
jne 0x620c
cmpl %esi, %eax
jne 0x623d
movl $0x65, %r14d
movslq 0xc(%rsp), %rax
movb (%rcx,%rax,4), %al
movb %al, (%r15,%r13)
jmp 0x610d
movl $0x65, %r14d
xorl %ecx, %ecx
leaq 0x2878(%rip), %rdi      # 0x8ac4
movsbl (%rcx,%rdi), %edx
cmpl %edx, %eax
je 0x6261
leaq 0x1(%rcx), %rsi
cmpq $0x5, %rcx
movq %rsi, %rcx
jne 0x624c
cmpl %edx, %eax
jne 0x639f
movb $0x3f, (%r15,%r13)
jmp 0x610d
cmpl $0x65, %r14d
sete %al
movq (%rsp), %r14
movq 0x10(%rsp), %rdx
testb %al, %al
je 0x62b5
movb $0x0, 0x1(%r13,%r15)
movq 0x8(%rbx), %rax
testq %rax, %rax
jle 0x62b5
xorl %ecx, %ecx
movb 0x1(%r15,%rcx), %sil
imulq %rdx, %rax
addq 0x18(%rbx), %rax
movb %sil, (%rcx,%rax)
movq 0x8(%rbx), %rax
incq %rcx
cmpq %rax, %rcx
jl 0x6298
decq %r13
cmpq 0x8(%rbx), %r13
jne 0x62e1
movq %rbx, %rdi
callq 0x63c2
testl %eax, %eax
jne 0x6370
jmp 0x6354
callq 0x2743
jmp 0x6303
callq 0x26fb
jmp 0x6354
movq 0x6d10(%rip), %rax      # 0xcff8
movq (%rax), %rdi
leaq 0x263d(%rip), %rsi      # 0x892f
xorl %eax, %eax
callq 0x2180
jmp 0x6354
movq %r13, %rdi
callq 0x2717
xorl %ebx, %ebx
xorl %r15d, %r15d
xorl %r14d, %r14d
jmp 0x6354
callq 0x266f
xorl %r15d, %r15d
jmp 0x6350
callq 0x26a7
jmp 0x6350
movq 0x6cd3(%rip), %rax      # 0xcff8
movq (%rax), %rdi
leaq 0x2600(%rip), %rsi      # 0x892f
movq 0x10(%rsp), %rdx
xorl %eax, %eax
callq 0x2180
jmp 0x6350
callq 0x26df
jmp 0x6350
callq 0x26c3
jmp 0x6350
callq 0x268b
movq (%rsp), %r14
testq %r14, %r14
jne 0x6382
testq %r15, %r15
je 0x6366
movq %r15, %rdi
callq 0x2040
movq %rbx, %rdi
callq 0x6457
xorl %ebx, %ebx
movq %rbx, %rax
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %r14, %rdi
callq 0x275f
jmp 0x6359
movq 0x6c65(%rip), %rax      # 0xcff8
movq (%rax), %rdi
leaq 0x25de(%rip), %rsi      # 0x897b
jmp 0x63b0
movq 0x6c52(%rip), %rax      # 0xcff8
movq (%rax), %rdi
leaq 0x2606(%rip), %rsi      # 0x89b6
movl 0xc(%rsp), %edx
movq 0x10(%rsp), %rcx
xorl %eax, %eax
callq 0x2180
jmp 0x6350