/****************************************************************************************


		MCRect.h


		Copyright: (c) 2001 Eovia Corp. All rights reserved.


		Author:	link and RSSource
		Date:	12/10/97

		Revision History

		when		who			what & why
		==========	==========	======================================================
		8/2/99		Ian			Bad recursive bug in PinPoint which was calling itself.
		04/20/99	Nba			Added SafeUnion
		1/20/99		Pbk			Moved the static at the end of of the declaration to help in teh debugger
		12/10/98	Thierry		inlined corner point accessors (often used)
		7/19/98		Ian			Had to include MCPoint.h.
		6/16/98		Ian			Point accesors now return a TMCPoint instead of filling
								in a TMCPoint&.
		6/2/98		Ian			Added LeftCenter() and RightCenter() point accessors.
		4/2/98		Ian			Moved operators into MCStreamOperators.

*****************************************************************************************/

#ifndef __MCRect__
#define __MCRect__

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "MCBasicTypes.h"
#include "MCBasicDefines.h"
#include "MCPoint.h"
#include "MCAssert.h"

class TMCiostream;
class TMCRealRect;


///Constants to identify the different sides of a rectangle
enum ERectangleSide
{
	kLeftSide,
	kTopSide,
	kRightSide,
	kBottomSide
};

inline boolean IsHorizontalSide	(ERectangleSide inSide) { return ((inSide == kTopSide) || (inSide == kBottomSide)); }
inline boolean IsVerticalSide	(ERectangleSide inSide) { return ((inSide == kLeftSide) || (inSide == kRightSide)); }


/// A rectangle class that uses integers.
///	\note
///	- The member component ordering is: left,top,right,bottom (x0,y0,x1,y1)
///	- This class cannot have virtual functions for C size compatability
///
class TMCRect : public TMCObject0
{
public:
	inline TMCRect					(void);
	inline TMCRect					(const int32 left, const int32 top, const int32 right, const int32 bottom);
	TMCRect							(const TMCPoint& topLeft, const TMCPoint& bottomRight);
	
	// element access	 	  		 
	inline int32 L					(void) const;
	inline int32 T					(void) const;
	inline int32 R					(void) const;
	inline int32 B					(void) const;
	
	///	Positions "centerRect" at the center of srcRect.
	///
	void CenterInside				(const TMCRect& inRect);

	///	Center the rect on a point.
	///
	void CenterTo					( const TMCPoint& inCenter );
	
	///	Gives "this" the maximum possible size at the center of inBounds that has the same ratio than inRatio
	///
	void MaximizeInside				(const TMCRect& inBounds, const TMCPoint& inRatio);
	
	///	Compare the components of the two rectangles and
	///	return TRUE if they are the same width and height.
	///
	boolean EqualDimensions			(const TMCRect& inRect ) const;
	
	///	Return TRUE if the rectangle has no width or height.
	///
	boolean Empty					(void) const;
	
	boolean Valid					() const;
	boolean Invalid					() const;
	
	/// UIFramework Compatibility: Equal().
	///	Compare the components of the two rectangles and
	///	return TRUE if they are all the same.
	///
	boolean Equal					(const TMCRect& inRect ) const;
	
	///	Calculate and return the width of the rectangle.
	///	May return a negative width.
	///
	inline int32 GetWidth			(void) const;
	
	///	Calculate and return the height of the rectangle.
	///	May return a negative width.
	///
	inline int32 GetHeight			(void) const;
	
	/// returns TMCPoint(GetWidth(), GetHeight())
	///
	inline TMCPoint GetSize			(void) const;
	
	///	Calculate and return the center of the rectangle.
	///
	TMCPoint GetCenter				(void) const;
	
	///	Calculate and return the area of the rectangle.
	///
	int32 GetArea					(void) const;
	
	///	InsetRect shrinks or expands the rectangle. The left and right
	///	sides are moved by dx; the top and bottom sides are moved by dy.
	///	Note: The rectangle is not set to an empty rect (0,0,0,0) if the
	///	resulting width or height is less than zero.
	///
	void Inset						(const int32 dx, const int32 dy);
	
	///	Intersect calculates the rectangle that is the intersection of "this" and
	///	the input rectangle, and returns TRUE if they indeed intersect or FALSE if
	///	they do not. If the rectangles do not intersect, the rect is set either empty
	///	or invalid based on the "inSetEmpty" flag.
	///
	boolean Intersect				(const TMCRect& inRect, const boolean inSetEmpty = 1);
	
