// -*- C++ -*-
/* GG is a GUI for SDL and OpenGL.
   Copyright (C) 2003-2008 T. Zachary Laine

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public License
   as published by the Free Software Foundation; either version 2.1
   of the License, or (at your option) any later version.
   
   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.
    
   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA

   If you do not wish to comply with the terms of the LGPL please
   contact the author as other terms are available for a fee.
    
   Zach Laine
   whatwasthataddress@gmail.com */

/** \file PtRect.h \brief Contains the utility classes Pt and Rect. */

#ifndef _GG_PtRect_h_
#define _GG_PtRect_h_

#include <GG/Base.h>
#include <GG/StrongTypedef.h>


namespace GG {

/** \class GG::X
    \brief The x-coordinate value type.

    X has an underlying value type of int.  \see GG_STRONG_INTEGRAL_TYPEDEF */
GG_STRONG_INTEGRAL_TYPEDEF(X, int);

/** \class GG::Y
    \brief The y-coordinate value type.

    Y has an underlying value type of int.  \see GG_STRONG_INTEGRAL_TYPEDEF */
GG_STRONG_INTEGRAL_TYPEDEF(Y, int);

// some useful coordinate constants
extern GG_API const X X0;
extern GG_API const X X1;
extern GG_API const Y Y0;
extern GG_API const Y Y1;

/** \brief A GG screen coordinate class. */
struct GG_API Pt
{
    /** \name Structors */ ///@{
    Pt();               ///< Default ctor.
    Pt(X x_, Y y_);     ///< Ctor that creates a Pt ( \a _x , \a y ).
    Pt(X_d x_, Y y_);   ///< Ctor that creates a Pt ( \a _x , \a y ).
    Pt(X x_, Y_d y_);   ///< Ctor that creates a Pt ( \a _x , \a y ).
    Pt(X_d x_, Y_d y_); ///< Ctor that creates a Pt ( \a _x , \a y ).
    //@}

    /** \name Accessors */ ///@{
    /** Returns true if x < \a rhs.x or returns true if x == \a rhs.x and y
        <\a rhs.y.  This is useful for sorting Pts in STL containers and
        algorithms. */
    bool Less(const Pt& rhs) const
        { return x < rhs.x ? true : (x == rhs.x ? (y < rhs.y ? true : false) : false); }
    //@}

    /** \name Mutators */ ///@{
    void  operator+=(const Pt& rhs)      { x += rhs.x; y += rhs.y; } ///< Adds \a rhs to Pt.
    void  operator-=(const Pt& rhs)      { x -= rhs.x; y -= rhs.y; } ///< Subtracts \a rhs to Pt.
    Pt    operator-() const              { return Pt(-x, -y); }      ///< Negates Pt.
    //@}

    X x; ///< The x component.
    Y y; ///< The y component.
};

/** \brief A GG rectangle class.

    This is essentially just two points that bound the rectangle. */
struct GG_API Rect
{
    /** \name Structors */ ///@{
    Rect();                                ///< default ctor
    Rect(const Pt& pt1, const Pt& pt2);    ///< ctor that constructs a Rect from two corners; any two opposing corners will do
    Rect(X x1, Y y1, X x2, Y y2);  ///< ctor that constructs a Rect from its left, upper, right, and bottom boundaries
    //@}

    /** \name Accessors */ ///@{
    X  Left() const         { return ul.x; }        ///< returns the left boundary of the Rect
    X  Right() const        { return lr.x; }        ///< returns the right boundary of the Rect
    Y  Top() const          { return ul.y; }        ///< returns the top boundary of the Rect
    Y  Bottom() const       { return lr.y; }        ///< returns the bottom boundary of the Rect
    Pt UpperLeft() const    { return ul; }          ///< returns the upper-left corner of the Rect
    Pt LowerRight() const   { return lr; }          ///< returns the lower-right corner of the Rect
    X  Width() const        { return lr.x - ul.x; } ///< returns the width of the Rect
    Y  Height() const       { return lr.y - ul.y; } ///< returns the height of the Rect

