# -*- coding: utf-8 -*-
"""
Created on Mon Jan 25 15:51:18 2021

@author: ludox
"""
import copy
from math import log
from math import floor
import string
import sys

maiuscole=string.ascii_uppercase
minuscole=string.ascii_lowercase

# Triangolazione di una sfera
# Sim_compl= [[1,2,3,5],[2,3,4,5],[1,2,4,5],[1,2,3,6],[2,3,4,6],[1,2,4,6]]

def Face_index(indices):
    L=[0,1,2,3]
    for k in range(3):
        L.remove(indices[k])
    return L[0]

def Reorder(tet, gluing, face):
    tet_copy=copy.deepcopy(tet)
    L=[0,1,2,3]
    L.remove(face)
    for k in range(3):
        tet[L[k]] = tet_copy[gluing[k]]
    tet[face] = tet_copy[Face_index(gluing)]
    return tet

def pi_conv(n):
    if n<26:
        return minuscole[n]
    if n<52:
        return maiuscole[n-26]
    if n<62:
        return str(n-52)
    if n==62:
        return '+'
    if n==63:
        return '-'

def eps_conv(d, n):
    k=0
    output=''
    while k<d:
        x=int(n%64)
        output=output+pi_conv(x)
        k=k+1
        n=(n-x)/64
    return output

def perm_conv(p):
    L=[[0,1,2,3], [0,1,3,2], [0,2,1,3], [0,2,3,1], [0,3,1,2], [0,3,2,1], [1,0,2,3], [1,0,3,2], [1,2,0,3], [1,2,3,0], [1,3,0,2], [1,3,2,0], [2,0,1,3], [2,0,3,1], [2,1,0,3], [2,1,3,0], [2,3,0,1], [2,3,1,0], [3,0,1,2], [3,0,2,1], [3,1,0,2], [3,1,2,0], [3,2,0,1], [3,2,1,0]]
    return L.index(p)

# Returns the isomorphism signature of a 3-dimensional simplicial complex. 
# The simplicial complex is given as the union of tetrahedra.

def get_iso_signature(simplicial_complex):
    answer = []
    Sim_compl = simplicial_complex[:]
    while len(Sim_compl)>0:

        Con_compo=[Sim_compl[0]]
        Sim_compl.remove(Sim_compl[0])
        ind_tet=0
        Glued_faces=[]
        type_sequence=[]
        destination_sequence=[]
        permutation_sequence=[]
        destination_sequence_type_2=[]
        
        while ind_tet < len(Con_compo):
            S=Con_compo[ind_tet]
        # we search for face k
            for k in range (4):
                if [ind_tet,k] not in Glued_faces:
                    
                    span_face=[0,1,2,3]
                    span_face.remove(k)
                    F=[S[span_face[0]],S[span_face[1]],S[span_face[2]]]
                    found=0
                    
                    ind = ind_tet+1
                    while found==0 and ind<len(Con_compo):
                        if (all(x in Con_compo[ind] for x in F)):
                            found=1
                            glued_tet=Con_compo[ind]                    
                            gluing=[glued_tet.index(F[0]),glued_tet.index(F[1]),glued_tet.index(F[2])]
                            glued_face=Face_index(gluing)
                            Glued_faces.append([ind,glued_face])
                            
                            type_sequence.append(2)
                            destination_sequence.append(ind)
                            destination_sequence_type_2.append(ind)
                        else:
                            ind=ind+1
                    
                    ind=0
                    while found==0 and ind<len(Sim_compl):
                        if (all(x in Sim_compl[ind] for x in F)):
                            found=1
                            glued_tet=Sim_compl[ind]
                            gluing=[glued_tet.index(F[0]),glued_tet.index(F[1]),glued_tet.index(F[2])]
                            
                            Con_compo.append(Reorder(glued_tet,gluing, k))
                            Sim_compl.remove(glued_tet)                    
                            
                            Glued_faces.append([len(Con_compo)-1,k])
                            
                            type_sequence.append(1)
                            destination_sequence.append(len(Con_compo)-1)
                        else:
                            ind=ind+1
                            
                    if found == 0 :
                        type_sequence.append(0)
                        destination_sequence.append('delta')
                        
                    if type_sequence[-1] == 2:
                        gluing.insert(k,glued_face)
                        perm=gluing
                        permutation_sequence.append(perm)
                        
                
                            
            ind_tet=ind_tet+1
            
        
        n=len(Con_compo)
        d=floor(log(n,64))+1
        
        i_s=''
        if n<63:
            i_s = i_s + pi_conv(n)
        else:
            i_s = i_s + '-' + pi_conv(d) + eps_conv(d,n)
        
        num_types=len(type_sequence)
        type_sequence=type_sequence+[0,0]
        k=0
        
        while k<num_types:
            i_s = i_s + pi_conv( type_sequence[k] + 4* type_sequence[k+1] + 16* type_sequence[k+2] )
            k=k+3
            
        for k in destination_sequence_type_2:
            i_s = i_s + eps_conv(d,k)
        
        for k in permutation_sequence:
            i_s = i_s + pi_conv( perm_conv(k))

        answer.append(i_s[:])            
            
        # i_s=i_s + '\n'
        
        # file = open('is_sig.txt', 'a')
        # sys.stdout = file
        # print(i_s)
        # file.close()
        # sys.stdout = sys.__stdout__   
        
    # terminal_output = open('/dev/stdout', 'w')
    
    # f = open('is_sig.txt', 'a')
    # print(i_s, file=terminal_output) #, file = f)
    
    # return i_s
    
    return answer