	///	Offset moves the rectangle by adding dx to the horizontal
	///	coordinates, and adding dy to the vertical coordinates.
	///
	void Offset						(const int32 dx, const int32 dy);
	
	///	Pin the passed in point to within the rectangle and return the
	///	resulting point.
	///
	void PinPoint					(const TMCPoint& inPt, TMCPoint& outPoint) const;
	
	///	Pin the passed in point to within the rectangle and return the
	///	resulting point.
	///
	TMCPoint PinPoint				(const TMCPoint& inPt) const;
	
	///	Proportionally map src rect into dst. Warning: zero width or
	///	zero height rects are dangerous.
	///
	void Proportion					(const TMCRect& inRect);
	
	///	PtToRect returns the smallest rectangle which encloses the two
	///	input points.
	///
	void PtToRect					(const TMCPoint& pt1, const TMCPoint& pt2);
	
	///	PtInside determines whether a point is enclosed within the
	///	specified rectangle, and returns TRUE if so and FALSE if not.
	///
	boolean PtInside				(const TMCPoint& srcPt) const;
	
	///	RectInside determines whether a rectangle is enclosed within
	///	a second rectangle, and returns TRUE if so and FALSE if not.
	///
	boolean RectInside				(const TMCRect& inRect) const;
	
	///	Note: similar to above, but ignores empty rects.
	///	
	///	This routine interprets rectangles in the
	///	same way that QD does.  A rectangle will
	///	hit if any of the bits in the bitmap it 
	///	encloses overlap with any of the bits in the
	///	bitmap enclosed by the other rectangle.
	///
	boolean RectInRect				(const TMCRect& inRect) const;
	
#if Do_We_Need_This
	//	Added this as a convenience: converts a rectangle
	//	from one dpi to another. Note: the topLeft corner
	//	is not displaced from the original position. Also,
	//	the scaling is rounded upward.
	void Rect2DPI					(const float src_dpi, const float dest_dpi);
#endif
	
	/// returns true if rects intersect false otherwise
	///
	boolean RectOverRect			(const TMCRect& inRect) const;
	
	///	Scales each component. Note: accurate but slow.
	///
	void Scale						(const float scale);
	
	///	Set assigns the four boundary coordinates to a rectangle.
	///	The result is a rectangle with coordinates (left,top,right,bottom).
	///
	inline void Set					(const int32 inLeft, const int32 inTop,	const int32 inRight, const int32 inBottom);
	
	
	/// Same than Set but with real32 parameters (thanks to gcc...)
	inline void SetFromReal64		(const real64 inLeft, const real64 inTop,	const real64 inRight, const real64 inBottom);
	
	
	///	Set the rectangle to no width or height.
	///
	void SetEmpty					(void);
	
	///	Set the rectangle to have negative width or height.
	///	This is useful for initializing a rectangle to be
	///	the union of a set of rectangles
	///
	void SetInvalid					(void);
	
	///	Union calculates the smallest rectangle which encloses both
	///	input rectangles. The destination (result) rectangle may also be
	///	one of the input rectangles.
	///
	void Union						(const TMCRect& inRect);
	
#if Do_We_Need_This
	//	UnionPt expands the input rectangle to enclose the input point.
	//	If the point is already within the rectangle, nothing is changed.
	void UnionPt					(const TVector2& inPt);
#endif
	
	/// this version of Union rect handle the case when one of the rects is empty
	///
	void SafeUnion					(const TMCRect & inRect);
	
	///	UnionPt expands the input rectangle to enclose the input point.
	///	If the point is already within the rectangle, nothing is changed.
	///
	void UnionPt					(const TMCPoint& inPt);
	
	inline	TMCPoint	TopLeft		(void) const;
	inline	TMCPoint	TopRight	(void) const;
			TMCPoint	TopCenter	(void) const;
				
			TMCPoint	LeftCenter	(void) const;
			TMCPoint	RightCenter	(void) const;
				
	inline	TMCPoint	BottomLeft	(void) const;
	inline	TMCPoint	BottomRight	(void) const;
			TMCPoint	BottomCenter(void) const;

	///returns the value of the field corresponding to the given side of the rectangle
	inline	int32		GetSidePos	(const ERectangleSide side) const;

	///Sets the value of the field corresponding to the given side of the rectangle
	inline	void		SetSidePos	(const ERectangleSide side, int32 value);
			
	boolean	operator==				(const TMCRect& rr) const 
	{
		return (left==rr.left)&& (right==rr.right)&& (top==rr.top)&& (bottom==rr.bottom);  
	}
	
