(ns rosettacode.arithmetic.cmplx
  (:require [clojure.algo.generic.arithmetic:as ga])
  (:import [java.lang Number]))

(defrecord Complex [^Number r ^Number i]
  Object
  (toString [{:keys [r i]}]
    (apply str
      (cond
        (zero? r) [(if (= i 1) "" i) "i"]
        (zero? i) [r]
       :else     [r (if (neg? i) "-" "+") i "i"]))))

(defmethod ga/+ [Complex Complex]
  [x y] (map->Complex (merge-with + x y))) 

(defmethod ga/+ [Complex Number] 
  [{:keys [r i]} y] (->Complex (+ r y) i))

(defmethod ga/- Complex
  [x] (->> x vals (map -) (apply ->Complex)))

(defmethod ga/* [Complex Complex]
  [x y] (map->Complex (merge-with * x y)))

(defmethod ga/* [Complex Number]
  [{:keys [r i]} y] (->Complex (* r y) (* i y)))

(ga/defmethod* ga / Complex
  [x] (->> x vals (map /) (apply ->Complex)))

(defn conj [^Complex {:keys [r i]}]
  (->Complex r (- i)))

(defn inv [^Complex {:keys [r i]}]
  (let [m (+ (* r r) (* i i))]
    (->Complex (/ r m) (- (/ i m)))))