    bool  Contains(const Pt& pt) const; ///< returns true iff \a pt falls inside the Rect
    //@}

    /** \name Mutators */ ///@{
    void operator+=(const Pt& pt)      { ul += pt; lr += pt; } ///< shifts the Rect by adding \a pt to each corner
    void operator-=(const Pt& pt)      { ul -= pt; lr -= pt; } ///< shifts the Rect by subtracting \a pt from each corner
    //@}

    Pt ul; ///< the upper-left corner of the Rect
    Pt lr; ///< the lower-right corner of the Rect
};

GG_API inline bool operator==(const Pt& lhs, const Pt& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y; } ///< returns true if \a lhs is identical to \a rhs
GG_API inline bool operator!=(const Pt& lhs, const Pt& rhs) { return !(lhs == rhs); }                    ///< returns true if \a lhs differs from \a rhs
GG_API inline bool operator<(const Pt& lhs, const Pt& rhs)  { return lhs.x < rhs.x && lhs.y < rhs.y; }   ///< returns true if \a lhs.x and \a lhs.y are both less than the corresponding components of \a rhs
GG_API inline bool operator>(const Pt& lhs, const Pt& rhs)  { return lhs.x > rhs.x && lhs.y > rhs.y; }   ///< returns true if \a lhs.x and \a lhs.y are both greater than the corresponding components of \a rhs
GG_API inline bool operator<=(const Pt& lhs, const Pt& rhs) { return lhs.x <= rhs.x && lhs.y <= rhs.y; } ///< returns true if \a lhs.x and \a lhs.y are both less than or equal to the corresponding components of \a rhs
GG_API inline bool operator>=(const Pt& lhs, const Pt& rhs) { return lhs.x >= rhs.x && lhs.y >= rhs.y; } ///< returns true if \a lhs.x and \a lhs.y are both greater than or equal to the corresponding components of \a rhs
GG_API inline Pt   operator+(const Pt& lhs, const Pt& rhs)  { return Pt(lhs.x + rhs.x, lhs.y + rhs.y); } ///< returns the vector sum of \a lhs and \a rhs
GG_API inline Pt   operator-(const Pt& lhs, const Pt& rhs)  { return Pt(lhs.x - rhs.x, lhs.y - rhs.y); } ///< returns the vector difference of \a lhs and \a rhs

GG_API std::ostream& operator<<(std::ostream& os, const Pt& pt); ///< Pt stream-output operator for debug output

/** returns true if \a lhs is identical to \a rhs */
GG_API inline bool operator==(const Rect& lhs, const Rect& rhs) { return lhs.ul.x == rhs.ul.x && lhs.lr.x == rhs.lr.x && lhs.ul.y == rhs.ul.y && lhs.lr.y == rhs.lr.y; }

/** returns true if \a lhs differs from \a rhs */
GG_API inline bool operator!=(const Rect& lhs, const Rect& rhs) { return !(lhs == rhs); }

GG_API inline Rect operator+(const Rect& rect, const Pt& pt) { return Rect(rect.ul + pt, rect.lr + pt); } ///< returns \a rect shifted by adding \a pt to each corner
GG_API inline Rect operator-(const Rect& rect, const Pt& pt) { return Rect(rect.ul - pt, rect.lr - pt); } ///< returns \a rect shifted by subtracting \a pt from each corner
GG_API inline Rect operator+(const Pt& pt, const Rect& rect) { return rect + pt; } ///< returns \a rect shifted by adding \a pt to each corner
GG_API inline Rect operator-(const Pt& pt, const Rect& rect) { return rect - pt; } ///< returns \a rect shifted by subtracting \a pt from each corner

GG_API std::ostream& operator<<(std::ostream& os, const Rect& rect); ///< Rect stream-output operator for debug output

} // namepace GG

#endif
