#!/usr/bin/env python3

from Cryptotools.Groups.group import Group


class Cyclic(Group):
    """
        This object contain a list of the Group for a cyclic group. This class find all generator of the group.
        This class is inherited from Group object

        Attributes:
            G (list): list of all elements in the group
            n (Integer): it's the value where the group has been generated
            operation (Function): it's the operation generating the group
            generators (list): contain all generators of the group 
            generatorChecked (boolean): Check if generators has been found
    """
    def __init__(self, G:list, n, ope):
        super().__init__(n, G, ope) # Call the Group's constructor
        self._G = G
        self._n = n
        self._operation = ope
        self._generators = list()
        self._generatorChecked = False

    def generator(self):
        """
            This function find all generators in the group G
        """

        index = 1
        G = sorted(self._g)
        for g in range(2, self._n):
            z = list()
            for entry in range(1, self._n):
                res = self._operation(g, index, self._n)
                if res not in z:
                    z.append(res)
                    index = index + 1

            # We check if that match with G
            # If yes, we find a generator
            if sorted(z) == G:
                self._generators.append(g)
        self._generatorChecked = True

    def getPrimitiveRoot(self):
        """
            This function return the primitive root modulo of n

            Returns:
                Return the primitive root of the group. None if no primitive has been found
        """

        index = 1
        G = sorted(self._g)
        for g in range(2, self._n):
            z = list()
            for entry in range(1, self._n):
                res = self._operation(g, index, self._n)
                if res not in z:
                    z.append(res)
                    index += 1

            # If the group is the same has G, we found a generator
            if sorted(z) == G:
                return g
        return None

    def getGenerators(self) -> list:
        """
            This function return all generators of that group
            
            Returns:
                Return the list of generators found. The function generators() must be called before to call this function
        """
        if not self._generatorChecked:
            self.generator()
            self._generatorChecked = True
        return self._generators

    def isCyclic(self) -> bool:
        """
            Check if the group is a cyclic group, means we have at least one generator

            Returns:
                REturn a boolean, False if the group is not Cyclic otherwise return True
        """
        if len(self.getGenerators()) == 0:
            return False
        return True
