//****************************************************************************
//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.
//****************************************************************************/

#include "DJGameRoom.h"
#include "DJGamePanel.h"
#include "DJGameDesktop.h"
#include "DJClientRequest.h"
#include "DJGamePokerDesktop.h"
#include "DJGameTraceManager.h"
#include "Utility.h"
#include "protocol.h"
#include "DJShowView.h"
#include "DJMatrixCanvasText.h"
#include "DJPoker.h"

uint qHash ( DJPoker poker )
{
	return (poker.suit() << 16) | poker.point();
}
static QList<int> allSuits	= QList<int>() 	<< DJPoker::Diamond
											<< DJPoker::Club
											<< DJPoker::Heart
											<< DJPoker::Spade
											<< DJPoker::Joker;
DJGamePokerDesktop	*gGamePokerDesktop	= 0;
bool PokerLessThan( const DJPoker& poker1, const DJPoker& poker2 )
{
	if ( gGamePokerDesktop )
		return gGamePokerDesktop->pokerLessThan( poker1, poker2 );
	else
		return false;
}

static double Z_REMAINDER	= 3500; 

void  HandleThrowACL( const QByteArray& buf, const QVariant& parameters );

DJGamePokerDesktop::DJGamePokerDesktop(QWidget* parent,DJGamePanel *panel,quint32 w,quint32 h)
			: DJGameDesktop(parent,panel,w,h)
{		
	gGamePokerDesktop	= this;
	
	DJGameRoom *room = panel->gameRoom();
	c_chTotalSeats = room->numberOfSeats();
	c_Panel = panel;
	int i;
	memset(c_ppokerimg,0,9*sizeof(PDJGamePokerImage));
	for(i = 0;i<= c_chTotalSeats; i++)
	{
		c_ppokerimg[i] = new DJGamePokerImage;
		ResetPlayerCards(i,0,0);
	}
	m_isWaitingThrowAcl = false;
	m_isWaitingThrow = false;
	c_bThrowOnTableCenter = true;
	c_bOrderByClass = true;
	c_bOrder = true;
	c_bLineClass = false;
	
	c_SelfFx = 1.0;
	c_OtherFx= 0.7;
	c_ThrowFx= 1.0;
	c_AttachFx=0.7;
	c_chCenterSize = 40;
	c_chPopupSize = 10;
	c_chPageLayoutSizeX = 22;
	c_chPageLayoutSizeY = 38;
	//c_bFirst = true;
	//c_bWaitAndThrow = false;
	
	setSelectRectEnabled( true );
	
	m_selectRectItem 	= new Q3CanvasRectangle( canvas() );
	m_selectRectItem->setPen( QPen(Qt::green) );
	m_selectRectItem->setZ( 4000 );
	m_selectRectItem->hide();	
	
	QFont font;
	font.setBold( true );
	font.setPointSize( 12 );
	for ( quint8 seat = 0; seat <= c_Panel->numberOfSeats(); ++seat) {
		DJMatrixCanvasText	*remainderItem	= new DJMatrixCanvasText( canvas(), "", font );
		remainderItem->setZ( Z_REMAINDER );
		remainderItem->hide();
		m_remainderItems  << remainderItem;
	}
	setRemainderEnabled( false );
	
	locateRemainderPositions( m_remainderPoints, m_remainderAligns, m_remainderModes );
	
	setBridgeCard( true );
	setPokerSortMode( SuitPoint );
	setRankOfSuits( NormalSuitRank );
	setRankOfPoints( AcePointRank );
}

DJGamePokerDesktop::~DJGamePokerDesktop()
{
	djDebug() << "DJGamePokerDesktop destructor";
	delete m_selectRectItem ;
	m_selectRectItem 	= 0;
	
	qDeleteAll(m_remainderItems);
	m_remainderItems.clear();
}
void DJGamePokerDesktop::setSelectRectEnabled( bool enabled )
{
	m_isSelectRectEnabled	= enabled;
}
void DJGamePokerDesktop::throwAllCards()
{
	if(c_Panel->isLookingOn())
		return;
	DJGamePanel *panel = GetGamePanel();
	DJGameImageItem *imgitem;
	DJGamePokerItem *pokeritem;
	int i,j;
	if ( !m_isWaitingThrowAcl && m_isWaitingThrow) {
		char buffer[255];
		PGeneralGameTrace2Head ptrace = (PGeneralGameTrace2Head)buffer;
		ptrace->chType = 0;
		ptrace->chTable = panel->tableId();
		ptrace->chSite = panel->selfSeatId();
		ptrace->chBufLen = 0;
		for(i=0;i<=0x3F;i++)
		{
			if(!DJGAME_POKER_ERRORCARD(i))
			{
				if(c_ppokerimg[ptrace->chSite]->chPage[i] > 0)
				{
					for(j=0;j<c_ppokerimg[ptrace->chSite]->chPage[i];j++)
					{
						imgitem = FindImageItem(i+(j<<8),ptrace->chSite,DJGAME_POKERDESKTOP_TYPE_HANDCARD);
						if(imgitem != NULL)
						{
							pokeritem = (DJGamePokerItem*)imgitem;
							ptrace->chBuf[ptrace->chBufLen] = i;
							ptrace->chBufLen ++;
						}
					}
				}
			}
		}
		if(ptrace->chBufLen > 0)
		{
			CreateThrowTrace(ptrace);
			if(ptrace->chBufLen > 0) {
				SendThrowCard(ptrace);
			}
		}
	}
}
void DJGamePokerDesktop::contentsMousePressEvent(QMouseEvent* e)
{	
	if(c_Panel->isLookingOn() )
		return;
	
	if ( m_isSelectRectEnabled ) {
		m_startPoint 	= e->pos();
		m_selectRectItem->move( m_startPoint.x(), m_startPoint.y() );
	}
}
void DJGamePokerDesktop::contentsMouseMoveEvent ( QMouseEvent * e )
{	
	if(c_Panel->isLookingOn() )
		return;
	
	if ( m_isSelectRectEnabled ) {
 		m_selectRectItem->setSize( e->pos().x() - m_startPoint.x(), e->pos().y() - m_startPoint.y() );
		m_selectRectItem->show();
		canvas()->update();
	}
}
void DJGamePokerDesktop::contentsMouseReleaseEvent ( QMouseEvent * e ) 
{	
	if(c_Panel->isLookingOn())
		return;
	
	if ( m_isSelectRectEnabled && m_selectRectItem ->isVisible() ) {
		m_selectRectItem->hide();
		
		QRect	selectRect( m_startPoint, e->pos() );
		Q3CanvasItemList list	= canvas()->collisions( selectRect );
		
		QRect	resultRect(0,0,0,0);
		foreach( Q3CanvasItem *canvasItem, list ) {
			if ( djgame_imageRTTI == canvasItem->rtti() ) {
				DJGameImageItem *imageItem	= (DJGameImageItem *)canvasItem;
				if ( DJGAME_POKERDESKTOP_TYPE_HANDCARD == imageItem->type()
 					&& imageItem->sid() == GetGamePanel()->selfSeatId() ) {
 					DJGamePokerItem *pokerItem = (DJGamePokerItem*)imageItem;
 					QRect rect	= selectRect.intersect( pokerItem->rect() );
 					if ( rect.isValid() && !resultRect.contains( rect ) ) {
 						resultRect	|= rect;
						pokerItem->setSelected( !pokerItem->selected() );
					}
 				}
			}
		}
		canvas()->update();
	}else {
		QPoint pp;
	
    	pp.setX( static_cast<int>((e->pos().x()-GetCurrentMatrix().dx())/GetCurrentMatrix().m11()) );
    	pp.setY( static_cast<int>((e->pos().y()-GetCurrentMatrix().dy())/GetCurrentMatrix().m22()) );
    	
    	Q3CanvasItemList l=canvas()->collisions(e->pos());
        Q3CanvasItemList::Iterator it=l.begin();
    	Q3CanvasItem * item = NULL;
        if (it != l.end())
    	{
    		item = *it;
    	}
    	handleItemClicked(e->button(),pp,item);
	}
}
bool DJGamePokerDesktop::handleItemClicked(Qt::MouseButton btn,const QPoint& pos,Q3CanvasItem *item)
{ 	
	djDebug() << "DJGamePokerDesktop::handleItemClicked" << m_isWaitingThrowAcl << m_isWaitingThrow << btn << item;
 	if(c_Panel->isLookingOn())
		return false;
	DJGamePanel *panel = GetGamePanel();
	DJGameImageItem *imgitem;
	DJGamePokerItem *pokeritem;
	int i,j;
	
	if( btn == Qt::RightButton && !m_isWaitingThrowAcl && m_isWaitingThrow)
	{
		char buffer[255];
		PGeneralGameTrace2Head ptrace = (PGeneralGameTrace2Head)buffer;
		ptrace->chType = 0;
		ptrace->chTable = panel->tableId();
		ptrace->chSite = panel->selfSeatId();
		ptrace->chBufLen = 0;
		for(i=0;i<=0x3F;i++)
		{
			if(!DJGAME_POKER_ERRORCARD(i))
			{
  				if(c_ppokerimg[ptrace->chSite]->chPage[i] > 0)
				{
					//djDebug() << "card" << hex << i << "pages" << c_ppokerimg[ptrace->chSite]->chPage[i];
					for(j=0;j<c_ppokerimg[ptrace->chSite]->chPage[i];j++)
					{
						imgitem = FindImageItem(i+(j<<8),ptrace->chSite,DJGAME_POKERDESKTOP_TYPE_HANDCARD);
						if(imgitem != NULL)
						{
							pokeritem = (DJGamePokerItem*)imgitem;
							//djDebug() << "find item and selected =" << pokeritem->selected();
							if(pokeritem->selected())
							{
								ptrace->chBuf[ptrace->chBufLen] = i;
								ptrace->chBufLen ++;
							}
						}
					}
				}
			}
		}
		djDebug() << "found selected card" << ptrace->chBufLen;
		if(ptrace->chBufLen > 0)
		{
			CreateThrowTrace(ptrace);
			djDebug() << "chBufLen after CreateThrowTrace" << ptrace->chBufLen;
			if(ptrace->chBufLen > 0) {
				SendThrowCard(ptrace);
				return true;
			}
		}
	}else if(item != NULL && btn == Qt::LeftButton && item->rtti() == djgame_imageRTTI) 
	{
		imgitem = (DJGameImageItem*)item;
		if(imgitem->type() == DJGAME_POKERDESKTOP_TYPE_HANDCARD && imgitem->sid() == panel->selfSeatId())
		{
			DJGamePokerItem *pokeritem = (DJGamePokerItem*)imgitem;
			pokeritem->setSelected(!pokeritem->selected());
			canvas()->update();
			return true;
		}
	}else if ( Qt::LeftButton == btn && NULL == item ) {
		selectPokerItems();
		return true;
	}
	return false;
}

