// rectangle and point classes - based on MFC's TiRect and TiPoint
// I finally broke down and wrote these because I really like them

#ifndef __TiPtSizeRect_h__
#define __TiPtSizeRect_h__

#include "SyTypes.h"
#include "SyMath.h"

class TiPoint
{
public:
    int32   x;
    int32   y;

    TiPoint(const TiPoint &pt) {x = pt.x; y = pt.y;}
	TiPoint(int32 nX, int32 nY) {x = nX; y = nY;}
	TiPoint() {x = 0; y = 0;}

    void    Set(int32 nX, int32 nY)
    {
        x = nX;
        y = nY;
    }
	TiPoint operator =(const TiPoint &pt)
	{
		x = pt.x;
		y = pt.y;
		return *this;
	}
	TiPoint operator +=(const TiPoint &pt) 
	{
		x += pt.x; 
		y += pt.y;
		return *this;
	}
	TiPoint operator -=(const TiPoint &pt) 
	{
		x -= pt.x; 
		y -= pt.y;
		return *this;
	}

	TiPoint operator +(const TiPoint &ptOther) const
	{
		TiPoint pt = *this;
		pt += ptOther;
		return pt;
	}

	TiPoint operator -(const TiPoint &ptOther) const
	{
		TiPoint pt = *this;
		pt -= ptOther;
		return pt;
	}

	TiPoint operator *(int32 nScalar) const
	{
		TiPoint pt = *this;
		pt.x *= nScalar;
        pt.y *= nScalar;
		return pt;
	}
    
	TiPoint operator /(int32 nScalar) const
	{
		TiPoint pt = *this;
        if(nScalar == 0)
            return pt;
		pt.x /= nScalar;
        pt.y /= nScalar;
		return pt;
	}
    
    bool operator ==(const TiPoint &ptOther) const
    {
        return (x == ptOther.x) && (y == ptOther.y);
    }

    bool operator !=(const TiPoint &ptOther) const
    {
        return !(*this == ptOther);
    }
};

class TiTinyPoint
{
public:
    int8 x;
    int8 y;

    TiTinyPoint(const TiPoint &pt) {x = pt.x; y = pt.y;}
	TiTinyPoint(int8 nX, int8 nY) {x = nX; y = nY;}
	TiTinyPoint() {x = 0; y = 0;}

    operator TiPoint () const
    {
        return TiPoint(x, y);
    }

    void    Set(int32 nX, int32 nY)
    {
        x = nX;
        y = nY;
    }
	TiTinyPoint operator =(const TiTinyPoint &pt)
	{
		x = pt.x;
		y = pt.y;
		return *this;
	}
	TiTinyPoint operator +=(const TiTinyPoint &pt) 
	{
		x += pt.x; 
		y += pt.y;
		return *this;
	}
	TiTinyPoint operator -=(const TiTinyPoint &pt) 
	{
		x -= pt.x; 
		y -= pt.y;
		return *this;
	}

	TiTinyPoint operator +(const TiTinyPoint &ptOther) const
	{
		TiTinyPoint pt = *this;
		pt += ptOther;
		return pt;
	}

	TiTinyPoint operator -(const TiTinyPoint &ptOther) const
	{
		TiTinyPoint pt = *this;
		pt -= ptOther;
		return pt;
	}

	TiTinyPoint operator *(int32 nScalar) const
	{
		TiTinyPoint pt = *this;
		pt.x *= nScalar;
        pt.y *= nScalar;
		return pt;
	}
    
	TiTinyPoint operator /(int32 nScalar) const
	{
		TiTinyPoint pt = *this;
        if(nScalar == 0)
            return pt;
		pt.x /= nScalar;
        pt.y /= nScalar;
		return pt;
	}
    
    bool operator ==(const TiTinyPoint &ptOther) const
    {
        return (x == ptOther.x) && (y == ptOther.y);
    }

    bool operator !=(const TiTinyPoint &ptOther) const
    {
        return !(*this == ptOther);
    }
};

