//****************************************************************************
//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 "DJGamePanel.h"
#include "DJGameController.h"
#include "DJClientRequest.h"
#include "DJGroupChat.h"
#include "DJGameRoom.h"
#include "DJGamePlayerItem.h"
#include "DJTreeWidget.h"
#include "DJTreeItemDelegate.h"
#include "DJGameUser.h"
#include "GameUtility.h"
#include "Utility.h"
#include "DJGameDesktop.h"
#include "DJShowView.h"
#include "DJGameUserContext.h"
#include "UIDropMsg.h"
#include "DJTextBrowser.h"
#include "LaunchUrl.h"
#include "DJWidget.h"
#include "DJCard.h"
#include "DJCardsWidget.h"
#include "DJToolButton.h"

static	QString		WWW_HOST_HELP_URL	= QString(HTTP_WWW_HOST) + "down/";

DJGamePanel::DJGamePanel( DJGameController* gameController, DJGameRoom *gameRoom, const QList<quint32>& tableUserIds, quint8 tableId, quint8 seatId, QWidget * parent, Qt::WFlags f )
	:QMainWindow( parent, f ),m_gameController(gameController),m_gameRoom(gameRoom),m_tableUserIds(tableUserIds),m_tableId(tableId),m_selfSeatId(seatId)
{
	djDebug()<<"DJGamePanel constructor";
	
	m_gameDesktop	= 0;
	m_accessorySplitter	= 0;
	m_selfShowView	= 0;
	
	m_logo	= 0;
	m_color	= 0;
	m_help	= 0;
	
#ifdef Q_WS_MAC
	setAttribute( Qt::WA_MacMetalStyle );
#endif
	setWindowIcon( gameController->gameIcon() );
	setWindowTitle( gameController->gameDisplayName() );
	QStatusBar*	statusBar	= new QStatusBar;
    statusBar->setMinimumHeight( 24 );
    setStatusBar( statusBar );
	m_chatWidget	= 0;
	m_playersTreeWidget	= 0;
	
	m_playerContextMenu	= new QMenu( this );
	
	m_actRequestPrivateView	= new QAction( tr("Request Private View"), this );
	m_actAcceptPrivateView	= new QAction( tr("Accept Private View"), this );
	m_actClosePrivateView	= new QAction( tr("Close Private View"), this );
	
	connect( gameController->mainWindow(), SIGNAL(hotKeyPressed()), SLOT(toggleShowHide()) );
	djDebug() << "m_tableUserIds = " << m_tableUserIds;
#ifdef DJ_OEM	
	m_layoutMode	= 0;
#else
	m_layoutMode	= 1;
#endif
}
DJGamePanel::~DJGamePanel()
{
	djDebug() << "DJGamePanel destructor";
}
//methods for panel
void DJGamePanel::createAccessoryWidgets()
{
	if ( !m_accessorySplitter )
		return;
	createPlayersWidget( m_accessorySplitter );
	
	if ( 0 == m_selfShowView ) {
		quint32 userId	= userIdOfSeat( selfSeatId() );
		DJGameUser	*user	= gameUser( userId );
		if ( user ) {
			DJGameUserContext	*selfContextWidget	= new DJGameUserContext( m_gameController, m_accessorySplitter );
			m_selfShowView	= selfContextWidget->showView();
			DJCardsWidget *cardsWidget	= selfContextWidget->cardsWidget();
			cardsWidget->setGamePanel(this);
			connect( m_gameController, SIGNAL(cardsReloaded()), cardsWidget, SLOT(loadCards()));
			
			connect( m_selfShowView, SIGNAL(rightClicked(quint32)), SLOT(showPlayerContextMenu(quint32)) );
			selfContextWidget->showUserContext( user );
		
			connect( user, SIGNAL(speedChanged(DJGameUser*)), selfContextWidget, SLOT(createUserInfo(DJGameUser*)) );
			connect( user, SIGNAL(moneyChanged(DJGameUser*)), selfContextWidget, SLOT(createUserInfo(DJGameUser*)) );
			connect( user, SIGNAL(magicChanged(DJGameUser*)), selfContextWidget, SLOT(createUserInfo(DJGameUser*)) );
			connect( user, SIGNAL(scoreChanged(DJGameUser*)), selfContextWidget, SLOT(createUserInfo(DJGameUser*)) );
			connect( user, SIGNAL(chipsChanged(DJGameUser*)), selfContextWidget, SLOT(createUserInfo(DJGameUser*)) );
			connect( user, SIGNAL(winsChanged(DJGameUser*)), selfContextWidget, SLOT(createUserInfo(DJGameUser*)) );
			connect( user, SIGNAL(losesChanged(DJGameUser*)), selfContextWidget, SLOT(createUserInfo(DJGameUser*)) );
			connect( user, SIGNAL(drawsChanged(DJGameUser*)), selfContextWidget, SLOT(createUserInfo(DJGameUser*)) );
			connect( user, SIGNAL(unwelcomeChanged(DJGameUser*)), selfContextWidget, SLOT(createUserInfo(DJGameUser*)) );
			
		}
	}
	
	createChatWidget( m_accessorySplitter );
}
void DJGamePanel::closeChildDialog()
{
	QObjectList list	= children();
	foreach( QObject* obj, list ){
		if ( obj->inherits("QDialog") ) {
			djDebug() << "find QDialog";
			QDialog *dlg	= qobject_cast<QDialog *>(obj);
			if ( dlg ) {
				dlg->close();
			}
		}
 	}
}
void DJGamePanel::removePendingAcl()
{
	djDebug() << "DJGamePanel::removePendingAcl";
	djDebug() << "m_acls = " << m_acls;
	if ( !m_acls.isEmpty() )
		m_gameController->removeAcl( m_acls );
}
void DJGamePanel::setGameDesktop( DJGameDesktop* gameDesktop )
{
	m_gameDesktop	= gameDesktop;
	connect( this, SIGNAL(changeBackgroundColor(const QColor&)), m_gameDesktop, SLOT(changeBackgroundColor(const QColor&)) );
	QPixmap pix( m_gameController->gameResDir() + "/image/base/background.png");
	if ( !pix.isNull() && m_color ) {
		m_color->hide();
	}
}
void DJGamePanel::setAccessorySplitter( QSplitter* splitter )
{
	m_accessorySplitter	= splitter;
}
void DJGamePanel::createPanelBar( QWidget* parent )
{
	int barHeight	= 64;
	int space	= 32;
	QSize	iconSize(48,48);
	
	DJWidget*	bar	= new DJWidget( parent );
	bar->setFixedHeight( barHeight );
	QHBoxLayout* layout	= new QHBoxLayout( bar );
	layout->setMargin( 0 );
	layout->setSpacing( space );
	layout->addSpacing( space );
	
	QList<DJPosColor>	posColors;
	DJPosColor	pc1( 0, QColor(97,148,185) );
	DJPosColor	pc2( 1, QColor(75,130,170) );
	posColors << pc1 << pc2;
	bar->setPosColors( posColors );
	
	m_logo	= new DJToolButton;
	QPixmap	pix	= QPixmap( ":/HallRes/image/bar/logo.png" );
	m_logo->setIcon( pix );
	m_logo->setIconSize( pix.size() );
	connect(m_logo, SIGNAL(clicked()), SLOT(handleLogoClicked()) );
	layout->addWidget( m_logo );
	
	layout->addStretch();
			
	m_color	= new DJToolButton;
#ifdef DJ_TOOL_BUTTON_HAS_TEXT
	m_color->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
#endif
	m_color->setText(tr("color"));
	m_color->setToolTip(tr("set background color"));
	m_color->setIcon( QIcon(":/BaseRes/image/panel/color.png") );
	m_color->setIconSize( iconSize );
	connect(m_color, SIGNAL(clicked()),SLOT(handleColorClicked()));
	layout->addWidget( m_color );
	
	m_help	= new DJToolButton;
#ifdef DJ_TOOL_BUTTON_HAS_TEXT
	m_help->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
#endif
	m_help->setText(tr("help"));
	m_help->setToolTip(tr("help of this game"));
	m_help->setIcon( QIcon(":/BaseRes/image/panel/help.png") );
	m_help->setIconSize( iconSize );
	connect(m_help, SIGNAL(clicked()),SLOT(handleHelpClicked()));
	layout->addWidget( m_help );
	
	layout->addSpacing( space );
}
void DJGamePanel::handleLogoClicked()
{
	LaunchURL( HTTP_WWW_HOST );
}
void DJGamePanel::handleColorClicked()
{
	QColor	color	= QColorDialog::getColor( QColor(75,130,170), this );
	if ( color.isValid() ) {
		emit changeBackgroundColor( color );
	}
}
void DJGamePanel::handleHelpClicked()
{
	LaunchURL( WWW_HOST_HELP_URL );
}
//*****************************methods for gamecontroller************************************
void DJGamePanel::lookerIn( quint32 userId, bool in )
{
	djDebug() << "DJGamePanel::lookerIn" << userId << in;
	if ( 0 == userId )
		return;
	if ( in ) {
		//looker in
		if ( !m_tableUserIds.contains(userId) )
			m_tableUserIds << userId;
		addPlayerItem( userId, false );
	}else {
		//looker out
		int index	= m_tableUserIds.indexOf( userId );
		if ( -1 != index ) {
			m_tableUserIds.removeAt( index );
    	}
    	removePlayerItem( userId );
	}
	if ( m_gameDesktop ) {
		m_gameDesktop->lookerIn( userId, in );
	}
}
//subclass should call baseclass userArrived
void DJGamePanel::userArrived( quint32 userId, quint8 seatId )
{
	djDebug() << "DJGamePanel::userArrived" << userId << seatId;
	if ( 0 == userId )
		return;
	setUserIdOfSeat( seatId, userId );
	addPlayerItem( userId, true );
	
	if ( m_gameDesktop ) {
		m_gameDesktop->userArrived( userId, seatId );
	}
}
void DJGamePanel::gameInfo( const QByteArray& buf )
{
	if ( m_gameDesktop ) {
		m_gameDesktop->gameInfo( reinterpret_cast<const unsigned char*>(buf.data()) );
		m_gameDesktop->ClearAutoDisappearText();
		if ( m_gameRoom->options() & DJGAME_ROOMOPTION_ANYPLAYER ) {
			m_gameDesktop->relocateAndRepaintAll();
		}
		m_gameDesktop->bonusWidget()->hide();
	}
	/*
	QString	roomDescription	= m_gameController->roomDescription(m_gameRoom);
    if ( !roomDescription.isEmpty() ) {
    	insertText2Browser( roomDescription );
	}
	*/
	repaintAllPlayerItems();
}
void DJGamePanel::gameWait( quint16 mask, quint8 status ,quint16 timeout )
{
	if ( m_gameDesktop ) {
		m_gameDesktop->gameWait( mask, status, timeout );
	}
}
void DJGamePanel::gameTrace( const GeneralGameTrace2Head *gameTrace )
{
	if ( m_gameDesktop ) {
		m_gameDesktop->gameTrace( gameTrace );
	}
}
void DJGamePanel::magicResult( const MagicResult* magicResult )
{
	if ( m_gameDesktop ) {
		m_gameDesktop->magicResult( magicResult );
	}
}
void DJGamePanel::gameOver( const DJGameOver* gameOver )
{
	if ( m_gameDesktop ) {
		m_gameDesktop->gameOver( gameOver );
	}
}
void DJGamePanel::bonusCondition( const DJGameBonus* condition )
{	
	if ( m_gameDesktop ) {
		QString bonusTarget	= m_gameDesktop->bonusTarget( condition );
		m_gameDesktop->bonusTargetWidget()->setText( tr("bonus target :") + "\n" + bonusTarget );
    	
    	quint16	bonus	= letoh2( condition->shBonus );
    	QString text	= tr("bonus :") + "\n";
    	switch( condition->chBonusType ) {
    	case DJGAME_PROTOCOL_GAMEBONUS_TYPE_CARD:
    		text	+= DJCard::name(bonus);
    		break;
    	case DJGAME_PROTOCOL_GAMEBONUS_TYPE_COUNTER:
    		text	+= QString::number( bonus );
			text	+= " ";
			text	+= gameController()->baseSectionName(DJGameController::Chips);
    		break;
    	case DJGAME_PROTOCOL_GAMEBONUS_TYPE_MONEY:
    		text	+= QString::number( bonus );
			text	+= " ";
			text	+= gameController()->baseSectionName(DJGameController::Money);
			break;
    	default:
    		text	+= tr("unknown bonus");
    		break;
    	}
    	m_gameDesktop->bonusResultWidget()->setText( text );
    	m_gameDesktop->bonusWidget()->adjustSize();
    	m_gameDesktop->bonusWidget()->move( m_gameDesktop->visibleWidth()-m_gameDesktop->bonusWidget()->width(),2);
    	m_gameDesktop->bonusWidget()->show();
	}
}
void DJGamePanel::bonusFulfilled( const DJGameBonusFulfill* fulfill )
{	
	if ( m_gameDesktop ) {
		m_gameDesktop->bonusFulfilled( fulfill );
	}
	quint32 userId	= letoh4( &fulfill->uid );
	DJGameUser *user	= gameUser( userId );
	if ( user ) {
		QString	text	= user->userName();
		text	+= " ";
		text	+= tr("obtained bonus : ");
		quint16	bonus	= letoh2( fulfill->shBonus );
		switch( fulfill->chBonusType ) {
		case DJGAME_PROTOCOL_GAMEBONUS_TYPE_CARD:
			text	+= DJCard::name(bonus);
			break;
		case DJGAME_PROTOCOL_GAMEBONUS_TYPE_COUNTER:
			text	+= QString::number( bonus );
			text	+= " ";
			text	+= gameController()->baseSectionName(DJGameController::Chips);
			break;
		case DJGAME_PROTOCOL_GAMEBONUS_TYPE_MONEY:
			text	+= QString::number( bonus );
			text	+= " ";
			text	+= gameController()->baseSectionName(DJGameController::Money);
			break;
		default:
			text	+= tr("unknown bonus");
			break;
		}
		insertText2Browser( text );
	}
}
void DJGamePanel::playWave( const QString& waveName, const QString& gameName ) const
{
	QString language	= QLocale::languageToString(QLocale::system().language());
	djDebug() << "DJGamePanel::playWave" << language;
	QString	waveDir	= QString("wav") + "/";
	QString waveLanguageDir	= waveDir + "language/" + language + "/";
	QString waveGameDir;
	if ( gameName.isEmpty() ) {
		waveGameDir	= waveDir + m_gameController->gameName() + "/";
	}else {
		waveGameDir	= waveDir + gameName + "/";
	}
	QString waveGameLanguageDir	= waveGameDir + language + "/";
	QString	wavePath;
	
	do {
		wavePath	= waveGameLanguageDir + waveName;
		if ( QFile::exists(wavePath) )
			break;
		wavePath	= waveGameDir + waveName;
		if ( QFile::exists(wavePath) )
			break;
		wavePath	= waveLanguageDir + waveName;
		if ( QFile::exists(wavePath) )
			break;
		wavePath	= waveDir + waveName;
	}while(false);
	
	m_gameController->playWave( wavePath );
}
bool DJGamePanel::sendRequest( const DJClientRequest& request, bool isDiscardable )
{
	void* acl	= (void*)request.aclProc();
	if ( acl && !m_acls.contains( acl ) ) {
		m_acls << acl;
	}
	return m_gameController->sendRequest( request, isDiscardable );
}
DJGameUser* DJGamePanel::gameUser( quint32 userId ) const
{
	return m_gameController->gameUser( userId );
}
DJGameUser* DJGamePanel::userAtSeat( quint8 seatId ) const
{
	quint32 userId	= userIdOfSeat( seatId );
	if ( 0 != userId )
		return m_gameController->gameUser( userId );
	else
		return 0;
}
QByteArray	DJGamePanel::makeGameData( quint8 subType, const QByteArray& gameData, quint8 type )
{
	return MakeGameData( m_gameController->gameId(), m_gameController->language(), subType, gameData, type );
}
bool DJGamePanel::isLookingOn() const
{
	return m_tableUserIds.at(0) != m_tableUserIds.at(m_selfSeatId);
}
bool DJGamePanel::isUserPlaying( quint32 userId ) const
{
	if ( 0 == userId )
		return false;
	for ( int seatId = 1; seatId <= numberOfSeats(); seatId++ ) {
		if ( userId == m_tableUserIds.at( seatId ) )
			return true;
	}
    return false;
}
quint8 DJGamePanel::seatIdOfUser( quint32 userId ) const
{
	for ( quint8 seat = 1; seat < m_tableUserIds.size(); ++seat ) {
		if ( userId == m_tableUserIds.at( seat ) )
			return seat;
	}
	return 0;
}
quint32	DJGamePanel::userIdOfSeat( quint8 seatId ) const
{
	if ( seatId > numberOfSeats() )
		return 0;
	else
		return m_tableUserIds.at( seatId );
}
void DJGamePanel::setUserIdOfSeat( quint8 seatId, quint32 userId )
{
	if ( seatId && seatId <= numberOfSeats() )
		m_tableUserIds[seatId]	= userId;
}
//NOTE:only reset the players in m_tableuserids[1-numberofseats]
//don't touch the lookers who live at numberofseats+1 and later
void DJGamePanel::resetPlayers( const QList<quint32> newUserIds )
{
	//remove player who is not in newUserIds
	for ( int seatId = 1; seatId <= numberOfSeats(); ++seatId ) {
		quint32 userId	= m_tableUserIds.at( seatId );
		if ( !newUserIds.contains( userId ) ) {
			removePlayerItem( userId );
			DJGameUser *user	= gameUser( userId );
			if ( user ) {
				insertText2Browser(tr("%1 quit game").arg(user->userName()));
			}
		}
	}
	//add player who is not in m_tableUserIds
	for ( int seatId = 1; seatId <= numberOfSeats(); ++seatId ) {
		quint32 userId	= newUserIds.at( seatId );
		if ( !m_tableUserIds.contains( userId ) ) {
			addPlayerItem( userId, true );
			DJGameUser *user	= gameUser( userId );
			if ( user ) {
				insertText2Browser(tr("%1 will join game on next start").arg(user->userName()));
			}
		}
	}
	for ( quint8 seatId = 1; seatId <= numberOfSeats(); ++seatId ) {
		m_tableUserIds[seatId]	= newUserIds.at(seatId);
	}
}
quint8 DJGamePanel::numberOfSeats() const
{ 
	return m_gameRoom->numberOfSeats();
}
//**********************methods for chat widget******************************
DJGroupChat* DJGamePanel::createChatWidget( QWidget* parent )
{
	if ( 0 == m_chatWidget ) {
    	m_chatWidget	= new DJGroupChat( m_gameController, MakeGroupId( m_gameController->gameId(),m_gameRoom->roomId(),m_tableId), DJGroupChat::GamePanel, parent );
    	connect( m_chatWidget->textBrowser(), SIGNAL(acceptPrivateView(quint32)), SLOT(acceptPrivateView(quint32)));
    }
	return m_chatWidget;
}
void DJGamePanel::receiveChat( const ChatContent *chatContent )
{
	quint32	speakerId	= letoh4( &chatContent->userid_speaker );
	if ( m_chatWidget )
		m_chatWidget->receiveChat( chatContent );
	if ( speakerId >= MIN_USER_ID && !isUserPlaying( speakerId ) ) {
		lookerIn( speakerId, true );
	}
}
void DJGamePanel::insertText2Editor( const QString& text )
{
	if ( m_chatWidget && !text.isEmpty() )
		m_chatWidget->insertText2Editor( text );
}
void DJGamePanel::insertText2Browser( const QString& text )
{
	if ( m_chatWidget && !text.isEmpty() ) {
		m_chatWidget->insertText2Browser( text );
	}
}
void DJGamePanel::insertGameResult2Browser( const QString& text )
{
	if ( m_chatWidget && !text.isEmpty() ) {
		QString tableText;
		tableText	+= "<table border>";
		if ( m_gameRoom->options() & DJGAME_ROOMOPTION_COUNTER )
			tableText	+= QString("<tr><th>%1<th>%2")
						.arg(baseSectionName(UserName))
						.arg(baseSectionName(PanelChips));
		else
			tableText	+= QString("<tr><th>%1<th>%2")
						.arg(baseSectionName(UserName))
						.arg(baseSectionName(PanelScore));
		tableText	+= text;
		tableText	+= "</table>";
		m_chatWidget->insertText2Browser( tr("game result:") );
		m_chatWidget->insertText2Browser( tableText );
	}
}
void DJGamePanel::deltaUserData( DJGameUser *user, int value )
{
	djDebug()<<"DJGamePanel::deltaUserData";
	if ( 0 == user )
		return;
	djDebug()<<user->userName()<<value;
	DJGamePlayerItem *item	= playerItem( user->userId() );
	if ( gameRoom()->options() & DJGAME_ROOMOPTION_COUNTER  ) { 
     	user->deltaChips( value );
     	if ( item ) {
     		item->deltaPanelChips( value );
     	}
	}else {
		user->deltaScore( value );
		if ( value > 0 )
    		user->increaseWins();
    	else if ( value < 0 ) 
    		user->increaseLoses();
   	 	else
    		user->increaseDraws();
    	if ( item ) {
     		item->deltaPanelScore( value );
     	}	
    }
}
//***************************methods for players tree widget************************
DJTreeWidget* DJGamePanel::createPlayersWidget( QWidget* parent )
{
	if ( 0 == m_playersTreeWidget ) {
    	m_playersTreeWidget	= new DJTreeWidget( parent );
    	
    	createPlayerItemHeader( m_playersTreeWidget );
    	//m_playersTreeWidget->setHeaderItem( headerOfPlayerItem() );
    	m_playersTreeWidget->setRootIsDecorated(false);
    	//m_playersTreeWidget->header()->setClickable(false);
    	m_playersTreeWidget->setSortingEnabled( true );
    	
    	m_playersTreeWidget->setItemDelegate(new DJTreeItemDelegate(selfUserId(),this));
    	//m_playersTreeWidget->setMinimumWidth(150);
    	//m_playersTreeWidget->setMaximumWidth(300);
		//m_playersTreeWidget->setMinimumHeight(200);
	
    	m_playersTreeWidget->setContextMenuPolicy( Qt::CustomContextMenu );
    	connect(m_playersTreeWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem *,int)), SLOT(playerItemDoubleClicked(QTreeWidgetItem *,int)));
    	connect(m_playersTreeWidget, SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(playerItemRightClicked(const QPoint&)));
    	
    	repaintAllPlayerItems();
    }
	return m_playersTreeWidget;
}
QString	DJGamePanel::playerItemNameSuffix( DJGameUser* user )
{
	if ( m_gameDesktop )
		return m_gameDesktop->playerItemNameSuffix( user );
	else
		return QString();
}
void DJGamePanel::repaintAllPlayerItems()
{
	for ( int seat = 1; seat <= numberOfSeats(); ++seat ) {
		quint32 userId	= userIdOfSeat( seat );
		if ( 0 != userId )
			addPlayerItem( userId, true );
	}
}
DJGamePlayerItem* DJGamePanel::addPlayerItem( quint32 userId, bool isPlayer )
{
	djDebug() << "DJGamePanel::addPlayerItem" << userId <<isPlayer;
	DJGameUser*	user	= gameUser( userId );
	if ( !user ) {
		djDebug()<<"user does not exists";
		return 0;
	}
	DJGamePlayerItem* item	= playerItem( userId );
	if ( 0 == item ) {
		item	= createPlayerItem( user, m_playersTreeWidget );
		item->setPanelScore( 0 );
		item->setScore();
		item->setPanelChips( 0 );
		item->setChips();
	}
	if ( isPlayer ) {
		QString suffix	= playerItemNameSuffix( user );
		item->setName( user->userName() + suffix );
		item->setNickName( user->nickName() );
		item->setSeat( user->seatId() );
	}else {
		item->setName( user->userName() + tr("(looker)") );
		item->setNickName( user->nickName() );
		item->setSeat( 0 );
	}
	return item;
}
void DJGamePanel::createPlayerItemHeader( QTreeWidget* treeWidget )
{
	playerItemHeaderSections( m_sectionIds, m_sectionNames );
	
	QTreeWidgetItem* headerItem	= new QTreeWidgetItem;
    for ( int i = 0; i < m_sectionNames.size(); i++) {
    	headerItem->setTextAlignment( i, Qt::AlignCenter );
    	headerItem->setText( i, m_sectionNames.at(i) );
    }
	treeWidget->setHeaderItem( headerItem );
}
void DJGamePanel::playerItemHeaderSections( QList<int> &sectionIds, QStringList &sectionNames )
{
	sectionIds.clear();
	sectionNames.clear();
	
	sectionIds << UserName << NickName;
	if ( m_gameRoom->options() & DJGAME_ROOMOPTION_COUNTER )
		sectionIds << PanelChips << Chips;
	else
		sectionIds << PanelScore << Score;
	sectionIds << Seat;
	for ( int i = 0; i < sectionIds.size(); ++i ) {
		sectionNames << baseSectionName( sectionIds.at(i) );
	}
	sectionNames << "-";
}
int DJGamePanel::indexOfSection( int sectionId ) const
{
	return m_sectionIds.indexOf( sectionId );
}
QString DJGamePanel::sectionName( int sectionId ) const
{
	QString name;
	int index	 = indexOfSection( sectionId );
	if ( -1 != index )
		name	= m_sectionNames.at( index );
	return name;
}
QString	DJGamePanel::baseSectionName( int sectionId )
{
	static const char *sections[] = {
       	QT_TR_NOOP("username"),
       	QT_TR_NOOP("nickname"),
        QT_TR_NOOP("seat"),
        QT_TR_NOOP("panel score"),
        QT_TR_NOOP("score"),
        QT_TR_NOOP("panel chips"),
        QT_TR_NOOP("chips"),
        QT_TR_NOOP("doorwind"),
        QT_TR_NOOP("ringwind")
	};
	if ( sectionId < LastSectionId )
		return tr(sections[sectionId]);
	else
		return tr("error");
}
DJGamePlayerItem* DJGamePanel::createPlayerItem( DJGameUser *user, QTreeWidget* parent, int type )
{
	if ( user->userId() == selfUserId() )
		type	= QTreeWidgetItem::UserType;
	DJGamePlayerItem *item	= new DJGamePlayerItem( user, this, parent, type );
	connect( user, SIGNAL(chipsChanged(DJGameUser*)), item, SLOT(setChips()) );
	connect( user, SIGNAL(scoreChanged(DJGameUser*)), item, SLOT(setScore()) );
	return item;
}
DJGamePlayerItem* DJGamePanel::playerItem( quint32 userId )
{
	if ( 0 != m_playersTreeWidget && 0 != userId ) {
    	for ( int i = 0; i < m_playersTreeWidget->topLevelItemCount(); i++ ) {
    		DJGamePlayerItem *playerItem	= static_cast<DJGamePlayerItem *>(m_playersTreeWidget->topLevelItem(i));
    		if ( playerItem && userId == playerItem->user()->userId() ) {
    			return playerItem;
    		}
    	}
	}
	return 0;
}
void DJGamePanel::removePlayerItem( quint32 userId )
{
	DJGamePlayerItem* item	= playerItem( userId );
	if ( item )
		delete item;
}
//slots
void DJGamePanel::showPlayerContextMenu( quint32 userId )
{
	djDebug() << "showPlayerContextMenu" << userId;

	bool isPlayer	= isUserPlaying( userId );
	m_playerContextMenu->clear();
	
	if ( isLookingOn() ) {
		if ( isPlayer ) {
			if ( m_gameRoom->options() & DJGAME_ROOMOPTION_PRIVATE_VIEW ) {
				m_playerContextMenu->addAction( m_actRequestPrivateView );
			}
		}
	}else {
		if ( !isPlayer ) {
			if ( m_gameRoom->options() & DJGAME_ROOMOPTION_PRIVATE_VIEW ) {			
				m_playerContextMenu->addAction( m_actAcceptPrivateView );
				m_playerContextMenu->addAction( m_actClosePrivateView );
			}
		}
	}
	
	QAction *action	= m_playerContextMenu->exec( QCursor::pos() );
	if ( action ) {
		if ( m_actRequestPrivateView == action ) {
			requestPrivateView( userId );
		}else if ( m_actAcceptPrivateView == action ) {
			acceptPrivateView( userId );
		}else if ( m_actClosePrivateView == action ) {
			closePrivateView( userId );
		}
	}
}
void DJGamePanel::playerItemDoubleClicked( QTreeWidgetItem * item, int column )
{
	DJGamePlayerItem *playerItem	= static_cast<DJGamePlayerItem *>(item);
	if ( playerItem ) {
		insertText2Editor( playerItem->user()->userName() + "," );
	}
}
void DJGamePanel::playerItemRightClicked( const QPoint &point )
{
	if ( 0 == m_playersTreeWidget )
		return;
	DJGamePlayerItem *playerItem	= static_cast<DJGamePlayerItem *>(m_playersTreeWidget->itemAt( point ));
	if ( playerItem ) {
		showPlayerContextMenu( playerItem->user()->userId() );
	}
}
//slots for menu action
void DJGamePanel::requestPrivateView( quint32 hostId )
{
	//self is looker
	QByteArray	lookerIdStream	= htoa4( selfUserId(), QDataStream::LittleEndian );
	QByteArray	hostIdStream	= htoa4( hostId, QDataStream::LittleEndian );
	
	QByteArray	gameData;
	
	gameData.append( lookerIdStream );
	gameData.append( hostIdStream );
	gameData.append( tableId() );
	gameData.append( seatIdOfUser( hostId ) );
	
	QByteArray buf	= makeGameData( DJGAME_PROTOCOL_SUBTYPE_REQUEST_PRIVATE_VIEW, gameData );
	DJClientRequest request( buf );
	
	sendRequest( request );
}
void DJGamePanel::acceptPrivateView( quint32 lookerId )
{
	//self is host
	QByteArray	lookerIdStream	= htoa4( lookerId, QDataStream::LittleEndian );
	QByteArray	hostIdStream	= htoa4( selfUserId(), QDataStream::LittleEndian );
	
	QByteArray	gameData;
	
	gameData.append( lookerIdStream );
	gameData.append( hostIdStream );
	gameData.append( tableId() );
	gameData.append( selfSeatId() );
	
	QByteArray buf	= makeGameData( DJGAME_PROTOCOL_SUBTYPE_AGREE_PRIVATE_VIEW, gameData );
	DJClientRequest request( buf );
	
	sendRequest( request );
}
void DJGamePanel::closePrivateView( quint32 lookerId )
{
	//self is host
	QByteArray	lookerIdStream	= htoa4( lookerId, QDataStream::LittleEndian );
	QByteArray	hostIdStream	= htoa4( selfUserId(), QDataStream::LittleEndian );
	
	QByteArray	gameData;
	
	gameData.append( lookerIdStream );
	gameData.append( hostIdStream );
	gameData.append( tableId() );
	gameData.append( selfSeatId() );
	
	QByteArray buf	= makeGameData( DJGAME_PROTOCOL_SUBTYPE_CLOSE_PRIVATE_VIEW, gameData );
	DJClientRequest request( buf );
	
	sendRequest( request );
}
void DJGamePanel::toggleShowHide()
{
	djDebug()<<"toggleShowHide";
	if ( isHidden() )
		show();
	else
		hide();
}
void DJGamePanel::cardUsed( const ReqUseCard *useCard )
{	
	djDebug()<<"DJGamePanel::cardUsed";
	
	quint32 hostId	= letoh4( &useCard->hostid );
	quint32 targetId	= letoh4( &useCard->targetid );
	quint8 cardId	= useCard->chCard;
	qint32 parameter	= letoh4( useCard->iParam );
	
	DJGameUser *host	= gameUser( hostId );
	DJGameUser *target	= gameUser( targetId );
	DJCard *card	= gameController()->card(cardId);
	if ( host && target && card ) {
		if ( hostId == targetId )
			insertText2Browser( tr("%1 used %2").arg(host->userName())
													.arg(DJCard::name(cardId)) );
		else
			insertText2Browser( tr("%1 used %2 to %3").arg(host->userName())
													.arg(DJCard::name(cardId))
													.arg(target->userName()) );
	}
	QString movie;
	if ( DJGAME_GAMECARD_BROADCAST == cardId ) {
		if ( hostId == selfUserId() ) {
			m_gameController->dropMsgWidget()->show();
		}
	}else if ( DJGAME_GAMECARD_EMOTION == cardId ) {
		movie	= DJCard::emotionMovieName(parameter);
	}else {
		movie	= DJCard::movieName(cardId);
	}
	if ( movie.isEmpty() )
		return;
	djDebug()<<"movie"<<movie;
	quint8 seatId	= seatIdOfUser( targetId );
   	if ( 0 != seatId && m_gameDesktop ) {
   		DJShowView	*show	= m_gameDesktop->showView( seatId );
   		show->addEffect( movie );
   	}
   	if ( seatId == selfSeatId() && m_selfShowView ) {
    	m_selfShowView->addEffect( movie );
    }	
}
void DJGamePanel::closeEvent( QCloseEvent *e )
{
	if ( isLookingOn() ) {
		//look on
		QByteArray data;
		data.append( tableId() );
		QByteArray buf	= makeGameData( DJGAME_PROTOCOL_SUBTYPE_QUITVIEW, data );
		DJClientRequest request( buf );
		sendRequest( request );
		e->accept();
		return;
	}
    if( m_gameDesktop && m_gameDesktop->isCloseable() )
    {
    	QByteArray buf	= makeGameData( DJGAME_PROTOCOL_SUBTYPE_QUIT, QByteArray() );
		DJClientRequest request( buf );
		sendRequest( request );
		e->accept();
    }else {
    	e->ignore();
    }
}
