//****************************************************************************
//Copyright (C) 2005-2006 Beijing BlueDJ Technology Co.,Ltd. All rights reserved.

//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either version 2
//of the License, or (at your option) any later version.

//This program 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 General Public License for more details.

//You should have received a copy of the GNU General Public License
//along with this program (in the file LICENSE.GPL); if not, write to the Free Software
//Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

//Please visit http://www.bluedj.com for more infomation about us.
//Contact us at ggwizard@gmail.com or darkdong@gmail.com.
//****************************************************************************/
#ifndef __DJGAME_GAMEPANEL_DESKTOP_POKER_H__
#define __DJGAME_GAMEPANEL_DESKTOP_POKER_H__

#include<QtGui>
#include <Qt3Support>
#include "DJBaseGlobal.h"
#include "DJGamePanel.h"
#include "DJGameDesktop.h"
#include "protocol.h"
#include "DJPoker.h"

#define DJGAME_POKERDESKTOP_EMOTION_YEH				0x41
#define DJGAME_POKERDESKTOP_EMOTION_SOS				0x42
#define DJGAME_POKERDESKTOP_EMOTION_GOD				0x43

#define DJGAME_POKERDESKTOP_EMOTION_GAMEDEFINE		0x50

#define DJGAME_POKERDESKTOP_TYPE_HANDCARD			0x50
#define DJGAME_POKERDESKTOP_TYPE_THROWCARD			0x51
#define DJGAME_POKERDESKTOP_TYPE_ATTACHCARD			0x52

#define DJGAME_POKERDESKTOP_ITEMCARD(__item)		((unsigned char)((__item)->tid()&0x00FF))

#define DJGAME_POKERDESKTOP_COMPARE_RESUST_1		1
#define DJGAME_POKERDESKTOP_COMPARE_RESUST_2		-1
#define DJGAME_POKERDESKTOP_COMPARE_RESUST_E		0

DJ_BASE_EXPORT uint qHash ( DJPoker poker );

class DJ_BASE_EXPORT DJGamePokerDesktop : public DJGameDesktop
{
	Q_OBJECT
	public :
		enum SortKey{
			SortByASCount,
			SortBySuit,
			SortByPoint
		};
		enum SortMode{
			ASCountPointSuit,
			PointASCountSuit,
			SuitPoint,
			PointSuit
		};
		enum SuitRankMode {
			BridgeSuitRank,
			NormalSuitRank
		};
		enum PointRankMode {
			Num2PointRank,
			AcePointRank
		};
		DJGamePokerDesktop(QWidget* parent,DJGamePanel *panel,quint32 w=850,quint32 h=850);
		virtual ~DJGamePokerDesktop();
	

		virtual void userArrived( quint32 userId, quint8 seatId );
	
		virtual void SendThrowCard(PGeneralGameTrace2Head ptrace);
		virtual void CreateThrowTrace(PGeneralGameTrace2Head ptrace);
		virtual void RecvThrowACL(bool bFailed);
		virtual int Compare2Card(quint8 chCard1,quint8 chCard2, PDJGamePokerImage pPokerImage);
		virtual void GetPageInterval(quint8 chView,quint8 *pcards,quint8 chPages,int *dx,int *dy);
		virtual void RepaintView1Cards(quint8 seat,quint8 *cards,quint8 chPages);
		virtual void RepaintView2Cards(quint8 seat,quint8 *cards,quint8 chPages);
		virtual void RepaintView3Cards(quint8 seat,quint8 *cards,quint8 chPages);
		virtual void RepaintView4Cards(quint8 seat,quint8 *cards,quint8 chPages);
	
		virtual void RepaintView1Throw(quint8 seat,quint8 *cards,quint8 chPages);
		virtual void RepaintView2Throw(quint8 seat,quint8 *cards,quint8 chPages);
		virtual void RepaintView3Throw(quint8 seat,quint8 *cards,quint8 chPages);
		virtual void RepaintView4Throw(quint8 seat,quint8 *cards,quint8 chPages);
	