class TiSize
{
public:
    int32   cx;
    int32   cy;

    TiSize(int32 nCX, int32 nCY) {cx = nCX; cy = nCY;}
	TiSize() {}

    void    SetSize(int32 nCX, int32 nCY) {cx = nCX; cy = nCY;}
    void    SetZero() { SetSize(0,0); }
    bool    IsZero() const 
    { 
        return (( cx == 0 ) && ( cy == 0 )); 
    }
    bool    IsAbnormal() const
    {
        return (( cx <= 0 ) || ( cy <= 0 ));
    }

    TiSize(const TiPoint &pt)
    {
        cx = pt.x;
        cy = pt.y;
    }

    TiSize operator -() const
    {
        TiSize size;
        size.cx = -cx;
        size.cy = -cy;
        return size;
    }

    TiSize operator +(const TiSize &other) const
    {
        TiSize size;
        size.cx = cx + other.cx;
        size.cy = cy + other.cy;
        return size;
    }
    TiSize operator -(const TiSize &other) const
    {
        TiSize size;
        size.cx = cx - other.cx;
        size.cy = cy - other.cy;
        return size;
    }

    TiSize operator *(int32 nScalar) const
	{
		TiSize size = *this;
		size.cx *= nScalar;
        size.cy *= nScalar;
		return size;
	}
    
	TiSize operator /(int32 nScalar) const
	{
		TiSize size = *this;
        if(nScalar == 0)
            return size;
		size.cx /= nScalar;
        size.cy /= nScalar;
		return size;
	}
};

class TiRect
{
public:
    int32   left;
    int32   top;
    int32   right;
    int32   bottom;

    TiRect(int32 nLeft, int32 nTop, int32 nRight, int32 nBottom) 
	{
		left = nLeft;
		top = nTop;
		right = nRight;
		bottom = nBottom;
	}
	TiRect()	{left = top = right = bottom = 0;}
	TiRect(TiPoint pt, TiSize size)
	{
		left = pt.x;
		top = pt.y;
		right = pt.x + size.cx;
		bottom = pt.y + size.cy;
	}
	TiRect(TiPoint pt1, TiPoint pt2)
	{
		left = pt1.x;
		top = pt1.y;
		right = pt2.x;
		bottom = pt2.y;
	}

    void    SetRect(TiPoint pt, TiSize size)
    {
		left = pt.x;
		top = pt.y;
		right = left + size.cx;
		bottom = top + size.cy;
    }
    void    SetRect(TiTinyPoint pt, TiSize size)
    {
		left = pt.x;
		top = pt.y;
		right = left + size.cx;
		bottom = top + size.cy;
    }

    void    SetRect(int32 l, int32 t, int32 r, int32 b)
    {
		left = l;
		top = t;
		right = r;
		bottom = b;
    }
    void    SetRect(TiPoint pt1, TiPoint pt2)
    {
		left = pt1.x;
		top = pt1.y;
		right = pt2.x;
		bottom = pt2.y;
    }
    void    SetSize(TiSize size)
    {
        right = left + size.cx;
        bottom = top + size.cy;
    }
    void    MoveTo(TiPoint pt)
    {
        SetRect(pt, GetSize());
    }
    void    MoveBy(TiPoint pt)
    {
        SetRect(TopLeft()+pt, GetSize());
    }
    void    SetRectEmpty()
    {
        left = top = right = bottom = 0;
    }

	TiPoint	TopLeft() const {return TiPoint(left, top);}
	TiPoint	BottomRight() const {return TiPoint(right, bottom);}
	TiPoint	TopRight() const {return TiPoint(right, top);}
	TiPoint	BottomLeft() const {return TiPoint(left, bottom);}
    TiPoint  CenterPoint() const {return TiPoint(left + (right - left) / 2, top + (bottom - top) / 2);}
    TiPoint  CenterTop() const {return TiPoint(left + (right - left) / 2, top);}
    TiPoint  CenterBottom() const {return TiPoint(left + (right - left) / 2, bottom);}
    TiPoint  LeftCenter() const {return TiPoint(left, top + (bottom - top) / 2);}
    TiPoint  RightCenter() const {return TiPoint(right, top + (bottom - top) / 2);}


