// File: BenLangmead[P]bowtie/./ebwt.h
// Function: void Ebwt::joinToDisk<SString<char>>(EList<FileBuf*, 128>&, EList<RefRecord, 128>&, EList<unsigned int, 128>&, unsigned int, RefReadInParams const&, SString<char>&, std::ostream&, std::ostream&, unsigned int)
void Ebwt::joinToDisk(
	EList<FileBuf*>& l,
	EList<RefRecord>& szs,
	EList<uint32_t>& plens,
	TIndexOffU sztot,
	const RefReadInParams& refparams,
	TStr& ret,
	ostream& out1,
	ostream& out2,
	uint32_t seed)
{
	RandomSource rand; // reproducible given same seed
	rand.init(seed);
	RefReadInParams rpcp = refparams;
	assert_gt(szs.size(), 0);
	assert_gt(l.size(), 0);
	assert_gt(sztot, 0);
	// Not every fragment represents a distinct sequence - many
	// fragments may correspond to a single sequence.  Count the
	// number of sequences here by counting the number of "first"
	// fragments.
	this->_nPat = 0;
	this->_nFrag = 0;
#ifdef ACCOUNT_FOR_ALL_GAP_REFS
	int nGapFrag = 0;
#endif
	for(size_t i = 0; i < szs.size(); i++) {
		if(szs[i].len > 0) this->_nFrag++;
#ifdef ACCOUNT_FOR_ALL_GAP_REFS
		if(szs[i].len == 0 && szs[i].off > 0) nGapFrag++;
		if(szs[i].first && szs[i].len > 0) this->_nPat++;
#else
		// For all records where len=0 and first=1, set first=0
		assert(szs[i].len > 0 || !szs[i].first);
		if(szs[i].first) this->_nPat++;
#endif
	}
	assert_gt(this->_nPat, 0);
	assert_geq(this->_nFrag, this->_nPat);
	this->_rstarts = NULL;
	writeU<TIndexOffU>(out1, this->_nPat, this->toBe());
	assert_eq(plens.size(), this->_nPat);
	// Allocate plen[]
	try {
		this->_plen = new TIndexOffU[this->_nPat];
	} catch(bad_alloc& e) {
		cerr << "Out of memory allocating plen[] in Ebwt::join()"
		     << " at " << __FILE__ << ":" << __LINE__ << endl;
		throw e;
	}
	// For each pattern, set plen
	for(TIndexOffU i = 0; i < plens.size(); i++) {
		this->_plen[i] = plens[i];
		writeU<TIndexOffU>(out1, this->_plen[i], this->toBe());
	}
	// Write the number of fragments
	writeU<TIndexOffU>(out1, this->_nFrag, this->toBe());
	TIndexOffU seqsRead = 0;
	ASSERT_ONLY(TIndexOffU szsi = 0);
	ASSERT_ONLY(TIndexOffU entsWritten = 0);
	TIndexOffU dstoff = 0;
	// For each filebuf
	for(unsigned int i = 0; i < l.size(); i++) {
		assert(!l[i]->eof());
		bool first = true;
		TIndexOffU patoff = 0;
		// For each *fragment* (not necessary an entire sequence) we
		// can pull out of istream l[i]...
		while(!l[i]->eof()) {
			string name;
			// Push a new name onto our vector
			_refnames.push_back("");
			//uint32_t oldRetLen = length(ret);
			RefRecord rec = fastaRefReadAppend(*l[i], first, ret, dstoff, rpcp, &_refnames.back());
#ifndef ACCOUNT_FOR_ALL_GAP_REFS
			if(rec.first && rec.len == 0) rec.first = false;
#endif
			first = false;
			if(rec.first) {
				if(_refnames.back().length() == 0) {
					// If name was empty, replace with an index
					ostringstream stm;
					stm << (_refnames.size()-1);
					_refnames.back() = stm.str();
				}
			} else {
				// This record didn't actually start a new sequence so
				// no need to add a name
				//assert_eq(0, _refnames.back().length());
				_refnames.pop_back();
			}
			assert_lt(szsi, szs.size());
			assert(szs[szsi].first == 0 || szs[szsi].first == 1);
			assert_eq(rec.off, szs[szsi].off);
			assert_eq(rec.len, szs[szsi].len);
			// szs[szsi].first == 2 sometimes?!?!  g++ is unable to do
			// the following correctly, regardless of how I write it
			//assert((rec.first == 0) == (szs[szsi].first == 0));
			assert(rec.first || rec.off > 0);
			ASSERT_ONLY(szsi++);
#ifdef ACCOUNT_FOR_ALL_GAP_REFS
			if(rec.len == 0) continue;
			if(rec.first && rec.len > 0) seqsRead++;
			assert_leq(rec.len, this->_plen[seqsRead-1]);
#else
			if(rec.first) seqsRead++;
			if(rec.len == 0) continue;
			assert_leq(rec.len, this->_plen[seqsRead-1]);
#endif
			// Reset the patoff if this is the first fragment
			if(rec.first) patoff = 0;
			patoff += rec.off; // add fragment's offset from end of last frag.
			// Adjust rpcps
			//uint32_t seq = seqsRead-1;
			ASSERT_ONLY(entsWritten++);
			// This is where rstarts elements are written to the output stream
			//writeU32(out1, oldRetLen, this->toBe()); // offset from beginning of joined string
			//writeU32(out1, seq,       this->toBe()); // sequence id
			//writeU32(out1, patoff,    this->toBe()); // offset into sequence
			patoff += rec.len;
		}
		assert_gt(szsi, 0);
		l[i]->reset();
		assert(!l[i]->eof());
		#ifndef NDEBUG
		int c = l[i]->get();
		assert_eq('>', c);
		assert(!l[i]->eof());
		l[i]->reset();
		assert(!l[i]->eof());
		#endif
	}
	assert_eq(entsWritten, this->_nFrag);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x350, %rsp            # imm = 0x350
movl 0x28(%rbp), %eax
movq 0x20(%rbp), %rax
movq 0x18(%rbp), %rax
movq 0x10(%rbp), %rax
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movl %r8d, -0x24(%rbp)
movq %r9, -0x30(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x290(%rbp)
leaq -0x44(%rbp), %rdi
callq 0x21c20
movl 0x28(%rbp), %esi
leaq -0x44(%rbp), %rdi
callq 0x21c40
movq -0x290(%rbp), %rax
movq -0x30(%rbp), %rcx
movq (%rcx), %rcx
movq %rcx, -0x4c(%rbp)
movl $0x0, 0x74(%rax)
movl $0x0, 0x78(%rax)
movq $0x0, -0x58(%rbp)
movq -0x58(%rbp), %rax
movq %rax, -0x298(%rbp)
movq -0x18(%rbp), %rdi
callq 0x1b600
movq %rax, %rcx
movq -0x298(%rbp), %rax
cmpq %rcx, %rax
jae 0x1f523
movq -0x18(%rbp), %rdi
movq -0x58(%rbp), %rsi
callq 0x1b620
cmpl $0x0, 0x4(%rax)
jbe 0x1f4f0
movq -0x290(%rbp), %rax
movl 0x78(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x78(%rax)
movq -0x18(%rbp), %rdi
movq -0x58(%rbp), %rsi
callq 0x1b620
testb $0x1, 0x8(%rax)
je 0x1f513
movq -0x290(%rbp), %rax
movl 0x74(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x74(%rax)
jmp 0x1f515
movq -0x58(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x58(%rbp)
jmp 0x1f4aa
movq -0x290(%rbp), %rdi
movq $0x0, 0x88(%rdi)
movq 0x18(%rbp), %rax
movq %rax, -0x2b0(%rbp)
movl 0x74(%rdi), %eax
movl %eax, -0x2a4(%rbp)
callq 0x16c80
movq -0x2b0(%rbp), %rdi
movl -0x2a4(%rbp), %esi
movzbl %al, %edx
callq 0xbd10
movq -0x290(%rbp), %rax
movl 0x74(%rax), %eax
movl %eax, %edi
shlq $0x2, %rdi
callq 0x6040
movq %rax, -0x2a0(%rbp)
jmp 0x1f581
movq -0x290(%rbp), %rax
movq -0x2a0(%rbp), %rcx
movq %rcx, 0x80(%rax)
jmp 0x1f6b7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x60(%rbp)
movl %eax, -0x64(%rbp)
movl -0x64(%rbp), %eax
movl $0x1, %ecx
cmpl %ecx, %eax
jne 0x1fb48
movq -0x60(%rbp), %rdi
callq 0x61a0
movq %rax, -0x70(%rbp)
movq 0x32a25(%rip), %rdi     # 0x51ff0
leaq 0x26e84(%rip), %rsi     # 0x46456
callq 0x6410
movq %rax, -0x2b8(%rbp)
jmp 0x1f5e0
movq -0x2b8(%rbp), %rdi
leaq 0x27654(%rip), %rsi     # 0x46c42
callq 0x6410
movq %rax, -0x2c0(%rbp)
jmp 0x1f5fc
movq -0x2c0(%rbp), %rdi
leaq 0x24af0(%rip), %rsi     # 0x440fa
callq 0x6410
movq %rax, -0x2c8(%rbp)
jmp 0x1f618
movq -0x2c8(%rbp), %rdi
leaq 0x2585f(%rip), %rsi     # 0x44e85
callq 0x6410
movq %rax, -0x2d0(%rbp)
jmp 0x1f634
movq -0x2d0(%rbp), %rdi
movl $0xf20, %esi            # imm = 0xF20
callq 0x6830
movq %rax, -0x2d8(%rbp)
jmp 0x1f64e
movq -0x2d8(%rbp), %rdi
movq 0x3290c(%rip), %rsi     # 0x51f68
callq 0x6470
jmp 0x1f663
movl $0x8, %edi
callq 0x61f0
movq %rax, %rdi
movq %rdi, -0x2e0(%rbp)
movq -0x70(%rbp), %rsi
callq 0x147a0
movq -0x2e0(%rbp), %rdi
movq 0x32922(%rip), %rsi     # 0x51fb0
movq 0x328f3(%rip), %rdx     # 0x51f88
callq 0x67f0
jmp 0x1fb59
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x60(%rbp)
movl %eax, -0x64(%rbp)
callq 0x6770
jmp 0x1f6b2
jmp 0x1fb48
movl $0x0, -0x74(%rbp)
movl -0x74(%rbp), %eax
movq %rax, -0x2e8(%rbp)
movq -0x20(%rbp), %rdi
callq 0x14440
movq %rax, %rcx
movq -0x2e8(%rbp), %rax
cmpq %rcx, %rax
jae 0x1f74d
movq -0x20(%rbp), %rdi
movl -0x74(%rbp), %eax
movl %eax, %esi
callq 0x14410
movq -0x290(%rbp), %rdi
movl (%rax), %edx
movq 0x80(%rdi), %rax
movl -0x74(%rbp), %ecx
movl %edx, (%rax,%rcx,4)
movq 0x18(%rbp), %rax
movq %rax, -0x2f8(%rbp)
movq 0x80(%rdi), %rax
movl -0x74(%rbp), %ecx
movl (%rax,%rcx,4), %eax
movl %eax, -0x2ec(%rbp)
callq 0x16c80
movq -0x2f8(%rbp), %rdi
movl -0x2ec(%rbp), %esi
movzbl %al, %edx
andl $0x1, %edx
callq 0xbd10
movl -0x74(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x74(%rbp)
jmp 0x1f6be
movq -0x290(%rbp), %rdi
movq 0x18(%rbp), %rax
movq %rax, -0x308(%rbp)
movl 0x78(%rdi), %eax
movl %eax, -0x2fc(%rbp)
callq 0x16c80
movq -0x308(%rbp), %rdi
movl -0x2fc(%rbp), %esi
movzbl %al, %edx
andl $0x1, %edx
callq 0xbd10
movl $0x0, -0x78(%rbp)
movl $0x0, -0x7c(%rbp)
movl $0x0, -0x80(%rbp)
movl -0x80(%rbp), %eax
movq %rax, -0x310(%rbp)
movq -0x10(%rbp), %rdi
callq 0x21c70
movq %rax, %rcx
movq -0x310(%rbp), %rax
cmpq %rcx, %rax
jae 0x1fb3f
movb $0x1, -0x81(%rbp)
movl $0x0, -0x88(%rbp)
movq -0x10(%rbp), %rdi
movl -0x80(%rbp), %eax
movl %eax, %esi
callq 0x21c90
movq (%rax), %rdi
callq 0x21cc0
xorb $-0x1, %al
testb $0x1, %al
jne 0x1f7f2
jmp 0x1fb1b
leaq -0xa8(%rbp), %rdi
callq 0x6630
movq -0x290(%rbp), %rax
addq $0xc8, %rax
movq %rax, -0x320(%rbp)
leaq -0xc9(%rbp), %rdi
movq %rdi, -0x318(%rbp)
callq 0x6860
movq -0x318(%rbp), %rdx
leaq 0x27842(%rip), %rsi     # 0x47075
leaq -0xc8(%rbp), %rdi
callq 0x146f0
jmp 0x1f841
movq -0x320(%rbp), %rdi
leaq -0xc8(%rbp), %rsi
callq 0x15e60
jmp 0x1f856
leaq -0xc8(%rbp), %rdi
callq 0x69a8
leaq -0xc9(%rbp), %rdi
callq 0x64a0
movq -0x10(%rbp), %rdi
movl -0x80(%rbp), %eax
movl %eax, %esi
callq 0x21c90
movq %rax, -0x328(%rbp)
jmp 0x1f885
movq -0x290(%rbp), %rdi
movq -0x328(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x348(%rbp)
movq 0x10(%rbp), %rax
movq %rax, -0x340(%rbp)
addq $0xc8, %rdi
movzbl -0x81(%rbp), %eax
movl %eax, -0x34c(%rbp)
callq 0x15f00
movl -0x34c(%rbp), %esi
movq -0x348(%rbp), %rdi
movq -0x340(%rbp), %rdx
movq %rax, %r9
andl $0x1, %esi
leaq -0x7c(%rbp), %rcx
leaq -0x4c(%rbp), %r8
callq 0x11cc0
movb %dl, -0x331(%rbp)
movq %rax, -0x330(%rbp)
jmp 0x1f8f7
movb -0x331(%rbp), %al
movq -0x330(%rbp), %rcx
movq %rcx, -0xe8(%rbp)
movb %al, -0xe0(%rbp)
movq -0xe8(%rbp), %rax
movq %rax, -0xd8(%rbp)
movb -0xe0(%rbp), %al
movb %al, -0xd0(%rbp)
testb $0x1, -0xd0(%rbp)
je 0x1f98e
cmpl $0x0, -0xd4(%rbp)
jne 0x1f98e
movb $0x0, -0xd0(%rbp)
jmp 0x1f98e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x60(%rbp)
movl %eax, -0x64(%rbp)
jmp 0x1f96c
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x60(%rbp)
movl %eax, -0x64(%rbp)
leaq -0xc8(%rbp), %rdi
callq 0x69a8
leaq -0xc9(%rbp), %rdi
callq 0x64a0
jmp 0x1fb0d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x60(%rbp)
movl %eax, -0x64(%rbp)
jmp 0x1fb0d
movb $0x0, -0x81(%rbp)
testb $0x1, -0xd0(%rbp)
je 0x1fa6c
movq -0x290(%rbp), %rdi
addq $0xc8, %rdi
callq 0x15f00
movq %rax, %rdi
callq 0x66e0
cmpq $0x0, %rax
jne 0x1fa6a
leaq -0x260(%rbp), %rdi
callq 0x6600
jmp 0x1f9d5
movq -0x290(%rbp), %rdi
addq $0xc8, %rdi
callq 0x15ee0
movq %rax, %rsi
decq %rsi
leaq -0x260(%rbp), %rdi
callq 0x6100
jmp 0x1f9fc
leaq -0x280(%rbp), %rdi
leaq -0x260(%rbp), %rsi
callq 0x6450
jmp 0x1fa11
movq -0x290(%rbp), %rdi
addq $0xc8, %rdi
callq 0x15f00
movq %rax, %rdi
leaq -0x280(%rbp), %rsi
callq 0x6560
leaq -0x280(%rbp), %rdi
callq 0x69a8
leaq -0x260(%rbp), %rdi
callq 0x6110
jmp 0x1fa6a
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x60(%rbp)
movl %eax, -0x64(%rbp)
leaq -0x260(%rbp), %rdi
callq 0x6110
jmp 0x1fb0d
jmp 0x1fa83
movq -0x290(%rbp), %rdi
addq $0xc8, %rdi
callq 0x21cf0
jmp 0x1fa81
jmp 0x1fa83
testb $0x1, -0xd0(%rbp)
je 0x1fa95
movl -0x78(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x78(%rbp)
cmpl $0x0, -0xd4(%rbp)
jne 0x1faaa
movl $0xb, -0x284(%rbp)
jmp 0x1faeb
testb $0x1, -0xd0(%rbp)
je 0x1fabd
movl $0x0, -0x88(%rbp)
movl -0xd8(%rbp), %eax
addl -0x88(%rbp), %eax
movl %eax, -0x88(%rbp)
movl -0xd4(%rbp), %eax
addl -0x88(%rbp), %eax
movl %eax, -0x88(%rbp)
movl $0x0, -0x284(%rbp)
leaq -0xa8(%rbp), %rdi
callq 0x69a8
movl -0x284(%rbp), %eax
testl %eax, %eax
je 0x1fb08
jmp 0x1fb03
jmp 0x1f7d1
jmp 0x1f7d1
leaq -0xa8(%rbp), %rdi
callq 0x69a8
jmp 0x1fb48
movq -0x10(%rbp), %rdi
movl -0x80(%rbp), %eax
movl %eax, %esi
callq 0x21c90
movq (%rax), %rdi
callq 0x21d10
movl -0x80(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x80(%rbp)
jmp 0x1f79a
addq $0x350, %rsp            # imm = 0x350
popq %rbp
retq
movq -0x60(%rbp), %rdi
callq 0x6850
movq %rax, %rdi
callq 0x147e0
nopl (%rax)