		virtual void RepaintView1Attach(quint8 seat,quint8 *cards,quint8 chPages);
		virtual void RepaintView2Attach(quint8 seat,quint8 *cards,quint8 chPages);
		virtual void RepaintView3Attach(quint8 seat,quint8 *cards,quint8 chPages);
		virtual void RepaintView4Attach(quint8 seat,quint8 *cards,quint8 chPages);
		
		virtual void GetDesktopCenterPoint(int *x,int *y,int *selfHeight);
		
		virtual void DisplayTheRound(int iRound);
		virtual bool IsThrowStep(PGeneralGameTrace2Head ptrace);
		
		quint8 GetCardsMaxWidth(quint8 chView,quint8 *cards,quint8 chPages);
		virtual QImage GetCardPicture(quint8 chCard,quint8 chView,qreal rate);
		
		void RepaintSeatCard(quint8 seat);
		void RepaintThrowCard(quint8 seat,quint8 *pbuf,quint8 chPages);
		void RepaintAttachCards(quint8 seat,quint8 *pbuf,quint8 chPages);
		
		virtual quint8 classForCard( quint8 card ) const;
		bool canShowHigher( PDJGamePokerImage pokerimage,quint8 testCard, quint8 lastShow);
		
		void PlayerThrowCards(quint8 chSeat,quint8 *pbuf,quint8 chPages);
	
		void ClearSeatHandCard(quint8 seat);
		void ClearSeatThrowCard(quint8 seat);
		void ClearSeatAttachCard(quint8 seat);
		
		void SetOrder(bool bOrder,bool bLineClass=false,bool bOrderByClass = true);
		bool order() const { return c_bOrder; }
		bool orderByClass() { return c_bOrderByClass; }
		bool lineClass() const { return c_bLineClass; }
		void DrawHCards(int x,int y,qreal fx,quint16 seat,quint16 type,quint8 *pbuf,quint8 chPages,quint8 chAlign,int z);

		void ResetPlayerCards(quint8 chSeat,quint8 *pbuf,quint8 chPages);
		void AppendPlayerCards(quint8 chSeat,quint8 *pbuf,quint8 chPages);
		void RemovePlayerCards(quint8 chSeat,quint8 *pbuf,quint8 chPages);
		void SetCardStatus(quint8 chSeat,quint8 chCard,quint8 status);
		quint8 GetCardStatus(quint8 chSeat,quint8 chCard);
		quint8 GetCardPages(quint8 chSeat,quint8 chCard);
		
		PDJGamePokerImage	GetPlayerCardImage(quint8 chSeat) const;
		
		void setWaitingThrowAcl(bool b);
		void setWaitingThrow(bool b);
		void throwAllCards();
		
		quint8 centerSize() const { return c_chCenterSize; }
		quint8 pageLayoutSizeX() const { return c_chPageLayoutSizeX; }
		quint8 pageLayoutSizeY() const { return c_chPageLayoutSizeY; }
		quint8 popupSize() const { return c_chPopupSize; }
		void  SetCardPictureSize(quint8 chCenter,quint8 chPopup,quint8 chLayoutX,quint8 chLayoutY);
		
		void SetFx(qreal selfFx,qreal otherFx,qreal throwFx,qreal attachFx);
		qreal getSelfFx() const { return c_SelfFx; }
		qreal getOtherFx() const { return c_OtherFx; }
		qreal getThrowFx() const { return c_ThrowFx; }
		qreal getAttachFx() const { return c_AttachFx; }
		
		virtual quint8 GetSeatCards(quint8 seat,quint8 *buffer,quint8 chSize);
		quint8 PokerImage2Bytes(PDJGamePokerImage ppokerimg,quint8 chClass,quint8 chValue, \
									quint8 *psubset,quint8 chSubMax,bool bOrder);
					
		static unsigned int GetSelfViewMaxHeight(QPixmap &pix ,quint8 chLayoutSizeY);
		static unsigned int GetSelfViewMaxHeight(QImage &img ,quint8 chLayoutSizeY);
		static unsigned int GetDesktopMaxHeight(QPixmap &pix,quint8 chCenterSize,quint8 chLayoutSizeY);
		