	int32 Width() const {return right - left;}
	int32 Height() const {return bottom - top;}
    TiSize   Size() const {return GetSize();}
	TiSize	GetSize() const {return TiSize(Width(), Height());}
	bool	PtInRect(TiPoint pt) const
	{
        // include the top and left edges, but not the bottom and right edges
		if(pt.x >= left && 
			pt.x < right &&
			pt.y >= top &&
			pt.y < bottom)
		{
			return true;
		}
		return false;
	}

	TiRect operator =(TiRect rect)
	{
		left = rect.left;
		top = rect.top;
		right = rect.right;
		bottom = rect.bottom;
		return *this;
	}

	TiRect &operator +=(TiPoint pt)
	{
		left += pt.x;
		right += pt.x;
		top += pt.y;
		bottom += pt.y;
		return *this;
	}
	TiRect &operator -=(TiPoint pt)
	{
		left -= pt.x;
		right -= pt.x;
		top -= pt.y;
		bottom -= pt.y;
		return *this;
	}

	TiRect operator +(TiPoint pt) const
	{
		TiRect rect = *this;
		rect += pt;
		return rect;
	}

	TiRect operator -(TiPoint pt) const
	{
		TiRect rect = *this;
		rect -= pt;
		return rect;
	}

	bool operator ==(TiRect otherRect) const
	{
		TiRect thisRect = *this;
		if(thisRect.left == otherRect.left &&
			thisRect.top == otherRect.top &&
			thisRect.right == otherRect.right &&
			thisRect.bottom == otherRect.bottom)
			return true;

		return false;
	}

	void AdjustSize(int32 x, int32 y)
	{
		left -= x;
		right += x;
		top -= y;
		bottom += y;
	}
    void DeflateRect(int32 dx, int32 dy)
    {
        AdjustSize(-dx, -dy);
    }
    void InflateRect(int32 dx, int32 dy)
    {
        AdjustSize(dx, dy);
    }


    void AdjustSize(TiSize size)
	{
		left -= size.cx;
		right += size.cx;
		top -= size.cy;
		bottom += size.cy;
	}

    void Normalize()
    {
        int32 nTemp;
        if(left > right)
        {
            nTemp = left;
            left = right;
            right = nTemp;
        }
        if(top > bottom)
        {
            nTemp = top;
            top = bottom;
            bottom = nTemp;
        }
    }
    void NormalizeRect() {Normalize();}

    TiRect operator &(TiRect rectOther) const   // intersection
    {
        TiRect rect(-1, -1, -1, -1);

        // first look for non-intersection
        if(right < rectOther.left)
            return rect;
        if(left > rectOther.right)
            return rect;
        if(top > rectOther.bottom)
            return rect;
        if(bottom < rectOther.top)
            return rect;

        // definite intersection
        rect.left = SY_MAX(left, rectOther.left);
        rect.top = SY_MAX(top, rectOther.top);
        rect.right = SY_MIN(right, rectOther.right);
        rect.bottom = SY_MIN(bottom, rectOther.bottom);

        return rect;
    }

    bool IntersectRect(TiRect *lpRect1, TiRect *lpRect2) 
    {
        TiRect rect1(lpRect1->left, lpRect1->top, lpRect1->right, lpRect1->bottom);
        TiRect rect2(lpRect2->left, lpRect2->top, lpRect2->right, lpRect2->bottom);
        *this = rect1 & rect2;
        return IsRectEmpty();
    }

    bool IntsersectsWith(const TiRect &other) const
    {
        if(left >= other.right || right <= other.left || top >= other.bottom || bottom <= other.top)
            return false;
        return true;
    }