void DJGamePokerDesktop::SendThrowCard(PGeneralGameTrace2Head ptrace)
{
	djDebug() << "SendThrowCard";
	DebugBuffer( (char*)ptrace->chBuf, ptrace->chBufLen);
	if(c_Panel->isLookingOn())
		return;
	QByteArray buf	= c_Panel->makeGameData( DJGAME_PROTOCOL_SUBTYPE_GAMETRACE2, QByteArray((char *)ptrace,sizeof(GeneralGameTrace2Head)+ptrace->chBufLen) );

	QVariant parameters	= QVariant::fromValue((void*)this);
	m_isWaitingThrowAcl = true;
	DJClientRequest request(buf, HandleThrowACL, parameters);
	c_Panel->sendRequest( request,false );
}
void DJGamePokerDesktop::setWaitingThrowAcl(bool b)
{
	m_isWaitingThrowAcl = b;
}
void DJGamePokerDesktop::setWaitingThrow(bool b)
{
	m_isWaitingThrow = b;
}
void DJGamePokerDesktop::SetFx(qreal selfFx,qreal otherFx,qreal throwFx,qreal attachFx)
{
	c_SelfFx = selfFx;
	c_OtherFx = otherFx;
	c_ThrowFx = throwFx;
	c_AttachFx = attachFx;
}
void  HandleThrowACL( const QByteArray& buf, const QVariant& parameters )
{
	PDJGameProtocol pacl = (PDJGameProtocol)buf.data();
	DJGamePokerDesktop* desktop = static_cast<DJGamePokerDesktop *>(parameters.value<void*>());
	    
	bool bFailed;
    if(buf.size() == 0)
        bFailed = true;
	else if( DJGAME_SUCCESS(pacl->chBuf[0]) )
		bFailed = false;
    else 
		bFailed= true;
	
	desktop->RecvThrowACL(bFailed);
}

int DJGamePokerDesktop::Compare2Card(quint8 chCard1,quint8 chCard2,PDJGamePokerImage pPokerImage)
{//默认大到是小: BK SK S H D C -- A K Q J 10 9 8 7 6 5 4 3 2
	if(DJGAME_POKER_ERRORCARD(chCard1) && DJGAME_POKER_ERRORCARD(chCard2))
		return DJGAME_POKERDESKTOP_COMPARE_RESUST_E;
	if(DJGAME_POKER_ERRORCARD(chCard1))
		return DJGAME_POKERDESKTOP_COMPARE_RESUST_2;
	if(DJGAME_POKER_ERRORCARD(chCard2))
		return DJGAME_POKERDESKTOP_COMPARE_RESUST_1;
	
	if(chCard1 == DJGAME_POKER_BACKGROUND && chCard2 == DJGAME_POKER_BACKGROUND)
		return DJGAME_POKERDESKTOP_COMPARE_RESUST_E;
	
	if(chCard1 == DJGAME_POKER_BACKGROUND)
		return DJGAME_POKERDESKTOP_COMPARE_RESUST_2;
	
	if(chCard2 == DJGAME_POKER_BACKGROUND)
		return DJGAME_POKERDESKTOP_COMPARE_RESUST_1;
	
	if(DJGAME_POKER_ISBK(chCard1) && DJGAME_POKER_ISBK(chCard2))
		return DJGAME_POKERDESKTOP_COMPARE_RESUST_E;
	if(DJGAME_POKER_ISBK(chCard1))
		return DJGAME_POKERDESKTOP_COMPARE_RESUST_1;
	if(DJGAME_POKER_ISBK(chCard2))
		return DJGAME_POKERDESKTOP_COMPARE_RESUST_2;
	
	if(DJGAME_POKER_ISSK(chCard1) && DJGAME_POKER_ISSK(chCard2))
		return DJGAME_POKERDESKTOP_COMPARE_RESUST_E;
	if(DJGAME_POKER_ISSK(chCard1))
		return DJGAME_POKERDESKTOP_COMPARE_RESUST_1;
	if(DJGAME_POKER_ISSK(chCard2))
		return DJGAME_POKERDESKTOP_COMPARE_RESUST_2;
	
	if(c_bOrderByClass && DJGAME_POKER_CLASS(chCard1) != DJGAME_POKER_CLASS(chCard2))
	{
		if(DJGAME_POKER_CLASS(chCard1) > DJGAME_POKER_CLASS(chCard2))
			return DJGAME_POKERDESKTOP_COMPARE_RESUST_1;
		else
			return DJGAME_POKERDESKTOP_COMPARE_RESUST_2;
	}
	if(DJGAME_POKER_VALUE(chCard1) == DJGAME_POKER_VALUE(chCard2))
	{
		if(!c_bOrderByClass && DJGAME_POKER_CLASS(chCard1) != DJGAME_POKER_CLASS(chCard2))
		{
			if(DJGAME_POKER_CLASS(chCard1) > DJGAME_POKER_CLASS(chCard2))
				return DJGAME_POKERDESKTOP_COMPARE_RESUST_1;
			else
				return DJGAME_POKERDESKTOP_COMPARE_RESUST_2;
		}
		return DJGAME_POKERDESKTOP_COMPARE_RESUST_E;
	}
	
	if(DJGAME_POKER_VALUE(chCard1) == DJGAME_POKER_A)
		return DJGAME_POKERDESKTOP_COMPARE_RESUST_1;
	if(DJGAME_POKER_VALUE(chCard2) == DJGAME_POKER_A)
		return DJGAME_POKERDESKTOP_COMPARE_RESUST_2;
	
	if(DJGAME_POKER_VALUE(chCard1) > DJGAME_POKER_VALUE(chCard2))
		return DJGAME_POKERDESKTOP_COMPARE_RESUST_1;
	
	return DJGAME_POKERDESKTOP_COMPARE_RESUST_2;
}
void DJGamePokerDesktop::GetPageInterval(quint8 chView,quint8 *pcards,quint8 chPages,int *dx,int *dy)
{
	(*dx) = 0;
	(*dy) = 0;

	if(c_bLineClass && chView == 1)
	{
		if( (DJGAME_POKER_ISBK(pcards[chPages]) || DJGAME_POKER_ISSK(pcards[chPages]) ) )
		{
			if(!DJGAME_POKER_ISBK(pcards[chPages+1]) && !DJGAME_POKER_ISSK(pcards[chPages+1]) )
				(*dy) = 1;
			else
				(*dx) = 1;
		}else if(DJGAME_POKER_CLASS(pcards[chPages]) != DJGAME_POKER_CLASS(pcards[chPages+1]))
			(*dy) = 1;
		else
			(*dx) = 1;
	}else
	{
		if(c_bOrderByClass &&
			DJGAME_POKER_CLASS(pcards[chPages]) != DJGAME_POKER_CLASS(pcards[chPages+1])  )
			(*dx) = 2;
		else
			(*dx) = 1;
	}
}
void DJGamePokerDesktop::CreateThrowTrace(PGeneralGameTrace2Head ptrace)
{
}
void DJGamePokerDesktop::RecvThrowACL(bool bFailed)
{ 
	if ( !m_isWaitingThrowAcl  )
		return;
	m_isWaitingThrowAcl 	= false;
	if ( bFailed ) {
		QMessageBox::information(c_Panel,tr("throw card failed"),tr("plz read game rules"),QMessageBox::Ok);
	}
}
QImage DJGamePokerDesktop::GetCardPicture(quint8 chCard,quint8 chView,qreal rate)
{
	QPixmap pix;
	QImage  img;
	unsigned char chCardIndex;
	if(chCard > 0x40 && chCard < 0x50)
	{
		quint8 yeh[] = {4,14,5,0};
		quint8 sos[] = {9,10,11,5,0};
		quint8 god[] = {12,13,1,2,8,0};
		quint8 *p;
		if( chCard == DJGAME_POKERDESKTOP_EMOTION_YEH)
			p = yeh;
		else if( chCard == DJGAME_POKERDESKTOP_EMOTION_SOS)
			p = sos;
		else //if( chCard == DJGAME_POKERDESKTOP_EMOTION_GOD)
			p = god;
		unsigned char chLen =0;
		while(*(p+chLen) != 0)
			chLen ++;	
		if(chLen > 0)
		{
			chLen = rand()%chLen;
			pix = QPixmap(QString(":/BaseRes/image/emotion/%1.png").arg(*(p+chLen)));
			img = pix.convertToImage();
   			if(rate != 1)
    		{
        		img = img.smoothScale((int)(img.width()*rate),(int)(img.height()*rate));
    		}
			return img;
		}
	}
    if(DJGAME_POKER_ISBK(chCard))
        chCardIndex = 54;
    else if(DJGAME_POKER_ISSK(chCard))
        chCardIndex = 53;
	else if(chCard == DJGAME_POKER_BACKGROUND)
		chCardIndex = 55;
    else
        chCardIndex = (DJGAME_POKER_CLASS(chCard)-1)*13 + (DJGAME_POKER_VALUE(chCard));
    
    if(chCardIndex ==0 || chCardIndex > 55)
        chCardIndex = 55;
	char buffer[100];
	if(chView == 1 || chView == 3)
		sprintf(buffer,":/BaseRes/image/poker/%02d.png",chCardIndex);
	else
		sprintf(buffer,":/BaseRes/image/poker/r%02d.png",chCardIndex);
	pix = QPixmap(QString(buffer));
	img = pix.convertToImage();
//	printf("card picture %s , (%d,%d)\n",buffer,img.width(),img.height());
    if(rate != 1)
    {
        img = img.smoothScale((int)(img.width()*rate),(int)(img.height()*rate));
    }
	return img;
}
quint8 DJGamePokerDesktop::numberOfCards( quint8 seat )
{
	quint8 result	= 0;
	for( quint8 i=1; i<=0x3F; ++i ) {
		result	+= c_ppokerimg[seat]->chPage[i];
	}
	return result;
}
QByteArray DJGamePokerDesktop::cardsOfSeat( qint8 seat )
{
	QByteArray	buf;
	for( quint8 i=1; i<=0x3F; ++i ) {
		quint8 pages	= c_ppokerimg[seat]->chPage[i];
		while(pages--) {
			buf.append( i );
		}
	}
	return buf;
}
QList<DJPoker> DJGamePokerDesktop::pokersOfSeat( quint8 seat )
{
	QByteArray cards	= cardsOfSeat(seat);
	QList<DJPoker> pokers;
	
	for( int i = 0; i < cards.size(); ++i ) {
		pokers << DJPoker( cards.at(i), m_isBridgeCard );
	}
	return pokers;
}
void DJGamePokerDesktop::repaintCards( quint8 seat )
{
	ClearSeatHandCard(seat);
	if(c_ppokerimg[seat] == NULL)
		return;
	
	QByteArray	buf	= cardsOfSeat( seat );
	if( buf.size() <= 0 )
		return ;
		
	sortCards( (quint8*)(buf.data()), buf.size() );
	
	quint8 chView = MapSeat2View(seat);
	switch(chView)
	{
		case 1 :
			RepaintView1Cards(seat,(quint8*)buf.data(),buf.size());
			break;
		case 2 :
			RepaintView2Cards(seat,(quint8*)buf.data(),buf.size());
			break;
		case 3 :
			RepaintView3Cards(seat,(quint8*)buf.data(),buf.size());
			break;
		case 4 :
			RepaintView4Cards(seat,(quint8*)buf.data(),buf.size());
			break;
	}
}
bool DJGamePokerDesktop::isCardVisible( quint8 seat ) const
{
	//djDebug() <<  "isCardVisible" << seat << c_ppokerimg[seat]->chPage[DJGAME_POKER_BACKGROUND] ;
	if ( 0 == c_ppokerimg[seat]->chPage[DJGAME_POKER_BACKGROUND] )
		return true ;
	else 
		return false;
}
quint8 DJGamePokerDesktop::classForCard( quint8 card ) const
{
	if ( DJGAME_POKER_ISBK ( card ) )
		return 5;
	else if ( DJGAME_POKER_ISSK ( card ) )
		return 4;
	else
		return  ( card & 0x30 ) >> 4;
}
bool DJGamePokerDesktop::canShowHigher( PDJGamePokerImage pokerimage, quint8 testCard, quint8 lastShow )
{
	if ( 0 == pokerimage  ) {
		quint8 selfSeat	= c_Panel ->selfSeatId(); 
		pokerimage = GetPlayerCardImage(selfSeat);
	}
	quint8 pages	= pokerimage->chPage[testCard];
	if ( pages < 2 )
		return false;
	quint8 lastShowPages	= DJGAME_POKER_PAGES(lastShow);
	if ( pages > lastShowPages ||
		(pages == lastShowPages && classForCard( testCard ) > classForCard(lastShow)) )
		return true;			
	else
		return false;
}
void DJGamePokerDesktop::RepaintSeatCard(quint8 seat)
{
	ClearSeatHandCard(seat);
	if(c_ppokerimg[seat] == NULL)
		return;
	quint8 chView = MapSeat2View(seat);

	quint8 buffer[200],chPages;
	memset(buffer,0,200);
	chPages = GetSeatCards(seat,buffer,200);
	if(chPages <= 0)
		return ;
	
	switch(chView)
	{
		case 1 :
			RepaintView1Cards(seat,buffer,chPages);
			break;
		case 2 :
			RepaintView2Cards(seat,buffer,chPages);
			break;
		case 3 :
			RepaintView3Cards(seat,buffer,chPages);
			break;
		case 4 :
			RepaintView4Cards(seat,buffer,chPages);
			break;
	}
}
quint8 DJGamePokerDesktop::GetSeatCards(quint8 seat,quint8 *buffer,quint8 chSize)
{ 
	return PokerImage2Bytes(c_ppokerimg[seat],0,0,buffer,chSize,c_bOrder);
}

