# Multiparadigm Programming with Python 3
# Rational Representation Module -- Core
# Copyright (C) 2018, H. Conrad Cunningham
#
# 34567890123456789012345678901234567890123456789012345678901234567890
#
# 2018-10-19: Original Python version (referencing Haskell versions)
# 2018-11-01: Cleanup based on flake8, pylint, & black runs

from __future__ import annotations  # 3.7 deferred annotations
from typing import ClassVar, Optional, Tuple
import math

from rational_rep import RatRep


class RatCore(RatRep):
    """
    Represent rational number as a tuple of relatively prime integers,
     with (0,1) for zero
    """

    _zero: ClassVar[Optional[RatCore]] = None
    r: Tuple[int, int]  # instance variable

    def __init__(self, x: int, y: int) -> None:
        """Initialize rational number x/y"""
        if y == 0:
            raise ZeroDivisionError
        elif x == 0:
            self.r = (0, 1)            # zeroRat instance
        else:
            if y < 0:
                x, y = -x, -y
            d = math.gcd(x, y)         # greatest common divisor
            self.r = (x // d, y // d)  # integer division

    @classmethod
    def zeroRat(cls) -> RatRep:
        """Get canonical representation for zero"""
        if cls._zero is None:
            cls._zero = RatCore(0, 1)
        return cls._zero

    def numer(self) -> int:
        """Get numerator of rational number"""
        return self.r[0]

    def denom(self) -> int:
        """Get denominator of rational number"""
        return self.r[1]

    def __repr__(self):
        """Return string representation of rational number"""
        return str(self.r)