    TiRect operator |(TiRect rectOther)   const // union
    {
        TiRect rect;

        rect.left = SY_MIN(left, rectOther.left);
        rect.top = SY_MIN(top, rectOther.top);
        rect.right = SY_MAX(right, rectOther.right);
        rect.bottom = SY_MAX(bottom, rectOther.bottom);

        return rect;
    }

    bool    IsRectEmpty() const
    {
        return(Width() == 0 && Height() == 0);
    }
    bool    IsAbnormal() const
    {
        return(Width() <= 0 || Height() <= 0);
    }
};

class TiTinyRect
{
public:
    int8 left;
    int8 top;
    int8 right;
    int8 bottom;

    TiTinyRect(int32 nLeft, int32 nTop, int32 nRight, int32 nBottom) 
	{
		left = nLeft;
		top = nTop;
		right = nRight;
		bottom = nBottom;
	}
	TiTinyRect()	{left = top = right = bottom = 0;}
	TiTinyRect(TiTinyPoint pt, TiSize size)
	{
		left = pt.x;
		top = pt.y;
		right = pt.x + size.cx;
		bottom = pt.y + size.cy;
	}
	TiTinyRect(TiTinyPoint pt1, TiTinyPoint pt2)
	{
		left = pt1.x;
		top = pt1.y;
		right = pt2.x;
		bottom = pt2.y;
	}

    void    SetRect(TiTinyPoint pt, TiSize size)
    {
		left = pt.x;
		top = pt.y;
		right = left + size.cx;
		bottom = top + size.cy;
    }

    void    SetRect(int32 l, int32 t, int32 r, int32 b)
    {
		left = l;
		top = t;
		right = r;
		bottom = b;
    }
    void    SetRect(TiTinyPoint pt1, TiTinyPoint pt2)
    {
		left = pt1.x;
		top = pt1.y;
		right = pt2.x;
		bottom = pt2.y;
    }
    void    SetSize(TiSize size)
    {
        right = left + size.cx;
        bottom = top + size.cy;
    }
    void    MoveTo(TiTinyPoint pt)
    {
        SetRect(pt, GetSize());
    }
    void    MoveBy(TiTinyPoint pt)
    {
        SetRect(TopLeft()+pt, GetSize());
    }
    void    SetRectEmpty()
    {
        left = top = right = bottom = 0;
    }

	TiTinyPoint	TopLeft() const {return TiTinyPoint(left, top);}
	TiTinyPoint	BottomRight() const {return TiTinyPoint(right, bottom);}
	TiTinyPoint	TopRight() const {return TiTinyPoint(right, top);}
	TiTinyPoint	BottomLeft() const {return TiTinyPoint(left, bottom);}
    TiTinyPoint  CenterPoint() const {return TiTinyPoint(left + (right - left) / 2, top + (bottom - top) / 2);}
    TiTinyPoint  CenterTop() const {return TiTinyPoint(left + (right - left) / 2, top);}
    TiTinyPoint  CenterBottom() const {return TiTinyPoint(left + (right - left) / 2, bottom);}
    TiTinyPoint  LeftCenter() const {return TiTinyPoint(left, top + (bottom - top) / 2);}
    TiTinyPoint  RightCenter() const {return TiTinyPoint(right, top + (bottom - top) / 2);}


	int32 Width() const {return right - left;}
	int32 Height() const {return bottom - top;}
    TiSize   Size() const {return GetSize();}
	TiSize	GetSize() const {return TiSize(Width(), Height());}
	bool	PtInRect(TiTinyPoint pt) const
	{
        // include the top and left edges, but not the bottom and right edges
		if(pt.x >= left && 
			pt.x < right &&
			pt.y >= top &&
			pt.y < bottom)
		{
			return true;
		}
		return false;
	}

	TiTinyRect operator =(TiTinyRect rect)
	{
		left = rect.left;
		top = rect.top;
		right = rect.right;
		bottom = rect.bottom;
		return *this;
	}

