// Origin.C
// ----------------------------------------------------------------
// COMP 290-001: Algorithm Library Design, Lutz Kettner, 01/11/2000
// Example for the symbolic origin to convert between points and vectors.

#include <iostream.h>

struct Origin {};
static const Origin ORIGIN = Origin();

struct Tuple {
    int x;
    int y;
    Tuple( int xx, int yy) : x(xx), y(yy) {}
    Tuple operator-()                const { return Tuple( -x, -y); }
    Tuple operator+( const Tuple& t) const { return Tuple( x + t.x, y + t.y); }
    Tuple operator-( const Tuple& t) const { return Tuple( x - t.x, y - t.y); }
};

class Vector; // forward declaration

class Point {
    Tuple tpl;
    Point( const Tuple& t) : tpl(t) {}
public:
    Point( int xx, int yy) : tpl(xx,yy) {}
    int x() const { return tpl.x;}
    int y() const { return tpl.y;}

    Point  operator+( const Vector& v) const;
    Point  operator-( const Vector& v) const;
    Vector operator-( const Point& p)  const;

    friend inline Vector operator-( const Point& p, Origin);
    friend inline Vector operator-( Origin, const Point& p);
    friend inline Point  operator+( Origin, const Vector& v);
    friend inline Point  operator-( Origin, const Vector& v);
};

class Vector {
    friend class Point;
    Tuple tpl;
    Vector( const Tuple& t) : tpl(t) {}
public:
    Vector( int xx, int yy) : tpl(xx,yy) {}
    int x() const { return tpl.x;}
    int y() const { return tpl.y;}

    Vector operator-()                 const { return -tpl; }
    Vector operator+( const Vector& v) const { return tpl + v.tpl; }
    Vector operator-( const Vector& v) const { return tpl - v.tpl; }

    friend inline Vector operator-( const Point&, Origin);
    friend inline Vector operator-( Origin, const Point&);
    friend inline Point  operator+( Origin, const Vector&);
    friend inline Point  operator-( Origin, const Vector&);
};

inline Point  Point::operator+( const Vector& v) const { return tpl + v.tpl; }
inline Point  Point::operator-( const Vector& v) const { return tpl - v.tpl; }
inline Vector Point::operator-( const Point& p)  const { return tpl - p.tpl; }

// Operations are inline and we rely on the compiler to figure out that
// actually nothing happens here (so, no explicit type cast written here).
inline Vector operator-( const Point& p, Origin)  { return p.tpl; }
inline Vector operator-( Origin, const Point& p)  { return -p.tpl;}
inline Point  operator+( Origin, const Vector& v) { return v.tpl; }
inline Point  operator-( Origin, const Vector& v) { return -v.tpl;}

int main() {
    Point  p(1,2);
    Point  q(3,4);
    Vector v(1,2);
    Point  r = q + v;
    Vector w = p - ORIGIN;
    Point  s = ORIGIN + v;
    // Point  t = p + q; // illegal
}

