#!/usr/bin/env python3
"""
 murd.py - t2isarvulise lugeja ja nimetajaga murd
"""


class Murd(object):
    
    __lugeja = 0
    __nimetaja = 1

    @staticmethod
    def suurim_yhistegur(a, b):
        m = int(max(abs(a), abs(b)))
        n = int(min(abs(a), abs(b)))
        if n == 0:
            raise ArithmeticError("Nullist ei saa leida suurimat yhistegurit")
        while n > 0:
            uus = m % n
            m = n
            n = uus
        return m

    def __init__(self, lugeja, nimetaja):
        lug = int(lugeja)
        nim = int(nimetaja)
        if nim == 0:
            raise ZeroDivisionError("Murru nimetaja ei saa olla null")
        if lug == 0:
            nim = 1
        else:
            syt = Murd.suurim_yhistegur(lug, nim)
            lug = lug // syt
            nim = nim // syt
        if nim < 0:
            lug = -lug
            nim = -nim
        self.__lugeja = lug
        self.__nimetaja = nim

    def lugeja(self):
        return self.__lugeja

    def nimetaja(self):
        return self.__nimetaja

    def real_value(self):
        return self.lugeja()/self.nimetaja()

    def __str__(self):
        return str(self.lugeja()) + "/" + str(self.nimetaja())

    def __repr__(self):
        return "Murd(" + str(self.lugeja()) + ", " + str(self.nimetaja()) + ")"

    def __eq__(self, other):
        # return self.real_value() == other.real_value()
        # return self.__hash__() == other.__hash__()
        return self.lugeja()*other.nimetaja() == self.nimetaja()*other.lugeja()

    def __gt__(self, other):
        return self.lugeja()*other.nimetaja() > self.nimetaja()*other.lugeja()

    def __ge__(self, other):
        return self.__gt__(other) or self.__eq__(other)

    def __bool__(self):
        return self.lugeja() != 0

    def __hash__(self):
        return hash(str(self))   # % 2147483648  # to make it 32-bit

    def plus(self, other):
        return Murd(self.lugeja()*other.nimetaja() +
                    self.nimetaja()*other.lugeja(),
                    self.nimetaja()*other.nimetaja())

    def opposite(self):
        return Murd(-self.lugeja(), self.nimetaja())

    def inverse(self):
        return Murd(self.nimetaja(), self.lugeja())

    def minus(self, other):
        return self.plus(other.opposite())

    def times(self, other):
        return Murd(self.lugeja()*other.lugeja(),
                    self.nimetaja()*other.nimetaja())

    def divide_by(self, other):
        return self.times(other.inverse())

    @staticmethod
    def parse_murd(tekst):
        lug, nim = tekst.split("/")
        return Murd(lug, nim)


def main():
    """
    Main method.
    """
    m1 = Murd(2, 7)
    print(m1.real_value())
    print(m1.plus(m1))
    print(m1.__repr__())
    m2 = Murd.parse_murd("1/-3 ")
    print(m2)
    print(Murd(223372036854775806, 223372036854775807).real_value())
    print(str(hash(Murd(386, 3))))
    print(str(hash(Murd(86, 113))))
    print(str(hash(Murd(249, 109))))
    print(str(hash(Murd(148, 5))))
    s = 1
    while True:
        s = s + 1
        print(str(s))
        for i in range(1, s):
            m1 = Murd(i, s-i)
            h1 = hash(m1)
            for t in range(1, s+1):
                for j in range(1, t):
                    m2 = Murd(j, t-j)
                    h2 = hash(m2)
                    if h1 == h2:
                        # print(str(i) + " " + str(s-i) + " " + str(j) + " " + str(t-j))
                        if m1.lugeja() != m2.lugeja() or m1.nimetaja() != m2.nimetaja():
                            print("hash=" + str(h1) + " m1=" + str(m1) + " m2=" + str(m2))
                            exit(0)


if __name__ == '__main__':
    main()
