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

#ifndef __TiFPtSizeRect_h__
#define __TiFPtSizeRect_h__

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

class TiFPoint
{
public:
  float32   x;
  float32   y;

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

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

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

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

  TiFPoint operator *(float32 nScalar) const
  {
    TiFPoint pt = *this;
    pt.x *= nScalar;
    pt.y *= nScalar;
    return pt;
  }

  TiFPoint operator /(float32 nScalar) const
  {
    TiFPoint pt = *this;
    if(nScalar == 0.f)
      return pt;
    pt.x /= nScalar;
    pt.y /= nScalar;
    return pt;
  }

  operator TiPoint() const
  {
    TiPoint pt;
    pt.x = (int32)x;
    pt.y = (int32)y;
    return pt;
  }

  bool operator ==(const TiFPoint &ptOther) const
  {
    return (x == ptOther.x) && (y == ptOther.y);
  }

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


class TiFSize
{
public:
  float32   cx;
  float32   cy;

  TiFSize(const TiSize &size) {cx = (float32)size.cx; cy = (float32)size.cy;}
  TiFSize(const TiFSize &size) {cx = size.cx; cy = size.cy;}
  TiFSize(int32 nCX, int32 nCY) {cx = (float32)nCX; cy = (float32)nCY;}
  TiFSize(float32 nCX, float32 nCY) {cx = nCX; cy = nCY;}
  TiFSize() {}

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

  TiFSize(const TiFPoint &pt)
  {
    cx = pt.x;
    cy = pt.y;
  }

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

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

  TiFSize operator *(int32 nScalar) const
  {
    TiFSize size = *this;
    size.cx *= nScalar;
    size.cy *= nScalar;
    return size;
  }

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

class TiFRect
{
public:
  float32   left;
  float32   top;
  float32   right;
  float32   bottom;

  TiFRect(const TiRect &rect)
  {
    left = (float32)rect.left;
    top = (float32)rect.top;
    right = (float32)rect.right;
    bottom = (float32)rect.bottom;
  }
  TiFRect(int32 nLeft, int32 nTop, int32 nRight, int32 nBottom) 
  {
    left = (float32)nLeft;
    top = (float32)nTop;
    right = (float32)nRight;
    bottom = (float32)nBottom;
  }
  TiFRect(float32 nLeft, float32 nTop, float32 nRight, float32 nBottom) 
  {
    left = nLeft;
    top = nTop;
    right = nRight;
    bottom = nBottom;
  }
  TiFRect()	{left = top = right = bottom = 0.f;}
  TiFRect(TiFPoint pt, TiFSize size)
  {
    left = pt.x;
    top = pt.y;
    right = pt.x + size.cx;
    bottom = pt.y + size.cy;
  }
  TiFRect(TiFPoint pt1, TiFPoint pt2)
  {
    left = pt1.x;
    top = pt1.y;
    right = pt2.x;
    bottom = pt2.y;
  }

  void    SetRect(TiFPoint pt, TiFSize 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 = (float32)l;
    top = (float32)t;
    right = (float32)r;
    bottom = (float32)b;
  }
  void    SetRect(float32 l, float32 t, float32 r, float32 b)
  {
    left = l;
    top = t;
    right = r;
    bottom = b;
  }
  void    SetRect(TiFPoint pt1, TiFPoint pt2)
  {
    left = pt1.x;
    top = pt1.y;
    right = pt2.x;
    bottom = pt2.y;
  }
  void    SetSize(TiFSize size)
  {
    right = left + size.cx;
    bottom = top + size.cy;
  }
  void    MoveTo(TiFPoint pt)
  {
    SetRect(pt, GetSize());
  }
  void    MoveBy(TiFPoint pt)
  {
    SetRect(TopLeft()+pt, GetSize());
  }
  void    SetRectEmpty()
  {
    left = top = right = bottom = 0.f;
  }

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


  float32 Width() const {return right - left;}
  float32 Height() const {return bottom - top;}
  TiFSize   Size() const {return GetSize();}
  TiFSize	GetSize() const {return TiFSize(Width(), Height());}
  bool	PtInRect(TiFPoint 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;
  }

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

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

  TiFRect operator +(TiFPoint pt) const
  {
    TiFRect rect = *this;
    rect += pt;
    return rect;
  }

  TiFRect operator -(TiFPoint pt) const
  {
    TiFRect rect = *this;
    rect -= pt;
    return rect;
  }

  bool operator ==(TiFRect otherRect) const
  {
    TiFRect 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(float32 x, float32 y)
  {
    left -= x;
    right += x;
    top -= y;
    bottom += y;
  }
  void DeflateRect(float32 dx, float32 dy)
  {
    AdjustSize(-dx, -dy);
  }
  void InflateRect(float32 dx, float32 dy)
  {
    AdjustSize(dx, dy);
  }


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

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

  TiFRect operator &(TiFRect rectOther) const   // intersection
  {
    TiFRect 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(TiFRect *lpRect1, TiFRect *lpRect2) 
  {
    TiFRect rect1(lpRect1->left, lpRect1->top, lpRect1->right, lpRect1->bottom);
    TiFRect rect2(lpRect2->left, lpRect2->top, lpRect2->right, lpRect2->bottom);
    *this = rect1 & rect2;
    return IsRectEmpty();
  }

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

  operator TiRect() const
  {
    TiRect rect;
    rect.left = (int32)left;
    rect.top = (int32)top;
    rect.right = (int32)right;
    rect.bottom = (int32)bottom;
    return rect;
  }

  TiFRect operator |(TiFRect rectOther)   const // union
  {
    TiFRect 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.f && Height() == 0.f);
  }
  bool    IsAbnormal() const
  {
    return(Width() <= 0.f || Height() <= 0.f);
  }
};

const TiFSize c_fsizePS3Screen(1920.f, 1080.f);
const TiFRect c_frectPS3Screen(0.f, 0.f, 1920.f, 1080.f);

#endif

