// File: MarkCBell[P]twister/./twister/kernel/twister.cpp
// Function: manifold::foldoff(tetra*)
tetra *manifold::foldoff(tetra *capoff_tetra)
{
	output_debugging("foldoff", 2);
	
	if (!last_tetra)  // Empty manifold?
		return NULL;
	
	if (capoff_tetra == NULL)  // There's no boundary faces.
		return capoff_tetra;
	
	// Definition: Suppose that two boundary triangles T_1 = ABC and T_2 = A'B'C'
	// are glued along the edge BC ~ B'C' then T is said to have a valid fold in 
	// direction A iff A and A' are not in the same vertex class.
	
	// Definition: With T_1, T_2 as above in a manifold M, the manifold obtained 
	// by performing the 'close the book' move on T_1 in direction A is M / ~. 
	// Here ~ is the gluing of T_1 to T_2 by A ~ A', B ~ B' and C ~ C' extended 
	// linearly over T_1 and T_2.
	
	// Lemma: If T is a boundary triangle of the 3-manifold M which has a valid 
	// fold in direction A then the manifold obtained by performing the 'close the book' 
	// move on T in the direction A is homeomorphic to M.
	
	// Proof: See L122 of close_cusps.c in the SnapPea kernel. //
	
	// Lemma: If 2 boundary triangles each have no valid folds in any direction and,
	// after doing a valid fold elsewhere, they are now are adjacent to each other then 
	// they both still do not have a valid fold.
	
	// Proof: Omitted. //
	
	// Corollary: Only 1 pass through the list of tetra is ever needed.
	
	// We only foldoff capping tetra when it will preserve the meridian or longitude information.
	for (tetra *current = capoff_tetra; current != NULL; current = current->get_next())
	{
		// Let's find a direction in which we can foldoff.
		for (int dir = 0; dir < 3; dir++)  // Direction 3 is down into the manifold so don't bother trying that way.
		{
			tetra *adjacent = current->get_gluedto(dir);
			perm current_to_adjacent = current->get_gluing(dir);
			
			// Check we're not going to mess up the longitudes or meridians.
			bool no_peripheral_curves = true;  // Peripheral curve free?
			bool side_to_side = ((current->get_peripheral_curves(longitude, dir) != 0) && (current->get_peripheral_curves(meridian, dir) != 0));
			for (int i = 0; i < 2; i++)
			{
				Curves c = (Curves) i;  // Which type of curve we're looking at.
				for (int j = 0; j < 3; j++)
				{
					int k = current_to_adjacent[j];
					if ((current->get_peripheral_curves(c, j) != 0) || (adjacent->get_peripheral_curves(c, k) != 0)) no_peripheral_curves = false;
					if (current->get_peripheral_curves(c, j) != -adjacent->get_peripheral_curves(c, k)) side_to_side = false;
				}
			}
			
			if (!no_peripheral_curves && !side_to_side)
				continue;
			
			if (adjacent == current)
				continue;  // This would be caught by the A == A' test later, but it's an easy catch here.
			
			int A = dir;  // These are the 'opposite vertices'.
			int A_prime = current_to_adjacent[A];
			
			// Now we check A != A'. If this is the case then we have sufficent grounds to foldoff this way.
			tetra *walking = current;
			
			// Let's label the vertices of the current triangle.
			int curr_a = A, curr_b = (curr_a == 0) ? 1 : 0, curr_c = 3 - curr_a - curr_b;
			
			// Walk around the edge between A and vertex 3.
			do
			{
				perm current_gluing = walking->get_gluing(curr_b);
				
				walking = walking->get_gluedto(curr_b);
				
				curr_a = current_gluing[curr_a];
				curr_b = current_gluing[curr_b];
				curr_c = current_gluing[curr_c];
				
				curr_b ^= curr_c; curr_c ^= curr_b; curr_b ^= curr_c;  // Interchange curr_b & curr_c.
			} while (((walking != current) || (curr_a != A)) && ((walking != adjacent) || (curr_a != A_prime)));
			// Stop only when we get back to current or adjacent with the CORRECT orientation.
			
			if (walking == adjacent)  // A == A'. So give up and try a different direction.
				continue;
			
			// A != A'. All's good, we definitely can foldoff this way.
			
			// Better record the previous one so we can take a step forward once we delete current.
			tetra *prev = (current->get_prev() != adjacent) ? current->get_prev() : adjacent->get_prev();
			
			// Unglue pairs of corresponding faces (one pair from current & one pair from adjacent)
			// and glue them together to allow us to remove current and adjacent from the manifold,
			// reducing the number of free faces by 2.
			// Note: This process maintains the cappoff, so no recapping is required.
			for (int i = 0; i < 4; i++)
			{
				if (i == dir)
					continue;  // Now it would be a waste of time to even think about gluing that way.
				
				tetra *from = current->get_gluedto(i);
				tetra *to = adjacent->get_gluedto(current_to_adjacent[i]);
				int glueout = current->get_gluing(i)[i];
				
				perm from_to_current = (current->get_gluing(i)).inverse();
				perm adjacent_to_to = adjacent->get_gluing(current_to_adjacent[i]);
				perm composed = adjacent_to_to.of(current_to_adjacent.of(from_to_current));
				
				adjacent->ungluesym(current_to_adjacent[i]);
				current->ungluesym(i);
				
				from->gluesym(to, glueout, composed);
			}
			
			// Delete current & adjacent as they are now disconnected from the manifold.
			oneless(adjacent);
			oneless(current);
			
			current = prev;  // Take a step back.
			break;
		}
	}
	
	// The capoff has changed, so better re-find the capoff_tetra.
	for (capoff_tetra = first_tetra; capoff_tetra != NULL; capoff_tetra = capoff_tetra->get_next())
		if (capoff_tetra->get_category() == cap)
			break;
	
	return capoff_tetra;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x190, %rsp            # imm = 0x190
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0x158(%rbp)
leaq -0x39(%rbp), %rdi
movq %rdi, -0x150(%rbp)
callq 0x3560
movq -0x150(%rbp), %rdx
leaq 0x7a82(%rip), %rsi      # 0x2779e
leaq -0x38(%rbp), %rdi
callq 0x4e10
jmp 0x1fd27
leaq -0x38(%rbp), %rdi
movl $0x2, %esi
callq 0x4c10
jmp 0x1fd37
leaq -0x38(%rbp), %rdi
callq 0x35f8
leaq -0x39(%rbp), %rdi
callq 0x3360
movq -0x158(%rbp), %rax
cmpq $0x0, 0x8(%rax)
jne 0x1fd95
movq $0x0, -0x8(%rbp)
jmp 0x20326
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
jmp 0x1fd87
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
leaq -0x38(%rbp), %rdi
callq 0x35f8
leaq -0x39(%rbp), %rdi
callq 0x3360
jmp 0x20333
cmpq $0x0, -0x18(%rbp)
jne 0x1fda9
movq -0x18(%rbp), %rax
movq %rax, -0x8(%rbp)
jmp 0x20326
movq -0x18(%rbp), %rax
movq %rax, -0x58(%rbp)
cmpq $0x0, -0x58(%rbp)
je 0x202e8
movl $0x0, -0x5c(%rbp)
cmpl $0x3, -0x5c(%rbp)
jge 0x202d4
movq -0x58(%rbp), %rdi
movl -0x5c(%rbp), %esi
callq 0x20b60
movq %rax, -0x68(%rbp)
movq -0x58(%rbp), %rsi
movl -0x5c(%rbp), %edx
leaq -0x78(%rbp), %rdi
callq 0x20b80
movb $0x1, -0x79(%rbp)
movq -0x58(%rbp), %rdi
movl -0x5c(%rbp), %edx
xorl %esi, %esi
callq 0x21590
movl %eax, %ecx
xorl %eax, %eax
cmpl $0x0, %ecx
movb %al, -0x159(%rbp)
je 0x1fe2b
movq -0x58(%rbp), %rdi
movl -0x5c(%rbp), %edx
movl $0x1, %esi
callq 0x21590
cmpl $0x0, %eax
setne %al
movb %al, -0x159(%rbp)
movb -0x159(%rbp), %al
andb $0x1, %al
movb %al, -0x7a(%rbp)
movl $0x0, -0x80(%rbp)
cmpl $0x2, -0x80(%rbp)
jge 0x1ff1e
movl -0x80(%rbp), %eax
movl %eax, -0x84(%rbp)
movl $0x0, -0x88(%rbp)
cmpl $0x3, -0x88(%rbp)
jge 0x1ff0e
movl -0x88(%rbp), %esi
leaq -0x78(%rbp), %rdi
callq 0x16f80
movl %eax, -0x8c(%rbp)
movq -0x58(%rbp), %rdi
movl -0x84(%rbp), %esi
movl -0x88(%rbp), %edx
callq 0x21590
cmpl $0x0, %eax
jne 0x1feb0
movq -0x68(%rbp), %rdi
movl -0x84(%rbp), %esi
movl -0x8c(%rbp), %edx
callq 0x21590
cmpl $0x0, %eax
je 0x1feb4
movb $0x0, -0x79(%rbp)
movq -0x58(%rbp), %rdi
movl -0x84(%rbp), %esi
movl -0x88(%rbp), %edx
callq 0x21590
movl %eax, -0x160(%rbp)
movq -0x68(%rbp), %rdi
movl -0x84(%rbp), %esi
movl -0x8c(%rbp), %edx
callq 0x21590
movl %eax, %edx
movl -0x160(%rbp), %eax
xorl %ecx, %ecx
subl %edx, %ecx
cmpl %ecx, %eax
je 0x1fef8
movb $0x0, -0x7a(%rbp)
jmp 0x1fefa
movl -0x88(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x88(%rbp)
jmp 0x1fe5a
jmp 0x1ff10
movl -0x80(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x80(%rbp)
jmp 0x1fe3d
testb $0x1, -0x79(%rbp)
jne 0x1ff2f
testb $0x1, -0x7a(%rbp)
jne 0x1ff2f
jmp 0x202c6
movq -0x68(%rbp), %rax
cmpq -0x58(%rbp), %rax
jne 0x1ff3e
jmp 0x202c6
movl -0x5c(%rbp), %eax
movl %eax, -0x90(%rbp)
movl -0x90(%rbp), %esi
leaq -0x78(%rbp), %rdi
callq 0x16f80
movl %eax, -0x94(%rbp)
movq -0x58(%rbp), %rax
movq %rax, -0xa0(%rbp)
movl -0x90(%rbp), %eax
movl %eax, -0xa4(%rbp)
movl -0xa4(%rbp), %edx
xorl %eax, %eax
movl $0x1, %ecx
cmpl $0x0, %edx
cmovel %ecx, %eax
movl %eax, -0xa8(%rbp)
movl $0x3, %eax
subl -0xa4(%rbp), %eax
subl -0xa8(%rbp), %eax
movl %eax, -0xac(%rbp)
movq -0xa0(%rbp), %rsi
movl -0xa8(%rbp), %edx
leaq -0xbc(%rbp), %rdi
callq 0x20b80
movq -0xa0(%rbp), %rdi
movl -0xa8(%rbp), %esi
callq 0x20b60
movq %rax, -0xa0(%rbp)
movl -0xa4(%rbp), %esi
leaq -0xbc(%rbp), %rdi
callq 0x16f80
movl %eax, -0xa4(%rbp)
movl -0xa8(%rbp), %esi
leaq -0xbc(%rbp), %rdi
callq 0x16f80
movl %eax, -0xa8(%rbp)
movl -0xac(%rbp), %esi
leaq -0xbc(%rbp), %rdi
callq 0x16f80
movl %eax, -0xac(%rbp)
movl -0xac(%rbp), %eax
xorl -0xa8(%rbp), %eax
movl %eax, -0xa8(%rbp)
movl -0xa8(%rbp), %eax
xorl -0xac(%rbp), %eax
movl %eax, -0xac(%rbp)
movl -0xac(%rbp), %eax
xorl -0xa8(%rbp), %eax
movl %eax, -0xa8(%rbp)
movq -0xa0(%rbp), %rax
cmpq -0x58(%rbp), %rax
jne 0x20076
movl -0xa4(%rbp), %ecx
xorl %eax, %eax
cmpl -0x90(%rbp), %ecx
movb %al, -0x161(%rbp)
je 0x200ac
movq -0xa0(%rbp), %rcx
movb $0x1, %al
cmpq -0x68(%rbp), %rcx
movb %al, -0x162(%rbp)
jne 0x200a0
movl -0xa4(%rbp), %eax
cmpl -0x94(%rbp), %eax
setne %al
movb %al, -0x162(%rbp)
movb -0x162(%rbp), %al
movb %al, -0x161(%rbp)
movb -0x161(%rbp), %al
testb $0x1, %al
jne 0x1ffa3
movq -0xa0(%rbp), %rax
cmpq -0x68(%rbp), %rax
jne 0x200cc
jmp 0x202c6
movq -0x58(%rbp), %rdi
callq 0x212e0
cmpq -0x68(%rbp), %rax
je 0x200ed
movq -0x58(%rbp), %rdi
callq 0x212e0
movq %rax, -0x170(%rbp)
jmp 0x200fd
movq -0x68(%rbp), %rdi
callq 0x212e0
movq %rax, -0x170(%rbp)
movq -0x170(%rbp), %rax
movq %rax, -0xc8(%rbp)
movl $0x0, -0xcc(%rbp)
cmpl $0x4, -0xcc(%rbp)
jge 0x20299
movl -0xcc(%rbp), %eax
cmpl -0x5c(%rbp), %eax
jne 0x20132
jmp 0x20285
movq -0x58(%rbp), %rdi
movl -0xcc(%rbp), %esi
callq 0x20b60
movq %rax, -0xd8(%rbp)
movq -0x68(%rbp), %rax
movq %rax, -0x188(%rbp)
movl -0xcc(%rbp), %esi
leaq -0x78(%rbp), %rdi
callq 0x16f80
movq -0x188(%rbp), %rdi
movl %eax, %esi
callq 0x20b60
movq %rax, -0xe0(%rbp)
movq -0x58(%rbp), %rsi
movl -0xcc(%rbp), %edx
leaq -0xf4(%rbp), %rdi
callq 0x20b80
movl -0xcc(%rbp), %esi
leaq -0xf4(%rbp), %rdi
callq 0x16f80
movl %eax, -0xe4(%rbp)
movq -0x58(%rbp), %rsi
movl -0xcc(%rbp), %edx
leaq -0x114(%rbp), %rdi
callq 0x20b80
leaq -0x104(%rbp), %rdi
leaq -0x114(%rbp), %rsi
callq 0x16fa0
movq -0x68(%rbp), %rax
movq %rax, -0x180(%rbp)
movl -0xcc(%rbp), %esi
leaq -0x78(%rbp), %rdi
callq 0x16f80
movq -0x180(%rbp), %rsi
movl %eax, %edx
leaq -0x124(%rbp), %rdi
callq 0x20b80
leaq -0x144(%rbp), %rdi
leaq -0x78(%rbp), %rsi
leaq -0x104(%rbp), %rdx
callq 0x17000
leaq -0x134(%rbp), %rdi
leaq -0x124(%rbp), %rsi
leaq -0x144(%rbp), %rdx
callq 0x17000
movq -0x68(%rbp), %rax
movq %rax, -0x178(%rbp)
movl -0xcc(%rbp), %esi
leaq -0x78(%rbp), %rdi
callq 0x16f80
movq -0x178(%rbp), %rdi
movl %eax, %esi
callq 0x17520
movq -0x58(%rbp), %rdi
movl -0xcc(%rbp), %esi
callq 0x17520
movq -0xd8(%rbp), %rdi
movq -0xe0(%rbp), %rsi
movl -0xe4(%rbp), %edx
leaq -0x134(%rbp), %rcx
callq 0x17390
movl -0xcc(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xcc(%rbp)
jmp 0x20115
movq -0x158(%rbp), %rdi
movq -0x68(%rbp), %rsi
callq 0x1d6f0
movq -0x158(%rbp), %rdi
movq -0x58(%rbp), %rsi
callq 0x1d6f0
movq -0xc8(%rbp), %rax
movq %rax, -0x58(%rbp)
jmp 0x202d4
movl -0x5c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x5c(%rbp)
jmp 0x1fdc3
jmp 0x202d6
movq -0x58(%rbp), %rdi
callq 0x21300
movq %rax, -0x58(%rbp)
jmp 0x1fdb1
movq -0x158(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x18(%rbp)
cmpq $0x0, -0x18(%rbp)
je 0x2031e
movq -0x18(%rbp), %rdi
callq 0x21200
cmpl $0x3, %eax
jne 0x2030d
jmp 0x2031e
jmp 0x2030f
movq -0x18(%rbp), %rdi
callq 0x21300
movq %rax, -0x18(%rbp)
jmp 0x202f6
movq -0x18(%rbp), %rax
movq %rax, -0x8(%rbp)
movq -0x8(%rbp), %rax
addq $0x190, %rsp            # imm = 0x190
popq %rbp
retq
movq -0x48(%rbp), %rdi
callq 0x3550
nopl (%rax)