void DJGamePokerDesktop::ClearSeatHandCard(quint8 seat)
{
	ClearImage(0,seat,DJGAME_POKERDESKTOP_TYPE_HANDCARD);
}

void DJGamePokerDesktop::ClearSeatThrowCard(quint8 seat)
{
	ClearImage(0,seat,DJGAME_POKERDESKTOP_TYPE_THROWCARD);
}

void DJGamePokerDesktop::ClearSeatAttachCard(quint8 seat)
{
	ClearImage(0,seat,DJGAME_POKERDESKTOP_TYPE_ATTACHCARD);
}
quint8 DJGamePokerDesktop::GetCardsMaxWidth(quint8 chView,quint8 *cards,quint8 chPages)
{
	quint8 iWidth = 0,iMaxWidth = 0;
	int i,dx,dy;
	for(i = 0;i<=chPages;i++)
	{
		GetPageInterval(chView,cards,i,&dx,&dy);
		if(dx >  1 && i!=chPages)
			iWidth += dx;
		else
			iWidth ++;
		if(dy > 0)
		{
			if(iWidth > iMaxWidth)
				iMaxWidth = iWidth;
			iWidth = 0;
		}
	}
	if(iWidth > iMaxWidth)
				iMaxWidth = iWidth;
	return iMaxWidth;
}
void DJGamePokerDesktop::DrawHCards(int x,int y,qreal fx,quint16 seat,quint16 type,quint8 *pbuf,quint8 chPages,quint8 chAlign,int z)
{
	if(chPages == 0)
		return;
	int dx;
	QImage img = GetCardPicture(DJGAME_POKER_BACKGROUND,1,fx);
	dx = ((chPages-1)*((int)(c_chPageLayoutSizeX*fx))+img.width());
	if(chAlign == Qt::AlignHCenter)
		x -= (dx>>1);
	else if(chAlign == Qt::AlignRight)
		x -= dx;
	
	QMatrix m = GetCurrentMatrix();
	DJGamePokerItem *item;
	for(int i=0;i<chPages;i++)
	{
		img = GetCardPicture(pbuf[i],1,fx);
		item = new DJGamePokerItem(img,canvas(),m,pbuf[i],seat,type,false);
		item->setdx((int)(c_chPopupSize*fx));
		item->setdy((int)((c_chPopupSize*fx)/2));
		item->setZ(z+i);
		item->move(x,y);
		item->show();
		item->setMatrix(m);
	
		x += ((int)(c_chPageLayoutSizeX*fx));
	}
	canvas()->update();
}

void DJGamePokerDesktop::RepaintView1Cards(quint8 seat,quint8 *cards,quint8 chPages)
{
	bool visible	= isCardVisible (seat);
	int iSelfHeight;
	GetDesktopCenterPoint(NULL,NULL,&iSelfHeight);
	QImage img = GetCardPicture(DJGAME_POKER_BACKGROUND,1,c_SelfFx);
	int x,y,dx;
	if(c_bLineClass)
		y = (GetRealHeight()-iSelfHeight)+30;
	else
		y = GetRealHeight()-((iSelfHeight-img.height())>>1)-img.height();
	
	quint8 iMaxWidth = GetCardsMaxWidth(1,cards,chPages);
	dx = 0;
	if(iMaxWidth >=1 )
		dx = ((iMaxWidth-1)*((int)(c_chPageLayoutSizeX*c_SelfFx))+img.width());
	if(dx >= (int)GetRealWidth())
		x = 3;
	else 
		x = ((GetRealWidth() -dx)>>1);
	
	DJGamePokerImage pokerimg;
	memset(&pokerimg,0,sizeof(DJGamePokerImage));
	DJGamePokerItem *item;
	int cx =x,cy = y,dy,i;
	QMatrix m = GetCurrentMatrix();
	for(i=0;i<chPages;i++)
	{
		img = GetCardPicture(cards[i],1,c_SelfFx);
		item = new DJGamePokerItem(img,canvas(),m,(pokerimg.chPage[cards[i]]<<8)+cards[i],seat,DJGAME_POKERDESKTOP_TYPE_HANDCARD,false);
		pokerimg.chPage[cards[i]] ++;
		item->setdx((int)(c_chPopupSize*c_SelfFx));
		item->setdy((int)((c_chPopupSize*c_SelfFx)/2));
		item->setZ(100+i);
		item->move(cx,cy);
		item->show();
		item->setMatrix(m);
		GetPageInterval(1,cards,i,&dx,&dy);
		if(dy > 0)
		{
			if ( visible ) {
				cy += dy*((int)(c_chPageLayoutSizeY*c_SelfFx));
				cx = x;
			}else
				break;
		}else
		{
			cx += dx*((int)(c_chPageLayoutSizeX*c_SelfFx));
			if(cx > (int)GetRealWidth()-((int)(c_chPageLayoutSizeX*c_SelfFx))*2 )
			{
				if ( visible ) {
					cy += ((int)(c_chPageLayoutSizeY*c_SelfFx));
					cx = x;
				}else
					break;
			}
		}
	}
	canvas()->update();
}

void DJGamePokerDesktop::RepaintView2Cards(quint8 seat,quint8 *cards,quint8 chPages)
{
	bool visible	= isCardVisible (seat);
	int x,sy,ey,iSelfHeight,cx,cy,dx,dy,i;
	GetDesktopCenterPoint(&x,&sy,&iSelfHeight);
	
	quint8 iMaxWidth = GetCardsMaxWidth(2,cards,chPages);
	QImage img = GetCardPicture(DJGAME_POKER_BACKGROUND,2,c_OtherFx);
	QImage img1 = GetCardPicture(DJGAME_POKER_BACKGROUND,3,c_OtherFx);
	dx = 0;
	if(iMaxWidth >=1 )
		dx = (iMaxWidth-1)*((int)(c_chPageLayoutSizeX*c_OtherFx))+img.height();
	x = DJGAME_POKER_DESKTOP_AVATAR_MAXWIDTH + 10;
	sy -= (dx>>1);
	if(sy <  DJGAME_POKER_DESKTOP_AVATAR_MAXHEIGHT+img1.height()+10)
		sy = DJGAME_POKER_DESKTOP_AVATAR_MAXHEIGHT+img1.height()+10;
	ey = GetRealHeight()-iSelfHeight;
	
	DJGamePokerImage pokerimg;
	memset(&pokerimg,0,sizeof(DJGamePokerImage));
	DJGamePokerItem *item;
	cx = x;
	cy = sy;
	QMatrix m = GetCurrentMatrix();
	for(i=0;i<chPages;i++)
	{
		img = GetCardPicture(cards[i],2,c_OtherFx);
		item = new DJGamePokerItem(img,canvas(),m,(pokerimg.chPage[cards[i]]<<8)+cards[i],seat,DJGAME_POKERDESKTOP_TYPE_HANDCARD,false);
		pokerimg.chPage[cards[i]] ++;
		item->setdx((int)((c_chPopupSize*c_OtherFx)/2));
		item->setdy((int)(c_chPopupSize*c_OtherFx));
		item->setZ(200+i);
		item->move(cx,cy);
		item->show();
		item->setMatrix(m);
		GetPageInterval(2,cards,i,&dx,&dy);
		cy += (dx*((int)(c_chPageLayoutSizeX*c_OtherFx)));
		if(cy + img.height() > ey)
		{
			if ( visible ) {
				cy = sy;
				cx -= ((int)(c_chPageLayoutSizeY*c_OtherFx));
			}else
				break;
		}
	}
	canvas()->update();
}

