/* Demonstrate how operator overloading and array-valued expressions
 * interact
 */
class complex {
    protected var real, imag;
    public proc create(r,i) {
        real = Float(r);
        imag = (oadl::nargs() > 1) ? Float(i) : 0.0;
    }
    operator + (rhs) {
        // lhs is self
        if (rhs.isarray()) {
            // Complex + array - have to promote LHS to an array of length 1
            // to get OADL array semantics to kick in
            var lhs = self.reshape(rhs.shape());
            return lhs + rhs;
        }
        else if (rhs ?= complex) {
            // Complex + complex
            return new complex(real + rhs.real, imag + rhs.imag);
        }
        else {
            // Complex + real
            return new complex(real + rhs, imag);
        }
    }
    operator \+ (lhs) {
        if (lhs.isarray()) {
            // Array + complex - have to promote RHS to an array of length 1
            // to get OADL array semantics to kick in
            var rhs = self.reshape(lhs.shape());
            return lhs + rhs;
        }
        else if (lhs ?= complex) {
            // Complex + complex
            return new complex(lhs.real + real, lhs.imag + imag);
        }
        else {
            // Complex + real
            return new complex(lhs + real, imag);
        }
    }
    operator => (rhs) {
        if (rhs == String) {
            // Create a string representation "(r,i)"
            return "(" ## String(real) ## "," ## String(imag) ## ")";
        }
        else {
            // Typically, converting a complex to a float
            return rhs(real);
        }
    }
    operator \=> (lhs) {
        // Typically, converting a float to a complex
        return new complex(lhs);
    }
}

proc main()
{
    var a = {complex( 1, 2), complex( 3, 4), complex( 5, 6)};
    var b = {complex(10,20), complex(30,40), complex(50,60)};
    var c;

    c = a + b;
    "c = { ", String(c[0]), ", ", String(c[1]), ", ", String(c[2]), " }\n";

    c = {complex(100,200)}.reshape(3) + a;
    "c = { ", String(c[0]), ", ", String(c[1]), ", ", String(c[2]), " }\n";

    c = complex(300,400) + a;
    "c = { ", String(c[0]), ", ", String(c[1]), ", ", String(c[2]), " }\n";

    c = a + complex(500,600);
    "c = { ", String(c[0]), ", ", String(c[1]), ", ", String(c[2]), " }\n";
}