# L-25 MCS 260 : quaternion
"""
Another illustration of operator overloading.
"""

class Quaternion(object):
    """
    Quaternions are hypercomplex numbers.
    """
    count = 0   # class data attributes
    who = []

    def __init__(self, a=0, b=0, c=0, d=0):
        """
        Constructs the Quaternion with
        coefficients a,b,c,d.
        """
        self.cre = a  # real part
        self.cim = b  # imaginary part
        self.cjj = c  # j-part
        self.ckk = d  # k-part
        Quaternion.count += 1
        Quaternion.who.append(self)

    def __str__(self):
        """
        The string representation of a Quaternion
        uses i, j, and k.  Note the + in the format.
        """
        return '%.2f %+.2f i %+.2f j %+.2f k' \
            % (self.cre, self.cim, self.cjj, self.ckk)

    def __repr__(self):
        """
        The representation of a quaternion is
        by default the string representation.
        """
        return str(self)

    def __eq__(self, other):
        """
        Defines Quaternion Equality.
        """
        return self.cre == other.cre and \
               self.cim == other.cim and \
               self.cjj == other.cjj and \
               self.ckk == other.ckk

    def __neg__(self):
        """
        The negation of a Quaternion.
        """
        return Quaternion(-self.cre, \
                          -self.cim, \
                          -self.cjj, \
                          -self.ckk)

    def __add__(self, other):
        """
        Adding two Quaternions"
        """
        return Quaternion(self.cre + other.cre, \
                          self.cim + other.cim, \
                          self.cjj + other.cjj, \
                          self.ckk + other.ckk)

    def __iadd__(self, other):
        """
        Inplace Adder of two Quaternions.
        """
        # We have to create a new object!
        return Quaternion(self.cre + other.cre, \
                          self.cim + other.cim, \
                          self.cjj + other.cjj, \
                          self.ckk + other.ckk)

    def __abs__(self):
        """
        Returns the magnitude of a Quaternion.
        """
        from math import sqrt
        return sqrt(self.cre**2+self.cim**2 \
                   +self.cjj**2+self.ckk**2)

    def conjugate(self):
        """
        Returns the conjugate of a Quaternion.
        """
        return Quaternion(self.cre, -self.cim, \
                         -self.cjj, -self.ckk)

    def scamul(self, scx):
        """
        Product of Quaternion with scalar scx.
        """
        return Quaternion(self.cre*scx, self.cim*scx, \
                          self.cjj*scx, self.ckk*scx)

    def __invert__(self):
        """
        The Inverse of the Quaternion.
        """
        return self.conjugate().scamul(1/abs(self))