void DJGamePokerDesktop::RepaintView3Cards(quint8 seat,quint8 *cards,quint8 chPages)
{
	bool visible	= isCardVisible (seat);
	int sx,ex,y,iSelfHeight,cx,cy,dx,dy,i;
	GetDesktopCenterPoint(&sx,&y,&iSelfHeight);
	
	QImage img = GetCardPicture(DJGAME_POKER_BACKGROUND,3,c_OtherFx);
	QImage img1 = GetCardPicture(DJGAME_POKER_BACKGROUND,2,c_OtherFx);
	QImage img2 = GetCardPicture(DJGAME_POKER_BACKGROUND,4,c_OtherFx);
	quint8 iMaxWidth = GetCardsMaxWidth(3,cards,chPages);
	dx = 0;
	if(iMaxWidth >=1 )
		dx = (iMaxWidth-1)*((int)(c_chPageLayoutSizeX*c_OtherFx))+img.width();
	y = DJGAME_POKER_DESKTOP_AVATAR_MAXHEIGHT+10;
	sx -= (dx>>1);
	if(sx < DJGAME_POKER_DESKTOP_AVATAR_MAXWIDTH+img1.width()+10)
		sx = DJGAME_POKER_DESKTOP_AVATAR_MAXWIDTH+img1.width()+10;
	ex = GetRealWidth()-DJGAME_POKER_DESKTOP_AVATAR_MAXWIDTH-img2.width()-10;
	
	DJGamePokerImage pokerimg;
	memset(&pokerimg,0,sizeof(DJGamePokerImage));
	DJGamePokerItem *item;
	cx = sx;
	cy = y;
	QMatrix m = GetCurrentMatrix();
	int z = 170;
	for(i=0;i<chPages;i++)
	{
		img = GetCardPicture(cards[i],3,c_OtherFx);
		item = new DJGamePokerItem(img,canvas(),m,(pokerimg.chPage[cards[i]]<<8)+cards[i],seat,DJGAME_POKERDESKTOP_TYPE_HANDCARD,false);
		pokerimg.chPage[cards[i]] ++;
		item->setdx((int)((c_chPopupSize*c_OtherFx)/2));
		item->setdy((int)(c_chPopupSize*c_OtherFx));
		item->setZ(z);
		item->move(cx,cy);
		item->show();
		item->setMatrix(m);
		z ++;
		GetPageInterval(3,cards,i,&dx,&dy);
		cx += (dx*((int)(c_chPageLayoutSizeX*c_OtherFx)));
		if(cx+img.width() > ex)
		{
			if ( visible ) {
				cx = sx;
				z -= 60;
				cy -= ((int)(c_chPageLayoutSizeY*c_OtherFx));
			}else
				break;
		}
	}
	canvas()->update();
}
void DJGamePokerDesktop::RepaintView4Cards(quint8 seat,quint8 *cards,quint8 chPages)
{
	bool visible	= isCardVisible (seat);
	int x,sy,ey,iSelfHeight,cx,cy,dx,dy,i;
	GetDesktopCenterPoint(&x,&sy,&iSelfHeight);
	
	quint8 iMaxWidth = GetCardsMaxWidth(2,cards,chPages);
	QImage img = GetCardPicture(DJGAME_POKER_BACKGROUND,4,c_OtherFx);
	QImage img1 = GetCardPicture(DJGAME_POKER_BACKGROUND,3,c_OtherFx);
	dx = 0;
	if(iMaxWidth >=1 )
		dx = (iMaxWidth-1)*((int)(c_chPageLayoutSizeX*c_OtherFx))+img.height();
	x = GetRealWidth()-DJGAME_POKER_DESKTOP_AVATAR_MAXWIDTH-10;
//	printf("RepaintView4Cards,center(%d,%d) iMaxWidth=%d(%d)\n",x,sy,dx,iMaxWidth);
	sy += (dx>>1);
	if(sy > (int)(GetRealHeight()-iSelfHeight))
		sy = (GetRealHeight()-iSelfHeight);
	ey = DJGAME_POKER_DESKTOP_AVATAR_MAXHEIGHT+img1.height()+10;
	
	DJGamePokerImage pokerimg;
	memset(&pokerimg,0,sizeof(DJGamePokerImage));
	DJGamePokerItem *item;
	cx = x;
	cy = sy;
	QMatrix m = GetCurrentMatrix();

	for(i=0;i<chPages;i++)
	{
		
		img = GetCardPicture(cards[i],4,c_OtherFx);
		item = new DJGamePokerItem(img,canvas(),m,(pokerimg.chPage[cards[i]]<<8)+cards[i],seat,DJGAME_POKERDESKTOP_TYPE_HANDCARD,false);
		pokerimg.chPage[cards[i]] ++;
		item->setdx((int)((c_chPopupSize*c_OtherFx)/2));
		item->setdy((int)(c_chPopupSize*c_OtherFx));
		item->setZ(400+i);
		item->setHAlignment(Qt::AlignRight);
		item->setVAlignment(Qt::AlignBottom);
		item->move(cx,cy);
		item->show();
		item->setMatrix(m);
		GetPageInterval(2,cards,i,&dx,&dy);
	
		cy -= (dx*((int)(c_chPageLayoutSizeX*c_OtherFx)));
		if(cy - img.height() < ey)
		{
			if ( visible ) {
				cy = sy;
				cx += ((int)(c_chPageLayoutSizeY*c_OtherFx));
			}else
				break;
		}
	}
	
	canvas()->update();
}

void DJGamePokerDesktop::DisplayTheRound(int iRound)
{
	DJGameTraceManager traces;
	traces = GetTraceManager();
	//unsigned short shSteps = traces.GetTotalSteps();
}

bool DJGamePokerDesktop::IsThrowStep(PGeneralGameTrace2Head ptrace)
{
	return false;
}

void DJGamePokerDesktop::RepaintView1Throw(quint8 seat,quint8 *cards,quint8 chPages)
{
	int x,y,i;
	GetDesktopCenterPoint(&x,&y,NULL);
	y += (c_chCenterSize>>1);
	QImage img = GetCardPicture(*cards,1,c_ThrowFx);
	int iWidth = static_cast<int>((chPages-1)*c_chPageLayoutSizeX*c_ThrowFx)+img.width();
	x -= (iWidth>>1);
	QMatrix m = GetCurrentMatrix();
	DJGamePokerItem *item;
	for(i=0;i<chPages;i++)
	{
		img = GetCardPicture(cards[i],1,c_ThrowFx);
		item = new DJGamePokerItem(img,canvas(),m,cards[i],seat,DJGAME_POKERDESKTOP_TYPE_THROWCARD,false);
		item->setZ(1200+i);
		item->move(x,y);
		item->show();
		item->setMatrix(m);
		x += static_cast<int>(c_chPageLayoutSizeX*c_ThrowFx);
	}
	canvas()->update();
}

void DJGamePokerDesktop::RepaintView2Throw(quint8 seat,quint8 *cards,quint8 chPages)
{
	int x,y,i;
	GetDesktopCenterPoint(&x,&y,NULL);
	QImage img = GetCardPicture(*cards,1,c_ThrowFx);
	y -= (img.height()>>1);
	int iWidth = (chPages-1)*static_cast<int>(c_chPageLayoutSizeX*c_ThrowFx)+img.width();
	x -= (iWidth+(c_chCenterSize>>1));
	QMatrix m = GetCurrentMatrix();
	DJGamePokerItem *item;
	for(i=0;i<chPages;i++)
	{
		img = GetCardPicture(cards[i],1,c_ThrowFx);
		item = new DJGamePokerItem(img,canvas(),m,cards[i],seat,DJGAME_POKERDESKTOP_TYPE_THROWCARD,false);
		item->setZ(1100+i);
		item->move(x,y);
		item->show();
		item->setMatrix(m);
		x += static_cast<int>(c_chPageLayoutSizeX*c_ThrowFx);
	}
	canvas()->update();
}
void DJGamePokerDesktop::RepaintView3Throw(quint8 seat,quint8 *cards,quint8 chPages)
{
	int x,y,i;
	GetDesktopCenterPoint(&x,&y,NULL);
	QImage img = GetCardPicture(*cards,1,c_ThrowFx);
	int iWidth = (chPages-1)*static_cast<int>(c_chPageLayoutSizeX*c_ThrowFx)+img.width();
	x -= (iWidth>>1);
	y -= (img.height()+(c_chCenterSize>>1));
	QMatrix m = GetCurrentMatrix();
	DJGamePokerItem *item;
	for(i=0;i<chPages;i++)
	{
		img = GetCardPicture(cards[i],1,c_ThrowFx);
		item = new DJGamePokerItem(img,canvas(),m,cards[i],seat,DJGAME_POKERDESKTOP_TYPE_THROWCARD,false);
		item->setZ(1000+i);
		item->move(x,y);
		item->show();
		item->setMatrix(m);
		x += static_cast<int>(c_chPageLayoutSizeX*c_ThrowFx);
	}
	canvas()->update();
}
void DJGamePokerDesktop::RepaintView4Throw(quint8 seat,quint8 *cards,quint8 chPages)
{
	int x,y,i;
	GetDesktopCenterPoint(&x,&y,NULL);
	QImage img = GetCardPicture(*cards,1,c_ThrowFx);
	y -= (img.height()>>1);
	x += (c_chCenterSize>>1);
	QMatrix m = GetCurrentMatrix();
	DJGamePokerItem *item;
	for(i=0;i<chPages;i++)
	{
		img = GetCardPicture(cards[i],1,c_ThrowFx);
		item = new DJGamePokerItem(img,canvas(),m,cards[i],seat,DJGAME_POKERDESKTOP_TYPE_THROWCARD,false);
		item->setZ(1100+i);
		item->move(x,y);
		item->show();
		item->setMatrix(m);
		x += static_cast<int>(c_chPageLayoutSizeX*c_ThrowFx);
	}
	canvas()->update();
}

