class myBinaryInteger:
    """ Represents a binary integer (+ or -). The number is stored in
       reverse order. That is, the least significant bit is stored
       at index 0. The sign is stored separately. The constructor description
       should make some of these things clear.
    """
    
    def __init__(self, num = None, n=0):
        """ Create an n-bit binary number with all 0's.
        We will use a list to internally represent the number
        """
        
        # The formal parameter num is assumed to be a string or a list
        self._sign = True # Default sign in +, unless otherwise specified with - sign
        if num != None:
            # Read and store the number
            # First, check the sign of the number
            if len(num) <= 0:
                raise ValueError('The number cannot be empty')
            if str(num[0]) == '+':
                self._sign = True
                num = num[1:]
            elif str(num[0]) == '-':
                self._sign = False
                num = num[1:]
            self._n = len(num)
            if self._n <= 0:
                raise ValueError('The number cannot be empty')
            self._num = [0]*self._n
            for i in range(len(num)):
                if(int(num[i]) == 0 or int(num[i]) == 1):
                    self._num[self._n - i - 1] = int(num[i])
                else:
                    raise ValueError('The number must be Binary')
        else:
            if n <= 0:
                raise ValueError('The length should be positive')
            self._n = n
            self._num = [0]*n
               
    def __len__(self):
        """ Returns the length of the binary number """
        return(self._n)
        
    def __getitem__(self, j):
        """ Return the j^th bit"""
        return self._num[j]
        
    def __setitem__(self, j, val):
        """ Set the j^th bit with value val """
        if not (val == 0 or val == 1):
            raise ValueError('Value must be 0/1')
        self._num[j] = val

    def __str__(self):
        """ Returns the string representation of the number, which is the list in reverse        
        """
        S = '+' if self._sign else '-'
        for i in self._num: S += str(i)
        return S[0] + S[:0:-1]

    
    # To keep things simple for this assignment, we are asking to implement
    # only addition and subtraction of binary integers
    def __add__(self, other):
        """Return the sum of two myBinaryIntegers. 
        The result should not have any leading 0's.
        For example, 0101+01 should be 110, and 111+101 should be 1100.
        Please implement long addition for this. 
        DO NOT USE ANY PYTHON LIBRARIES or BUILT-IN FUNCTIONS."""
        
    def __sub__(self, other):
        """ Subtract the second number from the first. 
        The sign must be correctly set for the resulting number. 
        The result should not have any leading 0's.
        Please implement long subtraction for this. 
        DO NOT USE ANY PYTHON LIBRARIES OR BUILT-IN FUNCTIONS."""


    
    # The students are requested to complete the following methods.
    # The meaning of these operations must be looked up from Module-4
    # (operator overloading)
    def __pos__(self):
        """The result should not have leading 0's. 
        Add remaining description here"""
        
    def __neg__(self):
         """The result should not have leading 0's. 
        Add remaining description here"""
        
    def __abs__(self):
         """The result should not have leading 0's. 
        Add remaining description here"""
        
    def __bool__(self):
         """The result should not have leading 0's. 
        Add remaining description here"""
        
    def __int__(self):
         """The result should not have leading 0's. 
        Add remaining description here"""
        
    def __lt__(self, other):
         """The result should not have leading 0's. 
        Add remaining description here"""
        
    def __le__(self, other):
         """The result should not have leading 0's. 
        Add remaining description here"""
        
    def __gt__(self, other):
         """The result should not have leading 0's. 
        Add remaining description here"""
        
    def __ge__(self, other):
         """The result should not have leading 0's. 
        Add remaining description here"""
        
    def __eq__(self, other):
         """The result should not have leading 0's. 
        Add remaining description here"""
        
    def __ne__(self, other):
         """The result should not have leading 0's. 
        Add remaining description here"""
    
    
        
    
        
if __name__ == '__main__':
    N = myBinaryInteger('111')
    print(N)
    M = myBinaryInteger(None, 10)
    print(M)
    M[2] = 1 # 2 here denotes the position from the right (i.e., LSB side)
    print(M)
    # We can use "bin()" to work with large integers
    # bin() converts an integer to binary string
    N = myBinaryInteger('-' + bin(8037048730845703847503874508374508347530847)[2:])
    print(N)
    N1 = int(str(N), 2) # Converts string in binary to decimal
    print(N1)
