#<p>
#  This file is in the public domain.
#</p>
#<p>
#  Author: Steve Wampler (sbw@tapestry.tucson.az.us)
#</p>

package math

#<p>
#  A complex number representation that supports overloading the
#  basic numeric operators ("<tt>+</tt>","<tt>-</tt>",
#  "<tt>*</tt>","<tt>/</tt>") to work with complex numbers.
#  Note that Unicon's operator overloading implementation requires
#  that the <i>left</i> operand be of the overloaded type.
#  That is, <tt>Complex(1,2)+3</tt> works but <tt>3+Complex(1,2)</tt>
#  doesn't.
#  <b>Operator overloading only works with Unicon configured with
#  the <tt>--enable-ovld</tt> flag.  However, this class provides
#  methods that can be invoked directly, as in: <tt>Complex(3,1).add(4)</tt></b>
#</p>
class Complex(r,i)

    #<p>Add a scalar or Complex to this complex number.
    #   Fails if right operator cannot be converted to Complex.
    #</p>
    method add(x)
       if x := convert(x) then return Complex(r+x.r,i+x.i)
    end

    #<p>Subtract a scalar or Complex from this complex number.
    #   Fails if right operator cannot be converted to Complex.
    #</p>
    method minus(x)
       if x := convert(x) then return Complex(r-x.r,i-x.i)
    end

    #<p>Multiply this complex number by a scalar or Complex.
    #   Fails if right operator cannot be converted to Complex.
    #</p>
    method mult(x)
       if x := convert(x) then return Complex(r*x.r-i*x.i, r*x.i+i*x.r)
    end

    #<p>Divide this complex number by a scalar or Complex.
    #   In the result, both the real and imaginary parts are
    #   represented as floating point values.
    #   Fails if right operator cannot be converted to Complex.
    #</p>
    method div(x)
       if x := convert(x) then {
          c := x.conjugate()
          n := self.mult(c)
          d := ::real((x.mult(c)).r)
          return Complex(n.r/d,n.i/d)
          }
    end

    #<p>Overload the "+" binary operator.
    #   Fails if right operator cannot be converted to Complex.
    #</p>
    method __add__(x)
       return add(x)
    end

    #<p>Overload the "-" binary operator.
    #   Fails if right operator cannot be converted to Complex.
    #</p>
    method __minus__(x)
       return minus(x)
    end

    #<p>Overload the "*" binary operator.
    #   Fails if right operator cannot be converted to Complex.
    #</p>
    method __mult__(x)
       return mult(x)
    end

    #<p>Overload the "/" binary operator.
    #   In the result, both the real and imaginary parts are
    #   represented as floating point values.
    #   Fails if right operator cannot be converted to Complex.
    #</p>
    method __div__(x)
       return div(x)
    end

    #<p>
    #  Produce the complex conjugate of this complex number.
    #  <i>Note: no support for operator overloading for this operation.</i>
    #</p>
    method conjugate()
       return Complex(r, -i)
    end

    #<p>
    #  Produce the additive inverse of this complex number.
    #  <i>Note: no support for operator overloading for this operation
    #  because there is no such operator in Unicon.</i>
    #</p>
    method addInverse()
       return Complex(-r, -i)
    end

    #<p>
    #  Produce the multiplicative inverse of this complex number.
    #  <i>Note: no support for operator overloading for this operatio
    #  because there is no such operator in Unicon.</i>
    #</p>
    method multInverse()
       n := conjugate()
       d := ::real(r^2 + i^2)
       return Complex(n.r/d, n.i/d)
    end

    #<p>
    #  Produce a string representation of this complex number.
    #</p>
    method toString()
       return "("||r||","||i||"i)"
    end

    #<p>
    #  Convert x into a complex number, if possible.
    #  <i>Used internally.</i>
    #</p>
    method convert(x)
       if ::type(x) == "math__Complex__state" then return x
       return Complex(::numeric(x),0)
    end

    initially (pr,pi)
       r := \pr | 0
       i := \pi | 0
end