	TiTinyRect &operator +=(TiTinyPoint pt)
	{
		left += pt.x;
		right += pt.x;
		top += pt.y;
		bottom += pt.y;
		return *this;
	}
	TiTinyRect &operator -=(TiTinyPoint pt)
	{
		left -= pt.x;
		right -= pt.x;
		top -= pt.y;
		bottom -= pt.y;
		return *this;
	}

	TiTinyRect operator +(TiTinyPoint pt) const
	{
		TiTinyRect rect = *this;
		rect += pt;
		return rect;
	}

	TiTinyRect operator -(TiTinyPoint pt) const
	{
		TiTinyRect rect = *this;
		rect -= pt;
		return rect;
	}

	bool operator ==(TiTinyRect otherRect) const
	{
		TiTinyRect thisRect = *this;
		if(thisRect.left == otherRect.left &&
			thisRect.top == otherRect.top &&
			thisRect.right == otherRect.right &&
			thisRect.bottom == otherRect.bottom)
			return true;

		return false;
	}

	void AdjustSize(int32 x, int32 y)
	{
		left -= x;
		right += x;
		top -= y;
		bottom += y;
	}
    void DeflateRect(int32 dx, int32 dy)
    {
        AdjustSize(-dx, -dy);
    }
    void InflateRect(int32 dx, int32 dy)
    {
        AdjustSize(dx, dy);
    }


    void AdjustSize(TiSize size)
	{
		left -= size.cx;
		right += size.cx;
		top -= size.cy;
		bottom += size.cy;
	}

    void Normalize()
    {
        int32 nTemp;
        if(left > right)
        {
            nTemp = left;
            left = right;
            right = nTemp;
        }
        if(top > bottom)
        {
            nTemp = top;
            top = bottom;
            bottom = nTemp;
        }
    }
    void NormalizeRect() {Normalize();}

    TiTinyRect operator &(TiTinyRect rectOther) const   // intersection
    {
        TiTinyRect rect(-1, -1, -1, -1);

        // first look for non-intersection
        if(right < rectOther.left)
            return rect;
        if(left > rectOther.right)
            return rect;
        if(top > rectOther.bottom)
            return rect;
        if(bottom < rectOther.top)
            return rect;

        // definite intersection
        rect.left = SY_MAX(left, rectOther.left);
        rect.top = SY_MAX(top, rectOther.top);
        rect.right = SY_MIN(right, rectOther.right);
        rect.bottom = SY_MIN(bottom, rectOther.bottom);

        return rect;
    }

    bool IntersectRect(TiTinyRect *lpRect1, TiTinyRect *lpRect2) 
    {
        TiTinyRect rect1(lpRect1->left, lpRect1->top, lpRect1->right, lpRect1->bottom);
        TiTinyRect rect2(lpRect2->left, lpRect2->top, lpRect2->right, lpRect2->bottom);
        *this = rect1 & rect2;
        return IsRectEmpty();
    }

    bool IntsersectsWith(const TiTinyRect &other) const
    {
        if(left >= other.right || right <= other.left || top >= other.bottom || bottom <= other.top)
            return false;
        return true;
    }

    TiTinyRect operator |(TiTinyRect rectOther)   const // union
    {
        TiTinyRect rect;

        rect.left = SY_MIN(left, rectOther.left);
        rect.top = SY_MIN(top, rectOther.top);
        rect.right = SY_MAX(right, rectOther.right);
        rect.bottom = SY_MAX(bottom, rectOther.bottom);

        return rect;
    }

    bool    IsRectEmpty() const
    {
        return(Width() == 0 && Height() == 0);
    }
    bool    IsAbnormal() const
    {
        return(Width() <= 0 || Height() <= 0);
    }
};

const TiSize c_sizePS3Screen(1920, 1080);
const TiRect c_rectPS3Screen(0, 0, 1920, 1080);

#endif