void DJGamePokerDesktop::RepaintView1Attach(quint8 seat,quint8 *cards,quint8 chPages)
{
	if(chPages == 0 || cards == NULL)
		return;
	int x,y,ex,iSelfHeight;
	GetDesktopCenterPoint(&x,&y,&iSelfHeight);
	QImage img = GetCardPicture(DJGAME_POKER_BACKGROUND,1,c_ThrowFx);
	QImage img1 = GetCardPicture(DJGAME_POKER_BACKGROUND,2,c_OtherFx);
	y += ((c_chCenterSize>>1)+img.height());
	x = 5;
	ex = DJGAME_POKER_DESKTOP_AVATAR_MAXWIDTH+10;
	QMatrix m = GetCurrentMatrix();
	DJGamePokerItem *item;
	for(int i=0;i<chPages;i++)
	{
		img = GetCardPicture(cards[i],1,c_AttachFx);
		item = new DJGamePokerItem(img,canvas(),m,cards[i],seat,DJGAME_POKERDESKTOP_TYPE_ATTACHCARD,false);
		item->setZ(i);
		item->move(x,y);
		item->show();
		item->setMatrix(m);
		x += static_cast<int>(c_chPageLayoutSizeX*c_AttachFx);
		if(x + c_chPageLayoutSizeX*c_AttachFx > ex)
		{
			y += static_cast<int>(c_chPageLayoutSizeY*c_AttachFx);
			x = 5;
		}
			
	}
}

void DJGamePokerDesktop::RepaintView2Attach(quint8 seat,quint8 *cards,quint8 chPages)
{
	if(chPages == 0 || cards == NULL)
		return;
	
  	int cx,x,y;
	QRect showRect	=  idealRectOfShow( seat );
	x	= showRect.left() + DJGAME_POKER_DESKTOP_AVATAR_MAXWIDTH;
	y	= showRect.top() - 5; 
	
 	QMatrix m = GetCurrentMatrix();
	cx = x;
	DJGamePokerItem *item;
	QImage img;
	int dx = static_cast<int>(c_chPageLayoutSizeX*c_AttachFx);
	for(int i=0;i<chPages;i++)
	{
		img = GetCardPicture(cards[i],1,c_AttachFx);
		item = new DJGamePokerItem(img,canvas(),m,cards[i],seat,DJGAME_POKERDESKTOP_TYPE_ATTACHCARD,false);
		item->setZ(50-i);
		item->setHAlignment(Qt::AlignRight);
		item->setVAlignment(Qt::AlignBottom);
		item->move(cx,y);
		item->show();
		item->setMatrix(m);
		cx -= dx;
		if(cx-dx < 0)
		{
			cx = x;
			y -= static_cast<int>(c_chPageLayoutSizeY*c_AttachFx);
		}
	}
}

void DJGamePokerDesktop::RepaintView3Attach(quint8 seat,quint8 *cards,quint8 chPages)
{
	if(chPages == 0 || cards == NULL)
		return;
	
	int cy,x,y;
	QRect showRect	=  idealRectOfShow( seat );
	x	= showRect.left() + DJGAME_POKER_DESKTOP_AVATAR_MAXWIDTH + 5;
	y	= showRect.top() + DJGAME_POKER_DESKTOP_AVATAR_MAXHEIGHT; 
	
	QMatrix m = GetCurrentMatrix();
	cy = y;
	int z = 10;
	DJGamePokerItem *item;
	QImage img;
	int dy = static_cast<int>(c_chPageLayoutSizeY*c_AttachFx);
	for(int i=0;i<chPages;i++)
	{
		img = GetCardPicture(cards[i],1,c_AttachFx);
		item = new DJGamePokerItem(img,canvas(),m,cards[i],seat,DJGAME_POKERDESKTOP_TYPE_ATTACHCARD,false);
		item->setZ(z);
		z --;
		item->setVAlignment(Qt::AlignBottom);
		item->move(x,cy);
		item->show();
		item->setMatrix(m);
		cy -= dy;
		if(cy-img.height() < 0)
		{
			x += static_cast<int>(c_chPageLayoutSizeX*c_AttachFx);
			cy = y;
			z += 10;
		}
			
	}
}

void DJGamePokerDesktop::RepaintView4Attach(quint8 seat,quint8 *cards,quint8 chPages)
{
	if(chPages == 0 || cards == NULL)
		return;
		
	int cx,x,y,ex=GetRealWidth();
	QRect showRect	=  idealRectOfShow( seat );
	x	= showRect.left();
	y	= showRect.top() - 5;  
	
	QMatrix m = GetCurrentMatrix();
	cx = x;
	int z=50;
	DJGamePokerItem *item;
	QImage img;
	int dx = static_cast<int>(c_chPageLayoutSizeX*c_AttachFx);
	for(int i=0;i<chPages;i++)
	{
		img = GetCardPicture(cards[i],1,c_AttachFx);
		item = new DJGamePokerItem(img,canvas(),m,cards[i],seat,DJGAME_POKERDESKTOP_TYPE_ATTACHCARD,false);
		item->setZ(z);
		z ++;
		item->setVAlignment(Qt::AlignBottom);
		item->move(cx,y);
		item->show();
		item->setMatrix(m);
		cx += dx;
		if(cx + dx > ex)
		{
			cx = x;
			y -= static_cast<int>(c_chPageLayoutSizeY*c_AttachFx);
			z -= 10;
		}
			
	}
}
void DJGamePokerDesktop::GetDesktopCenterPoint(int *x,int *y,int *selfHeight)
{
	QImage img = GetCardPicture(DJGAME_POKER_BACKGROUND,1,c_SelfFx);
	QImage img1 = GetCardPicture(DJGAME_POKER_BACKGROUND,1,c_ThrowFx);
	QImage img2 = GetCardPicture(DJGAME_POKER_BACKGROUND,3,c_OtherFx);
	quint16 iSelfHeight = GetSelfViewMaxHeight(img,c_chPageLayoutSizeY);
	if(selfHeight != NULL)
		*selfHeight = iSelfHeight;
	
	if(x != NULL)
		*x = GetRealWidth()>>1;
	if(y != NULL)
	{
		int i = DJGAME_POKER_DESKTOP_AVATAR_MAXHEIGHT+10+img2.height();
		*y = i+(GetRealHeight()-iSelfHeight-i)/2;
	}
}
void DJGamePokerDesktop::RepaintAttachCards(quint8 seat,quint8 *pbuf,quint8 chPages)
{
	quint8 chView = MapSeat2View(seat);
	ClearSeatAttachCard(seat);
	switch(chView)
	{
		case 1 :
			RepaintView1Attach(seat,pbuf,chPages);
			break;
		case 2 :
			RepaintView2Attach(seat,pbuf,chPages);
			break;
		case 3 :
			RepaintView3Attach(seat,pbuf,chPages);
			break;
		case 4 :
			RepaintView4Attach(seat,pbuf,chPages);
			break;
	}
}
void DJGamePokerDesktop::RepaintThrowCard(quint8 seat,quint8 *pbuf,quint8 chPages)
{
	quint8 chView = MapSeat2View(seat);
	ClearSeatThrowCard(seat);
	switch(chView)
	{
		case 1 :
			RepaintView1Throw(seat,pbuf,chPages);
			break;
		case 2 :
			RepaintView2Throw(seat,pbuf,chPages);
			break;
		case 3 :
			RepaintView3Throw(seat,pbuf,chPages);
			break;
		case 4 :
			RepaintView4Throw(seat,pbuf,chPages);
			break;
	}
}

void DJGamePokerDesktop::PlayerThrowCards(quint8 chSeat,quint8 *pbuf,quint8 chPages)
{
}

void DJGamePokerDesktop::SetOrder(bool bOrder,bool bLineClass,bool bOrderByClass)
{
	c_bOrder = bOrder;
	c_bOrderByClass = bOrderByClass;
	c_bLineClass = bLineClass;
}
void DJGamePokerDesktop::ResetPlayerCards(quint8 chSeat,quint8 *pbuf,quint8 chPages)
{
	if(c_ppokerimg[chSeat] == NULL)
		return ;
	memset(c_ppokerimg[chSeat],0,sizeof(DJGamePokerImage));
	AppendPlayerCards(chSeat,pbuf,chPages);
}
void DJGamePokerDesktop::AppendPlayerCards(quint8 chSeat,quint8 *pbuf,quint8 chPages)
{
	if(c_ppokerimg[chSeat] == NULL || chPages == 0)
		return ;
	
	int i;
	
	for(i=0;i<chPages;i++)
	{
		if ( 0 == pbuf[i] )
			continue; 
		if(DJGAME_POKER_ERRORCARD(pbuf[i]))
			c_ppokerimg[chSeat]->chPage[DJGAME_POKER_BACKGROUND] ++;
		else
			c_ppokerimg[chSeat]->chPage[pbuf[i]] ++;
	}
		
}
void DJGamePokerDesktop::RemovePlayerCards(quint8 chSeat,quint8 *pbuf,quint8 chPages)
{
	if(c_ppokerimg[chSeat] == NULL || chPages == 0)
		return ;
	
	int i;
	
	for(i=0;i<chPages;i++)
	{
		if(DJGAME_POKER_ERRORCARD(pbuf[i]) || c_ppokerimg[chSeat]->chPage[pbuf[i]] == 0)
		{
			if(c_ppokerimg[chSeat]->chPage[DJGAME_POKER_BACKGROUND] > 0)
				c_ppokerimg[chSeat]->chPage[DJGAME_POKER_BACKGROUND] --;
		}else
			c_ppokerimg[chSeat]->chPage[pbuf[i]] --;
	}
		
}

void DJGamePokerDesktop::SetCardStatus(quint8 chSeat,quint8 chCard,quint8 status)
{
	if(c_ppokerimg[chSeat] != NULL && !DJGAME_POKER_ERRORCARD(chCard))
	{
		c_ppokerimg[chSeat]->chSign[chCard] = status;
	}
}
quint8 DJGamePokerDesktop::GetCardStatus(quint8 chSeat,quint8 chCard)
{
	if(c_ppokerimg[chSeat] != NULL && !DJGAME_POKER_ERRORCARD(chCard))
	{
		return c_ppokerimg[chSeat]->chSign[chCard];
	}
	return 0;
}

quint8 DJGamePokerDesktop::GetCardPages(quint8 chSeat,quint8 chCard)
{
	if(c_ppokerimg[chSeat] != NULL && !DJGAME_POKER_ERRORCARD(chCard))
	{
		return c_ppokerimg[chSeat]->chPage[chCard];
	}
	return 0;
}
PDJGamePokerImage DJGamePokerDesktop::GetPlayerCardImage(quint8 chSeat) const
{
	return c_ppokerimg[chSeat];
}

