from __future__ import annotations

class UnknownVariable:
    """
    This class represents a variable that is not known yet.
    
    Parameters
    ----------
    name : str, optional
        The name of the variable. By default None.
    type_of_var : str, optional
        The type of the variable. By default None.
        
    Attributes
    ----------
    id : int
        The unique number assigned to each new generated variable.
    name : str
        The given name to each variable.
    type : str
        The type of the variable. It can be referred as the reason why the variable is generated.
        For example, is it a template variable or it is generated by farkas algorithm.
    number_of_variables : int
        The number of generated variables to find new id for the recently generated variable
    """
    number_of_variables = 0

    @staticmethod
    def get_new_id() -> int:
        """ 
        Get new unique id for the newest variable

        Returns
        -------
        int
            A number to assign to the latest created variable
        """
        UnknownVariable.number_of_variables += 1
        return UnknownVariable.number_of_variables

    def __init__(self, name: str = None, type_of_var: str = None):
        self.name = name
        self.type = type_of_var
        self.id = UnknownVariable.get_new_id()

    def __str__(self) -> str:
        """
        Convert variable to string by putting name and id together.
        
        Returns
        -------
        str
            The name of the variable with its id.
        """
        if self.type == 'template_var' or self.type == 'program_var':
            return self.name
        if self.name is not None:
            return self.name + f'_{self.id}'
        return str(f'var_{self.id}[{self.name}]')

    def __lt__(self, other: UnknownVariable) -> bool:
        """
        Compare variables based on their id (less than).
        
        Parameters
        ----------
        other : UnknownVariable
            The variable to compare with.
            
        Returns
        -------
        bool
            True if the id of the variable is less than the id of the other variable.        
        """
        return self.id < other.id

    def __eq__(self, other: UnknownVariable) -> bool:
        """
        Compare variables based on their id (equal).
        
        Parameters
        ----------
        other : UnknownVariable
            The variable to compare with.
            
        Returns
        -------
        bool
            True if the id of the variable is equal to the id of the other variable.
        """
        return self.id == other.id

    def __hash__(self) -> int:
        """
        Hash variables based on their id.
        
        Returns
        -------
        int
            The hash of the variable.
        """
        return hash(self.id)

    def convert_to_preorder(self) -> str:
        """
        Convert variables into preorder format of a fraction.
        
        Returns
        -------
        str
            The variable in the form of a fraction.
        """
        return f'(/ {self.name}_num {self.name}_den)'
