from fractions import Fraction

class Rep():
    def __init__(self , L , n = 50):
        self.repListe = L
        self.repetitions = n
    
    def liste(self):
        if len( self.repListe ) == 1:
            return [ self.repListe[0] for i in range(self.repetitions) ]
        else:
            liste_temp = []
            for i in range(self.repetitions):
                liste_temp.extend(self.repListe)
            return liste_temp
    

class Frac_cont():
    def __init__(self , instance):
        if isinstance(instance,list):
            if isinstance(instance[-1] , Rep):
                N = instance[-1].liste()
                instance.pop()
                instance.extend( N )
            self.ma_liste = instance
            self.fraction = None
        if isinstance(instance,Fraction):
            self.fraction = instance
            self.ma_liste = None
    
    # méthode simplify() : transforme la liste en fraction simplifiée
    
    def simplify(self):
        if self.ma_liste is not None:            
            counter = 0
            for i in self.ma_liste[::-1]:
                if i == 0:
                    print('Error: number must be different from 0.')
                    break
                    
                if counter == 0:
                    result = Fraction(i,1)
                    counter += 1
                else:
                    result = Fraction(i,1) + Fraction(1,result)
                    
            return result
        else:
            print('The instance of object Frac_cont must be a list.')
    
    # méthode decimal() : retourne la valeur approchée en type float
    
    def decimal(self):
        return float( self.simplify() )
    
    # méthode liste() : retourne la liste à partir d'une fraction
    # note : une fraction admet toujours une développement en fraction continue FINI
    
    def liste(self):
        if self.fraction is not None:
            L = []
            f = self.fraction
            a , b = f.numerator , f.denominator
            if a < b:
                a, b = b, a
            
            while b != 0:
                a, b , q = b, a % b , a // b
                L += [ q ]
                
            return L
        else:
            print('The instance of object Frac_cont must be a Fraction.')
            

if __name__ == "__main__":
    # obtenir une fraction à partir d'une liste
    liste = [2,3,1,1,9,1,1,48]
    r = Frac_cont(liste).simplify()
    print('La fraction correspondant au développement {} est : {}'.format(liste , r))
    
    # obtenir une liste à partir d'une fraction
    f = Fraction(63529,1252)
    print( 'La fraction {} admet pour développement en fraction continue : {}'.format( f, Frac_cont( f ).liste() ) )
    
    # obtenir une valeur approchée (flottant) à partir d'une liste avec répétition
    liste = [ Rep([1]) ]
    r = Frac_cont(liste).decimal()
    print('Le nombre décimal correspondant au développement {} est : {}'.format(liste , r))
    
    # gestion des erreurs d'instances
    a = Frac_cont( Fraction(12,7) )
    print( a.simplify() )