quint8 DJGamePokerDesktop::PokerImage2Bytes(PDJGamePokerImage ppokerimg,
									quint8 chClass,quint8 chValue,
									quint8 *psubset,quint8 chSubMax,bool bOrder)
{
	unsigned char chRet = 0;
	int iS,iE,d=1;
	if(chClass == 0 || chClass > DJGAME_POKER_CLASS_S)
	{
		iS = 1;
		iE = 0x3F;
	}else
	{
		iS = DJGAME_POKER_MAKE_CODE(0,chClass,1);
		iE = DJGAME_POKER_MAKE_CODE(0,chClass,DJGAME_POKER_K);
	}
	if(chValue != 0)
	{
		d = 0x10;
		iS += (chValue-1);
	}
	int i,j;
	if(bOrder)
	{
		for(i=iS; i<=iE;i+=d)
		{
			if( ppokerimg->chPage[i] > 0 )
			{
				//printf("%02x(%d) ",i,ppokerimg->chPage[i]);
				for(j=0;j<ppokerimg->chPage[i];j++)
				{
					if(chRet < chSubMax)
						*(psubset+chRet) = i;
					chRet ++;
				}
			}
		}
	}else 
	{
		for(i=iE; i>=iS;i-=d)
		{
			if( ppokerimg->chPage[i] > 0 )
			{
				//printf("%02x(%d)",i,ppokerimg->chPage[i]);
				for(j=0;j<ppokerimg->chPage[i];j++)
				{
					if(chRet < chSubMax)
						*(psubset+chRet) = i;
						
					chRet ++;
				}
			}
		}
	}
//	printf("\n");
	
	if(chRet > 1)
	{
		quint8 chTemp;
		int iRes;
		do
		{
			j = 0;
			for(i=0;i<chRet-1;i++)
			{
				iRes = Compare2Card(psubset[i],psubset[i+1],ppokerimg);
				if( (bOrder && iRes > 0) || (!bOrder && iRes < 0))
				{
					chTemp = psubset[i+1];
					psubset[i+1] = psubset[i];
					psubset[i] = chTemp;
					j ++;
				}
			}
		}while(j>0);
	}
	return chRet;
}
void  DJGamePokerDesktop::SetCardPictureSize(quint8 chCenter,quint8 chPopup,quint8 chLayoutX,quint8 chLayoutY)
{
	c_chCenterSize = chCenter;
	c_chPopupSize = chPopup;
	c_chPageLayoutSizeX = chLayoutX;
	c_chPageLayoutSizeY = chLayoutY;
}
unsigned int DJGamePokerDesktop::GetDesktopMaxHeight(QPixmap &pix,quint8 chCenterSize,
														quint8 chLayoutSizeY)
{
	return DJGAME_POKER_DESKTOP_AVATAR_MAXHEIGHT+10+((int)(pix.height()*0.75))+pix.height()+chCenterSize+pix.height()+GetSelfViewMaxHeight(pix,chLayoutSizeY);
}