		virtual void locateRemainderPositions( QList<QPoint>& points, QList<Qt::Alignment>& aligns, QList<int> &modes );
		
		quint8 numberOfCards( quint8 seat );
		QByteArray	cardsOfSeat( qint8 seat );
		QList<DJPoker> pokersOfSeat( quint8 seat );
		void repaintCards( quint8 seat );
		bool isCardVisible( quint8 seat ) const;
		bool isBridgeCard() const { return m_isBridgeCard; }
		void setSelectRectEnabled( bool enabled );
		void repaintRemainder( quint8 seat );
		void repaintAllRemainders();
		void hideAllRemainders();
		void setRemainderEnabled( bool enabled );
		DJMatrixCanvasText *remainderItem( quint8 seat );
		
		int rankOfSuit( int suit ) const { return m_rankOfSuits.value(suit); }
		int rankOfPoint( DJPoker::Point point ) const { return m_rankOfPoints.value(point); }
		int numberOfPokersOnAllSuits( const QHash<DJPoker,int> countPokers, const DJPoker& comboPoker ) const;
		
		QHash<DJPoker,int> createCountPokers( const QList<DJPoker>& handPokers ) const;
		void setPokerSortKeys( const QList<SortKey>& sortKeys );
		void setBridgeCard( bool isBridgeCard );
		void sortCards( quint8 *cards, quint8 len );
		void sortPokers( QList<DJPoker>& pokers );
		virtual bool pokerLessThan( const DJPoker& poker1, const DJPoker& poker2 );
		int	comparePokerWithKey( const DJPoker& poker1, const DJPoker& poker2, SortKey key );
		void setPokerSortMode( SortMode mode );
		void setRankOfSuits( SuitRankMode mode );
		void setRankOfPoints( PointRankMode mode );
		void saveSortInfo();
		void restoreSortInfo();
		
		//DJPoker greatestPoker( const QList<DJPoker>& pokers );
		virtual bool groupGreaterThan( const QList<DJPoker>& group1,
									const QList<DJPoker>& group2 );
		virtual bool shunGreaterThan( const QList<DJPoker>& shun1,
										const QList<DJPoker>& shun2 );
		virtual DJPoker parallelPoker( const DJPoker& poker, bool isStrictSuit ) const;	
		virtual DJPoker higherSerialPoker( const DJPoker& poker, bool isStrictSuit ) const;
		virtual DJPoker lowerSerialPoker( const DJPoker& poker, bool isStrictSuit ) const;
		//subclass should implemented the following two methods only for loop serial
		//e.g. Q K A, A 2 3, A can be the highest and the lowest
		//when A is the highest,stop iterate higherSerialPoker
		//when A is the lowest,stop iterate lowerSerialPoker
		virtual bool isHighestSerialPoker( const DJPoker& poker ) const;
		virtual bool isLowestSerialPoker( const DJPoker& poker ) const;
		
		QList<DJPoker> findGroup( const QHash<DJPoker,int> countPokers,
													const DJPoker& keyPoker,
											 		int width,
											 		bool isStrictSuit,
											 		bool isExactWidth ) const;
		QList<DJPoker> findNextGroup( const QHash<DJPoker,int> countPokers,
												const DJPoker& currentKeyPoker,
												DJPoker& nextKeyPoker,
										 		int width, bool isHigher,
										 		bool isStrictSuit,
										 		bool isExactWidth ) const;
		QList<DJPoker> findShun( const QHash<DJPoker,int> countPokers,
												const DJPoker& keyPoker,
										 		int width, int length, bool isHigher,
										 		bool isStrictSuit,
										 		bool isExactWidth ) const;
		QList<DJPoker> iterateGroup( const QHash<DJPoker,int>& countPokers,
						 	int width, DJPoker& keyPoker,
						 	QSet<DJPoker>& excluder,
						 	bool isStrictSuit,
						 	bool isExactWidth ) const;
		QList<DJPoker> iterateShun( const QHash<DJPoker,int>& countPokers,
						 	int width, int length,
						 	DJPoker& keyPoker,
						 	QSet<DJPoker>& excluder,
						 	bool isStrictSuit,
						 	bool isExactWidth ) const;
		//QList<DJPoker> iterateFlush( const QHash<DJPoker,int>& countPokers,
			//			 	int suit, int length,
				//		 	DJPoker& keyPoker,
					//	 	QSet<DJPoker>& excluder );
		void iterateCombination( int total,
										int length, 
										QList<bool>& indexes ) const;
		bool removeSubset( QList<DJPoker>& pokers, const QList<DJPoker>& subset ) const;
		void selectPokerItems( const QList<DJPoker>& handPokers = QList<DJPoker>() ) const;
		