	boolean	operator!=				(const TMCRect& rr) const
	{
		return (left!=rr.left)|| (right!=rr.right)|| (top!=rr.top)|| (bottom!=rr.bottom); 
	}
	
	TMCRect& operator=				(const TMCRect& rr)
	{
		left = rr.left;
		right = rr.right;
		top = rr.top; 
		bottom = rr.bottom; 
		return *this;
	}
	TMCRect& operator=				(const int32 i)
	{
		MCAssert(i==0);
		
		return (*this = TMCRect::kZero);
	}
	
	TMCRect& operator+=				(const TMCPoint& pp);
	TMCRect& operator-=				(const TMCPoint& pp);
				
public:
	int32	left;
	int32	top;
	int32	right;
	int32	bottom;
public:
	//	Warning: Do not use these in a static global since they are
	//	not gauranteed to be constructed before hand.
	
	static const TMCRect kZero;		//	( 0, 0, 0, 0 );
	
	static const TMCRect kEmpty;	//	( 0, 0, 0, 0 );
	static const TMCRect kInvalid;	//	( MAX, MAX, MIN, MIN );
	static const TMCRect kBiggest;
};

/// We need this for unions, having a class that has a constructor in it in a union
/// plays havoc with the windows compiler.
///
struct SMCRect : public TMCObject
{
	int32	l,t,r,b;
};

//	void contructor.
inline TMCRect::TMCRect	(void)
	{ }

//	Component contructor.
inline TMCRect::TMCRect	(const int32 left, const int32 top, const int32 right, const int32 bottom )
	: left(left), top(top), right(right), bottom(bottom)
	{ }

//	Component access (although public member variables).
inline int32 TMCRect::L	(void) const
	{ return left; }	
inline int32 TMCRect::T	(void) const
	{ return top; }	
inline int32 TMCRect::R	(void) const
	{ return right; }	
inline int32 TMCRect::B	(void) const
	{ return bottom; }	

//	Sets the components.
inline void TMCRect::Set (const int32 inLeft, const int32 inTop,	const int32 inRight, const int32 inBottom )
	{ left = inLeft; top = inTop; right = inRight; bottom = inBottom; }
	
inline void TMCRect::SetFromReal64(const real64 inLeft, const real64 inTop,	const real64 inRight, const real64 inBottom)
{ 
	ASSIGN_CAST( left,	inLeft 	);
	ASSIGN_CAST( top,	inTop 	); 
	ASSIGN_CAST( right,	inRight ); 
	ASSIGN_CAST( bottom,inBottom);
}

//	Return the width.
inline int32 TMCRect::GetWidth			(void) const
	{ return( right - left ); }

//	Return the height.
inline int32 TMCRect::GetHeight			(void) const
	{ return( bottom - top ); }


inline TMCPoint TMCRect::GetSize		(void) const
	{ return TMCPoint(GetWidth(), GetHeight() );}

inline boolean TMCRect::Valid			(void) const
	{ return( (left <= right) && (top <= bottom) ); }

inline boolean TMCRect::Invalid			(void) const
	{ return !Valid(); }


inline TMCPoint TMCRect::TopLeft		(void) const
	{ return TMCPoint(left, top); }

inline TMCPoint TMCRect::TopRight		(void) const
	{ return TMCPoint(right, top); }

inline TMCPoint TMCRect::BottomLeft		(void) const
	{ return TMCPoint(left, bottom); }

inline TMCPoint TMCRect::BottomRight	(void) const
	{ return TMCPoint(right, bottom); }

inline TMCPoint TMCRect::PinPoint		(const TMCPoint& inPt) const
	{TMCPoint outPoint; PinPoint(inPt, outPoint); return outPoint;}


inline int32 TMCRect::GetSidePos		(const ERectangleSide side) const
{
	switch (side)
	{
	case kLeftSide	: return left;
	case kTopSide	: return top;
	case kRightSide	: return right;
	case kBottomSide: return bottom;
	default	: MCNotify("Invalid ERectangleSide"); return 0;
	}
};

inline void TMCRect::SetSidePos	(const ERectangleSide side, int32 value)
{
	switch (side)
	{
	case kLeftSide	: left	 = value; break;
	case kTopSide	: top	 = value; break;
	case kRightSide	: right	 = value; break;
	case kBottomSide: bottom = value; break;
	default	: MCNotify("Invalid ERectangleSide");
	}
};


#endif