unsigned int DJGamePokerDesktop::GetSelfViewMaxHeight(QPixmap &pix, quint8 chLayoutSizeY)
{
	return chLayoutSizeY*5+15+pix.height()/2;
}
unsigned int DJGamePokerDesktop::GetSelfViewMaxHeight(QImage &img, quint8 chLayoutSizeY)
{
	return chLayoutSizeY*5+15+img.height()/2;
}
void DJGamePokerDesktop::repaintAllRemainders() 
{ 
	for ( int seat = 1; seat <= c_Panel->numberOfSeats(); ++seat) { 
		repaintRemainder( seat );
	}
}
void DJGamePokerDesktop::repaintRemainder( quint8 seat )
{
	if ( !m_remainderEnabled ) {
		return;
	}
	
	DJMatrixCanvasText	*remainderItem	= m_remainderItems.value( seat, 0 );
	if ( 0 == remainderItem )
		return;
	int mode	= m_remainderModes.value( seat, DJ_MATRIX_CANVAS_ITEM_HIDE );
	if ( DJ_MATRIX_CANVAS_ITEM_HIDE == mode ) {
		remainderItem->hide();
	}else {
		Qt::Alignment	align	= m_remainderAligns.value( seat, 0 );
		remainderItem->setTextFlags( align );
		remainderItem->setText( QString("( %1 )").arg( numberOfCards( seat ) ) );
		QPoint	point	= m_remainderPoints.value( seat, QPoint() );
		if (  DJ_MATRIX_CANVAS_ITEM_MATRIMOVE == mode  )
			remainderItem->matrimove( point.x(), point.y() );
		else
			remainderItem->move( point.x(), point.y() );
		remainderItem->show();
	}
}
void DJGamePokerDesktop::hideAllRemainders()
{
	foreach( DJMatrixCanvasText *remainderItem, m_remainderItems ) {
		remainderItem->hide();
	}
}
void DJGamePokerDesktop::setRemainderEnabled( bool enabled )
{
	m_remainderEnabled	= enabled;
}
DJMatrixCanvasText* DJGamePokerDesktop::remainderItem( quint8 seat )
{
	return m_remainderItems.value( seat, 0 );
}
void DJGamePokerDesktop::userArrived( quint32 userId, quint8 seatId )
{
	djDebug()<<"DJGamePokerDesktop::userArrived"<<userId<<seatId;
	DJGameDesktop::userArrived( userId, seatId );
	
	locateRemainderPositions( m_remainderPoints, m_remainderAligns, m_remainderModes );
	repaintAllRemainders();
}
void DJGamePokerDesktop::handleMatrixChanged( const QMatrix& matrix )
{
	djDebug()<<"DJGamePokerDesktop::handleMatrixChanged"<<matrix;
	DJGameDesktop::handleMatrixChanged( matrix );
		
	foreach( DJMatrixCanvasText *remainderItem, m_remainderItems ) {
		remainderItem->setExternalMatrix( matrix );
	}
	
	locateRemainderPositions( m_remainderPoints, m_remainderAligns, m_remainderModes );
	repaintAllRemainders();
}
void DJGamePokerDesktop::locateRemainderPositions( QList<QPoint>& points, QList<Qt::Alignment>& aligns, QList<int> &modes )
{
	points.clear();
	aligns.clear();
	modes.clear();
	
	quint8	numberOfSeats	= c_Panel->numberOfSeats(); 
	
	for ( quint8 seat = 0; seat <= numberOfSeats; ++seat ) {
		points 	<< QPoint();
		aligns 	<< 0;
		modes	<< DJ_MATRIX_CANVAS_ITEM_HIDE; 
	}
	
	for( quint8 seat = 1; seat <= numberOfSeats; ++seat ) {
		QRect	nameRect	= idealRectOfName( seat );
    	quint8 view = MapSeat2View(seat);
    	switch( view ) {
    	case 1: {
    		points[seat].setX( nameRect.right() + 10 );
    		points[seat].setY( nameRect.top() );
    		modes[seat]	= DJ_MATRIX_CANVAS_ITEM_MATRIMOVE;
    		break;
    	} 
    	case 2:  {
    		points[seat].setX( nameRect.left() );
    		points[seat].setY( nameRect.bottom() + 1 );
    		modes[seat]	= DJ_MATRIX_CANVAS_ITEM_MATRIMOVE;
    		break;
    	}
    	case 3:  {
    		points[seat].setX( nameRect.right() );
    		points[seat].setY( nameRect.bottom() + 1 );
    		aligns[seat]	= Qt::AlignRight;
    		modes[seat]	= DJ_MATRIX_CANVAS_ITEM_MATRIMOVE;
    		break;
    	}
    	case 4:  {
    		points[seat].setX( nameRect.right() );
    		points[seat].setY( nameRect.bottom() + 1 );
    		aligns[seat]	= Qt::AlignRight;
    		modes[seat]	= DJ_MATRIX_CANVAS_ITEM_MATRIMOVE;
    		break;
    	}
    	default:
    		break;
      	}
	}
}
void DJGamePokerDesktop::setPokerSortKeys( const QList<SortKey>& sortKeys )
{
	m_pokerSortKeys	= sortKeys;
}
void DJGamePokerDesktop::setBridgeCard( bool isBridgeCard )
{
	m_isBridgeCard	= isBridgeCard;
}
//result is descending
void DJGamePokerDesktop::sortCards( quint8 *cards, quint8 len )
{
	djDebug()<<"DJGamePokerDesktop::sortCards"<<len;
	DebugBuffer( (char*)cards, len );
	QList<DJPoker>	pokers;
	for( int i = 0; i < len; ++i ) {
		pokers << DJPoker( cards[i], m_isBridgeCard );
	}
	
	sortPokers( pokers );
	
	//sort descending
	for ( int i = 0; i < len; ++i ) {
		cards[len-1-i]	= pokers.at(i).toByte( m_isBridgeCard );
	}
}
QHash<DJPoker,int> DJGamePokerDesktop::createCountPokers( const QList<DJPoker>& handPokers ) const
{
	QHash<DJPoker,int> countPokers;
	foreach( DJPoker poker, handPokers ) {
		int count	= handPokers.count( poker );
		countPokers.insert( poker, count );
	}
	return countPokers;
}
//result is ascending
void DJGamePokerDesktop::sortPokers( QList<DJPoker>& pokers )
{
	m_sortingPokers	= createCountPokers( pokers );
	qSort( pokers.begin(), pokers.end(), PokerLessThan );
}
bool DJGamePokerDesktop::pokerLessThan( const DJPoker& poker1, const DJPoker& poker2 )
{
	int result	= 0;
	for( int i = 0; i < m_pokerSortKeys.size(); ++i ) {
		SortKey	key	= m_pokerSortKeys.at(i);
		result	= comparePokerWithKey( poker1, poker2, key );
		if ( result != 0 )
			break;
	}
	
	if ( -1 == result ) {
		return true;
	}else {
		return false;
	}
}
int	DJGamePokerDesktop::comparePokerWithKey( const DJPoker& poker1, const DJPoker& poker2, SortKey key )
{
	switch(key) {
	case SortByASCount: {
		int ascount1	= numberOfPokersOnAllSuits( m_sortingPokers, DJPoker(DJPoker::AnySuit,poker1.point()) );
		int ascount2	= numberOfPokersOnAllSuits( m_sortingPokers, DJPoker(DJPoker::AnySuit,poker2.point()) );
		if ( ascount1 < ascount2 )
			return -1;
		else if ( ascount1 > ascount2 )
			return 1;
		else
			return 0;
		break;
	}
	case SortBySuit: {
		int suitRank1	= rankOfSuit(poker1.suit());
		int suitRank2	= rankOfSuit(poker2.suit());
		if ( suitRank1 < suitRank2 )
			return -1;
		else if ( suitRank1 > suitRank2 )
			return 1;
		else
			return 0;
		break;
	}
	case SortByPoint: {
		int pointRank1	= rankOfPoint(poker1.point());
		int pointRank2	= rankOfPoint(poker2.point());
		if ( pointRank1 < pointRank2 )
			return -1;
		else if ( pointRank1 > pointRank2 )
			return 1;
		else
			return 0;
		break;
	}
	default:
		return 0;
	}
}
int DJGamePokerDesktop::numberOfPokersOnAllSuits( const QHash<DJPoker,int> countPokers, const DJPoker& comboPoker ) const
{
	int comboSuit	= comboPoker.suit();
	DJPoker::Point	point	= comboPoker.point();
	int count	= 0;
	foreach( int suit, allSuits ) {
		if ( comboSuit & suit ) {
			count	+= countPokers.value( DJPoker(suit,point) );
		}
	}
	return count;
}							 		
void DJGamePokerDesktop::setPokerSortMode( SortMode mode )
{
	switch( mode ) {
	case ASCountPointSuit: {
		QList<SortKey> sortKeys;
		sortKeys << SortByASCount << SortByPoint << SortBySuit;
		setPokerSortKeys( sortKeys );
		break;
	}
	case PointASCountSuit: {
		QList<SortKey> sortKeys;
		sortKeys << SortByPoint << SortByASCount << SortBySuit;
		setPokerSortKeys( sortKeys );
		break;
	}
	case SuitPoint: {
		QList<SortKey> sortKeys;
		sortKeys << SortBySuit << SortByPoint;
		setPokerSortKeys( sortKeys );
		break;
	}
	case PointSuit: {
		QList<SortKey> sortKeys;
		sortKeys << SortByPoint << SortBySuit;
		setPokerSortKeys( sortKeys );
		break;
	}
	default:
		break;
	}
}
void DJGamePokerDesktop::setRankOfSuits( SuitRankMode mode )
{
	m_rankOfSuits.clear();
	if ( BridgeSuitRank == mode ) {		
		m_rankOfSuits.insert( DJPoker::Diamond, 2 );
		m_rankOfSuits.insert( DJPoker::Club, 1 );
	}else {
		m_rankOfSuits.insert( DJPoker::Diamond, 1 );
		m_rankOfSuits.insert( DJPoker::Club, 2 );
	}
	m_rankOfSuits.insert( DJPoker::Heart, 3 );
	m_rankOfSuits.insert( DJPoker::Spade, 4 );
	m_rankOfSuits.insert( DJPoker::Joker, 20 );
	/*
	if ( hasTrump ) {
		int base	= 10;
		m_rankOfSuits.insert( DJPoker::Trump | DJPoker::Diamond, base + m_rankOfSuits.value(DJPoker::Diamond) );
		m_rankOfSuits.insert( DJPoker::Trump | DJPoker::Club, base + m_rankOfSuits.value(DJPoker::Club) );
		m_rankOfSuits.insert( DJPoker::Trump | DJPoker::Heart, base + m_rankOfSuits.value(DJPoker::Heart) );
		m_rankOfSuits.insert( DJPoker::Trump | DJPoker::Spade, base + m_rankOfSuits.value(DJPoker::Spade) );
	}
	*/	
}
void DJGamePokerDesktop::setRankOfPoints( PointRankMode mode )
{	
	m_rankOfPoints.clear();
	if ( Num2PointRank == mode ) {
		m_rankOfPoints.insert( DJPoker::Num2, 0x12 );
	}else {
		m_rankOfPoints.insert( DJPoker::Num2, 0x02 );
	}
	m_rankOfPoints.insert( DJPoker::Ace, 0x11 );
	m_rankOfPoints.insert( DJPoker::Num3, 0x03 );
	m_rankOfPoints.insert( DJPoker::Num4, 0x04 );
	m_rankOfPoints.insert( DJPoker::Num5, 0x05 );
	m_rankOfPoints.insert( DJPoker::Num6, 0x06 );
	m_rankOfPoints.insert( DJPoker::Num7, 0x07 );
	m_rankOfPoints.insert( DJPoker::Num8, 0x08 );
	m_rankOfPoints.insert( DJPoker::Num9, 0x09 );
	m_rankOfPoints.insert( DJPoker::Num10, 0x0A );
	m_rankOfPoints.insert( DJPoker::Jack, 0x0B );
	m_rankOfPoints.insert( DJPoker::Queen, 0x0C );
	m_rankOfPoints.insert( DJPoker::King, 0x0D );
	m_rankOfPoints.insert( DJPoker::SmallJoker, 0x3E );
	m_rankOfPoints.insert( DJPoker::BigJoker, 0x3F );
}
void DJGamePokerDesktop::saveSortInfo()
{
	m_savedSortKeys		= m_pokerSortKeys;
	m_savedRankOfSuits	= m_rankOfSuits;
	m_savedRankOfPoints	= m_rankOfPoints;
}
void DJGamePokerDesktop::restoreSortInfo()
{
	m_pokerSortKeys	= m_savedSortKeys;
	m_rankOfSuits	= m_savedRankOfSuits;
	m_rankOfPoints	= m_savedRankOfPoints;
}
/*
DJPoker DJGamePokerDesktop::greatestPoker( const QList<DJPoker>& pokers )
{
	if ( 1 == pokers.size() )
		return pokers.first();
	DJPoker poker;
	for( int i = 0; i < pokers.size() - 1; ++i) {
		DJPoker poker1	= pokers.at(i);
		DJPoker poker2	= pokers.at(i+1);
		if ( groupGreaterThan( QList<DJPoker>()<< poker1, QList<DJPoker>()<< poker2 ) ) {
			poker	= poker1;
		}else {
			poker	= poker2;
		}
	}
	return poker;
}
*/
bool DJGamePokerDesktop::groupGreaterThan( const QList<DJPoker>& group1,
									const QList<DJPoker>& group2 )
{
	/*
	if ( isSuitSensitive ) {
		int value1	= rankOfPoint(poker1.point());
		int value2	= rankOfPoint(poker2.point());
		if ( value1 == value2 ) {
			//point value is equal ,then compare suit value
			return rankOfSuit(poker1.suit()) > rankOfSuit(poker2.suit());
		}else {
			return value1 > value2;
		}
	}else {
		return rankOfPoint(poker1.point()) > rankOfPoint(poker2.point()); 
	}
	*/
	/*
	QList<DJPoker> pokers1	= group1;
	QList<DJPoker> pokers2	= group2;
	
	saveSortInfo();
	setPokerSortMode( PointSuit );
	sortPokers( pokers1 );
	sortPokers( pokers2 );
	restoreSortInfo();
	
	return rankOfPoint(pokers1.first().point()) > rankOfPoint(pokers2.first().point());
	*/
	return rankOfPoint(group1.first().point()) > rankOfPoint(group2.first().point());
}
bool DJGamePokerDesktop::shunGreaterThan( const QList<DJPoker>& shun1,
										const QList<DJPoker>& shun2 )
{
	/*
	if ( isSuitSensitive ) {
		//straight flush is greater than straight
		return rankOfSuit(poker1.suit()) > rankOfSuit(poker2.suit());
	}else {
		return rankOfPoint(poker1.point()) > rankOfPoint(poker2.point());
	}
	*/
	//shun has ordered, low -> high
	/*
	QList<DJPoker> pokers1	= shun1;
	QList<DJPoker> pokers2	= shun2;
	
	saveSortInfo();
	setPokerSortMode( PointSuit );
	sortPokers( pokers1 );
	sortPokers( pokers2 );
	restoreSortInfo();
	return rankOfPoint(pokers1.first().point()) > rankOfPoint(pokers2.first().point());
	*/
	return rankOfPoint(shun1.last().point()) > rankOfPoint(shun2.last().point());
}								
//same rank pokers can be united to become group
//e.g. Spade5 Heart5 Club5 Diamond5 => 5555
DJPoker DJGamePokerDesktop::parallelPoker( const DJPoker& poker, bool isStrictSuit ) const
{
	if ( isStrictSuit )
		return DJPoker( poker.suit(), poker.point() );
	else
		return DJPoker( DJPoker::AnySuit, poker.point() );
}
//serveral serial pokers can be linked to become shun
//e.g. Spade3 Heart4 Club5
DJPoker DJGamePokerDesktop::higherSerialPoker( const DJPoker& poker, bool isStrictSuit ) const
{
	DJPoker::Point point	= poker.point();
	if ( point >= DJPoker::Num2 && point <= DJPoker::Queen ) {
		point	= (DJPoker::Point)(point + 1);
	}else if ( DJPoker::King == point ) {
		point	= DJPoker::Ace;
	}else {
		return DJPoker();
	}
	if ( isStrictSuit )
		return DJPoker( poker.suit(), point );
	else
		return DJPoker( DJPoker::AnySuit, point );
}
DJPoker DJGamePokerDesktop::lowerSerialPoker( const DJPoker& poker, bool isStrictSuit ) const
{
	DJPoker::Point point	= poker.point();
	if ( point >= DJPoker::Num3 && point <= DJPoker::King ) {
		point	= (DJPoker::Point)(point - 1);
	}else if ( DJPoker::Ace == point ) {
		point	= DJPoker::King;
	}else {
		return DJPoker();
	}
	if ( isStrictSuit )
		return DJPoker( poker.suit(), point );
	else
		return DJPoker( DJPoker::AnySuit, point );
}
bool DJGamePokerDesktop::isHighestSerialPoker( const DJPoker& poker ) const
{
	return false;
}
bool DJGamePokerDesktop::isLowestSerialPoker( const DJPoker& poker ) const
{
	return false;
}
QList<DJPoker> DJGamePokerDesktop::findGroup( const QHash<DJPoker,int> countPokers,
													const DJPoker& keyPoker,
											 		int width,
											 		bool isStrictSuit,
											 		bool isExactWidth ) const
{
	if ( !keyPoker.isValid() )
    	return QList<DJPoker>();

	if ( isStrictSuit )
		return getGroupFromOneOfSuits( countPokers, keyPoker, width, isExactWidth );
	else
	 	return getGroupFromAllOfSuits( countPokers, keyPoker, width, isExactWidth );
}											 		
QList<DJPoker> DJGamePokerDesktop::getGroupFromAllOfSuits( const QHash<DJPoker,int> countPokers,
											const DJPoker& keyPoker, int width,
											bool isExactWidth ) const
{
	int comboSuit	= keyPoker.suit();
	DJPoker::Point	point	= keyPoker.point();
	
	QList<DJPoker> pokers;
	int totalCount	= 0;
	foreach( int suit, allSuits ) {
		if ( comboSuit & suit ) {
			DJPoker poker	= DJPoker(suit,point);
			int count = countPokers.value( poker );
			for( int i = 0; i < count; ++i ) {
				pokers << poker;
			}
			totalCount	+= count;
		}
	}
	if ( isExactWidth ) {
		if ( totalCount == width )
			return pokers;
		else
			return QList<DJPoker>();
	}else {
		if ( totalCount >= width ) {
			return pokers.mid(0,width);
		}else
			return QList<DJPoker>();
	}
}
QList<DJPoker> DJGamePokerDesktop::getGroupFromOneOfSuits( const QHash<DJPoker,int> countPokers,
											const DJPoker& keyPoker, int width,
											bool isExactWidth ) const
{
	int comboSuit	= keyPoker.suit();
	DJPoker::Point	point	= keyPoker.point();
	
	QList<DJPoker> pokers;
	foreach( int suit, allSuits ) {
		if ( comboSuit & suit ) {
			DJPoker poker	= DJPoker(suit,point);
			int count = countPokers.value( poker );
			for( int i = 0; i < count; ++i ) {
				pokers << poker;
			}
			if ( isExactWidth ) {
        		if ( count == width )
        			return pokers;
        		else
        			return QList<DJPoker>();
        	}else {
        		if ( count >= width ) {
        			return pokers.mid(0,width);
        		}else
        			return QList<DJPoker>();
        	}
		}
	}
	return QList<DJPoker>();
}
QList<DJPoker> DJGamePokerDesktop::findNextGroup( const QHash<DJPoker,int> countPokers,
												const DJPoker& currentKeyPoker, 
												DJPoker& nextKeyPoker,
												int width,
												bool isHigher,
												bool isStrictSuit,
												bool isExactWidth ) const
{
	if ( !currentKeyPoker.isValid() ) {
		return QList<DJPoker>();
	}
	//djDebug()<<"findNextGroup"<<isHigher<<"current keyPoker"<<currentKeyPoker.description();
	
	if ( isHigher )
		nextKeyPoker	= higherSerialPoker( currentKeyPoker, isStrictSuit );
	else
		nextKeyPoker	= lowerSerialPoker( currentKeyPoker, isStrictSuit );
	//djDebug()<<"nextKeyPoker"<<nextKeyPoker.description();
    return findGroup( countPokers, nextKeyPoker, width, isStrictSuit, isExactWidth );
}
QList<DJPoker> DJGamePokerDesktop::findShun( const QHash<DJPoker,int> countPokers,
												const DJPoker& keyPoker,
										 		int width, int length, bool isHigher,
										 		bool isStrictSuit,
										 		bool isExactWidth ) const
{
	QList<DJPoker> pokers;
	DJPoker nextKeyPoker	= keyPoker;
	while( length-- ) {
       	QList<DJPoker> nextGroup	= findGroup( countPokers, nextKeyPoker,
       											width, isStrictSuit, isExactWidth );
       	if ( nextGroup.isEmpty() )
       		return QList<DJPoker>();
       	pokers << nextGroup;
       	if ( 0 == length )
       		return pokers;
       	if ( isHigher )
			nextKeyPoker	= higherSerialPoker( nextKeyPoker, isStrictSuit );
		else
			nextKeyPoker	= lowerSerialPoker( nextKeyPoker, isStrictSuit );
		if ( !nextKeyPoker.isValid()
			|| (isHighestSerialPoker( nextKeyPoker ) && 1 != length) )
            return QList<DJPoker>();
    }
    return QList<DJPoker>();
}										 		
QList<DJPoker> DJGamePokerDesktop::iterateGroup( const QHash<DJPoker,int>& countPokers,
									int width, DJPoker& keyPoker,
									QSet<DJPoker>& excluder,
									bool isStrictSuit,
									bool isExactWidth ) const
{	
	QHash<DJPoker,int>::const_iterator it	= countPokers.constBegin();
	while( it != countPokers.constEnd() ) {
		keyPoker	= parallelPoker( it.key(), isStrictSuit );
		if ( !excluder.contains( keyPoker ) ) {
			QList<DJPoker> group	= findGroup( countPokers, keyPoker, width, isStrictSuit, isExactWidth );
			if ( !group.isEmpty() ) {
				excluder.insert( keyPoker );
				return group;
			}
		}
		++it;
	}
	return QList<DJPoker>();
}
QList<DJPoker> DJGamePokerDesktop::iterateShun( const QHash<DJPoker,int>& countPokers,
						 			int width, int length,
						 			DJPoker& keyPoker,
						 			QSet<DJPoker>& excluder,
						 			bool isStrictSuit,
						 			bool isExactWidth ) const
{
	djDebug()<<"DJGamePokerDesktop::iterateShun"<<width<<length<<isStrictSuit;
	if ( length <= 0 )
		return QList<DJPoker>();
	if ( 1 == length )
		return iterateGroup( countPokers, width, keyPoker, excluder,
							isStrictSuit, isExactWidth );
		
	QSet<DJPoker> groupExcluder;
	while( true ) {
		QList<DJPoker> firstGroup = iterateGroup( countPokers, width,
												keyPoker, groupExcluder,
												isStrictSuit, isExactWidth );
		
		if ( firstGroup.isEmpty() )
			return QList<DJPoker>();
		//djDebug()<<"firstGroup"<<firstGroup.first().description();
		//djDebug()<<"keyPoker"<<keyPoker.description();
		
		if ( !excluder.contains( keyPoker ) ) {
			//go on find the next groups of shun
			//djDebug()<<"go to find next group";
        	QList<DJPoker> shunPokers;
        	shunPokers << firstGroup;
        	
        	bool foundShun	= true;
        	int count	= length - 1;//still need count group to complete shun
        	
        	DJPoker currentKeyPoker	= keyPoker;
        	while( count > 0 ) {
        		//djDebug()<<"count"<<count;
        		DJPoker nextKeyPoker;
        		QList<DJPoker> nextGroup	= findNextGroup( countPokers, currentKeyPoker,
        										nextKeyPoker, width, true,
        										isStrictSuit, isExactWidth );
        		if ( nextGroup.isEmpty() ) {
        			djDebug()<<"no next group";
            		foundShun	= false;
            		break;
            	}
            	//djDebug()<<"nextGroup"<<nextGroup.first().description();
				//djDebug()<<"currentKeyPoker"<<currentKeyPoker.description();
				//djDebug()<<"nextKeyPoker"<<nextKeyPoker.description();
				
            	if ( isHighestSerialPoker( nextKeyPoker ) && 1 != count ) {
            		djDebug()<<"reach the highest";
            		foundShun	= false;
            		break;
            	}
            	count--;
            	currentKeyPoker = nextKeyPoker;
            	shunPokers << nextGroup;
        	}
        	if ( foundShun ) {
    			//found shun, add key poker to excluder to avoid reporting again
    			//djDebug()<<"found shun"<<keyPoker.description();
    			excluder.insert( keyPoker );
    			return shunPokers;
    		}
		}
	}
	return QList<DJPoker>();
}
/*
QList<DJPoker> DJGamePokerDesktop::iterateFlush( const QHash<DJPoker,int>& countPokers,
						 					int suit, int length,
						 					DJPoker& keyPoker,
						 					QSet<DJPoker>& excluder )
{
	QList<DJPoker> flushPokers;
	for( int point = DJPoker::Ace; point <= DJPoker::King; ++point ) {
		DJPoker poker( suit, point );
		if ( countPokers.contains( poker ) && !excluder.contains( poker ) ) {
			flushPokers << poker;
			if ( flushPokers.size() >= length ) {
				keyPoker	= greatestPoker( flushPokers );
				excluder.insert( keyPoker );
				return flushPokers;
			}
		}
	}
	return QList<DJPoker>();
}
*/				 	
//indexes should be empty before iteration
//indexed is empty means end
void DJGamePokerDesktop::iterateCombination( int total, int length, 
									QList<bool>& indexes ) const
{
	if ( indexes.isEmpty() ) {
		for (int i = 0; i < total; ++i ) {
			if ( i < length )
				indexes.append( true );
			else
				indexes.append( false );
		}
		return;
	}
	
	bool found	= false;
	int i;
	int countFalse	= 0;
	int countTrue	= 0;
	for( i = 0; i < indexes.size() - 1; ++i ) {
		if ( indexes.at(i) && !indexes.at(i+1) ) {
			//found 1 0,exchange
			indexes[i]	= false;
			indexes[i+1]	= true;
			found	= true;
			break;
		}
		if ( indexes.at(i) )
			countTrue++;
		else
			countFalse++;
	}
	if ( found ) {
		//move all 1 before found point to left
		for (int j = 0; j < qMin(countFalse,countTrue); ++j )
			indexes.swap(j,i-j-1);
	}else {
		indexes.clear();
	}
}
bool DJGamePokerDesktop::removeSubset( QList<DJPoker>& pokers, const QList<DJPoker>& subset ) const
{
	bool removed	= false;
	foreach( DJPoker poker, subset ) {
		int index	= pokers.indexOf( poker );
		if ( -1 != index ) {
			pokers.removeAt( index );
			removed	= true;
		}
	}
	return removed;
}							  
void DJGamePokerDesktop::selectPokerItems( const QList<DJPoker>& handPokers ) const
{	
	QList<DJPoker> pokers	= handPokers;
	
	Q3CanvasItemList list	= canvas()->allItems();
	foreach( Q3CanvasItem *canvasItem, list ) {
		if ( djgame_imageRTTI == canvasItem->rtti() ) {
			DJGameImageItem *imageItem	= (DJGameImageItem *)canvasItem;
			if ( DJGAME_POKERDESKTOP_TYPE_HANDCARD == imageItem->type()
				&& imageItem->sid() == GetGamePanel()->selfSeatId() ) {
				DJGamePokerItem *pokerItem = (DJGamePokerItem*)imageItem;
				pokerItem->setSelected( false );
				quint8 card	= pokerItem->tid();
				DJPoker poker( card, m_isBridgeCard );

				QList<DJPoker> subset;
				subset	<< poker;
				if ( removeSubset( pokers, subset ) )
					pokerItem->setSelected( true );
			}
		}
	}
	canvas()->update();
}
////////////////////////////////////////////////////////////////////////////
DJGamePokerItem::DJGamePokerItem( QImage img, Q3Canvas *cv,QMatrix &m,unsigned short tid,unsigned short sid,unsigned short type,bool bMovable)
					:DJGameImageItem(img,cv,m,tid,sid,type,bMovable)
{
	c_x = 0;
	c_y = 0;
	c_dx = 5;
	c_dy = 10;
	c_bSelected = false;
	
	QPen pen( Qt::green );
	pen.setWidth( 2 );
	setPen( pen );
}

DJGamePokerItem::~DJGamePokerItem()
{
}
void DJGamePokerItem::move(double x, double y)
{
	c_x = x;
	c_y = y;

	if(c_bSelected)
	{
	//	x += c_dx;
		y -= c_dy;
	}
	DJGameImageItem::move(x,y);
}
void DJGamePokerItem::setSelected(bool b)
{
	c_bSelected = b;
	setMark(c_bSelected);
	move(c_x,c_y);
}
void DJGamePokerItem::setdx(int d)
{
	c_dx = d;
}
void DJGamePokerItem::setdy(int d)
{
	c_dy = d;
}