	protected:
		virtual void handleMatrixChanged( const QMatrix& matirx );
		virtual void contentsMousePressEvent(QMouseEvent* e);
		virtual void contentsMouseMoveEvent( QMouseEvent * e );
		virtual void contentsMouseReleaseEvent( QMouseEvent * e );
		virtual bool handleItemClicked( Qt::MouseButton btn,const QPoint& pos, Q3CanvasItem *item );
	private :
		QList<DJPoker> getGroupFromAllOfSuits( const QHash<DJPoker,int> countPokers,
													const DJPoker& keyPoker,
											 		int width, bool isExactWidth ) const;
		QList<DJPoker> getGroupFromOneOfSuits( const QHash<DJPoker,int> countPokers,
													const DJPoker& keyPoker,
										 			int width, bool isExactWidth ) const;
		PDJGamePokerImage		c_ppokerimg[9];
		int 					c_iSelfHandCardBaseY;
		//bool 					c_bWaitACL,c_bThrowFlag;//,c_bWaitAndThrow;
		bool					m_isWaitingThrowAcl,m_isWaitingThrow;
		quint8					c_chTotalSeats;
		bool					c_bThrowOnTableCenter;
		bool 					c_bOrderByClass,c_bOrder,c_bLineClass;
		qreal					c_SelfFx,c_OtherFx,c_ThrowFx,c_AttachFx;
		DJGamePanel				*c_Panel;
		
		quint8			c_chThrowCard[9][54];
		quint8 			c_chCenterSize,c_chPopupSize,c_chPageLayoutSizeX,c_chPageLayoutSizeY;
		//bool			c_bFirst;
		
		bool						m_isSelectRectEnabled;
		QPoint						m_startPoint;
		Q3CanvasRectangle			*m_selectRectItem;
		
		QList<DJMatrixCanvasText*>	m_remainderItems;
		QList<QPoint>				m_remainderPoints;
		QList<Qt::Alignment>		m_remainderAligns;
		QList<int>					m_remainderModes;
		bool						m_remainderEnabled;
		
		QList<SortKey>				m_pokerSortKeys,m_savedSortKeys;
		QHash<int,int>				m_rankOfSuits,m_savedRankOfSuits;//suit, rank
   	 	QHash<DJPoker::Point,int>	m_rankOfPoints,m_savedRankOfPoints;//point,rank
		QHash<DJPoker,int>			m_sortingPokers;//poker,count
		bool						m_isBridgeCard;
};

class DJ_BASE_EXPORT DJGamePokerItem: public DJGameImageItem
{
	public:
    	DJGamePokerItem( QImage img, Q3Canvas *cv,QMatrix &m,unsigned short tid,unsigned short sid,unsigned short type,bool bMovable);
		~DJGamePokerItem();
	
		void setSelected(bool b);
		bool selected() const { return c_bSelected; }
		void move(double x, double y);
		double	x() const { return c_x; }
		double 	y() const { return c_y; }
		void setdx(int d);
		void setdy(int d);
	private :
		double  c_x,c_y;
		int		c_dx,c_dy;
		bool 	c_bSelected;
};

#define DJGAME_POKER_DESKTOP_AVATAR_MAXHEIGHT			120//100
#define DJGAME_POKER_DESKTOP_AVATAR_MAXWIDTH			90



#endif
