//****************************************************************************
//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 "DJShowView.h"
#include "DJRemoteToLocalFile.h"
#include "DJMatrixCanvasImage.h"
#include "DJMatrixCanvasSprite.h"
#include "DJGameUser.h"
#include "DJMatrixCanvasText.h"

static	uint	KEEP_XML_MAX_SHOWID	= 255;
static	int		SHOW_WIDTH			= 72;
static 	int		SHOW_HEIGHT			= 122;

DJShowItem::DJShowItem( DJShowView *showView, const QString& name, DJGameUser *user, double x, double y, double z, bool isAnimated, const QMatrix& innerMatrix )
	:m_showView(showView),m_name(name),m_x(x),m_y(y),m_z(z),m_isAnimated(isAnimated),m_innerMatrix(innerMatrix)
{
	djDebug() << "DJShowItem constructor" << name << x << y << z << isAnimated<<innerMatrix;
	
	if ( m_name.isEmpty() ) {
		quint8 gender	= 0;
		if ( user )
			gender	= user->gender();
		if ( DJGAME_GENDER_MALE == gender ) {
			m_localImagePath	= ":/BaseRes/image/hall/ShowMale.gif";
		}else if ( DJGAME_GENDER_FEMALE == gender ) {
			m_localImagePath	= ":/BaseRes/image/hall/ShowFemale.gif";
		}else {
			m_localImagePath	= ":/BaseRes/image/hall/ShowSecret.gif";
		}
	}else {
		m_localImagePath	= QString("images/avatars/") + m_name;
	}
	m_item	= 0;
	
	createItem();
	
	m_hasStartedTimer	= false;
	m_lifeTime	= 0;
}
DJShowItem::~DJShowItem()
{
	djDebug() << "DJShowItem destructor";
	if ( m_isAnimated ) {
		delete reinterpret_cast<DJMatrixCanvasSprite*>(m_item);
	}else {
		delete reinterpret_cast<DJMatrixCanvasImage*>(m_item);
	}
	m_item	= 0;
}
void DJShowItem::description()
{
	djDebug() << "m_name=" << m_name << "x=" << m_x << "y=" << m_y << "z=" << m_z << "animated=" << m_isAnimated;
}
void DJShowItem::createItem()
{
	djDebug() << "DJShowItem::createItem" << m_localImagePath;
	if ( !QFile::exists(m_localImagePath) ) {
		djDebug() << "file is not exists";
		QUrl	url( HTTP_WWW_HOST + m_localImagePath );
		DJRemoteToLocalFile	*r2lItem	= new DJRemoteToLocalFile( url, m_localImagePath, this );
    	connect( r2lItem, SIGNAL(localFileDone(const QString&)), SLOT(showImageDone()) );
		return;
	}
	if ( 0 != m_item )
		return;
	
	//clear dx , dy 
	if ( m_isAnimated ) {
		//create animated item
		djDebug() << "create animated item";
		DJMatrixCanvasSprite *item	= new DJMatrixCanvasSprite( m_showView->canvas(), m_localImagePath );
		item->setExternalMatrix( m_showView->scaleMatrix() );
		item->setInnerMatrix( m_innerMatrix );
		item->matrimove( m_x, m_y );
		item->setZ( m_z );
		item->hide();
		m_item	= (void*)item;
	}else {
		//create static item
		djDebug() << "create static item";
		DJMatrixCanvasImage	*item	= new DJMatrixCanvasImage( m_showView->canvas(), QPixmap(m_localImagePath) );
		item->setExternalMatrix( m_showView->scaleMatrix() );
		item->setInnerMatrix( m_innerMatrix );
		item->matrimove( m_x, m_y );
		item->setZ( m_z );
		item->hide();
		m_item	= (void*)item;
	}
}
void DJShowItem::show()
{
	if ( 0 == m_item )
		return;
	if ( m_isAnimated ) {
		reinterpret_cast<DJMatrixCanvasSprite*>(m_item)->show();
	}else {
		reinterpret_cast<DJMatrixCanvasImage*>(m_item)->show();
	}
}
void DJShowItem::hide()
{
	if ( 0 == m_item )
		return;
	if ( m_isAnimated ) {
		reinterpret_cast<DJMatrixCanvasSprite*>(m_item)->hide();
	}else {
		reinterpret_cast<DJMatrixCanvasImage*>(m_item)->hide();
	}
}
bool DJShowItem::isReady() const
{
	return 0 != m_item;
}
void DJShowItem::setLifeTime( int second )
{
	if ( !m_hasStartedTimer ) {
		m_hasStartedTimer	= true;
		startTimer( 1000 );
	}
	m_lifeTime	= second;
}
void DJShowItem::setAlignment( Qt::AlignmentFlag flag )
{
	if ( 0 == m_item )
		return;
	if ( m_isAnimated ) {
		reinterpret_cast<DJMatrixCanvasSprite*>(m_item)->setAlignment( flag );
	}else {
		reinterpret_cast<DJMatrixCanvasImage*>(m_item)->setAlignment( flag );
	}
}
/*
void DJShowItem::canvasResized( const QSize& realSize, const QSize& newSize )
{
	if ( 0 == m_item )
		return;
	if ( m_isAnimated ) {
		reinterpret_cast<DJMatrixCanvasSprite*>(m_item)->canvasResized( realSize, newSize );
	}else {
		reinterpret_cast<DJMatrixCanvasImage*>(m_item)->canvasResized( realSize, newSize );
	}
}
*/
void DJShowItem::setInnerMatrix( const QMatrix& matrix )
{
	if ( 0 == m_item )
		return;
	if ( m_isAnimated ) {
		reinterpret_cast<DJMatrixCanvasSprite*>(m_item)->setInnerMatrix( matrix );
	}else {
		reinterpret_cast<DJMatrixCanvasImage*>(m_item)->setInnerMatrix( matrix );
	}
}
void DJShowItem::setExternalMatrix( const QMatrix& matrix )
{
	if ( 0 == m_item )
		return;
	if ( m_isAnimated ) {
		reinterpret_cast<DJMatrixCanvasSprite*>(m_item)->setExternalMatrix( matrix );
	}else {
		reinterpret_cast<DJMatrixCanvasImage*>(m_item)->setExternalMatrix( matrix );
	}
}
void DJShowItem::timerEvent( QTimerEvent * event )
{
	if ( m_lifeTime > 0 ) {
		m_lifeTime--;
		if ( 0 == m_lifeTime ) {
			hide();
		}
	}
}
void DJShowItem::showImageDone()
{
	createItem();
	emit itemIsReady();
}
///////////////////////////////////////////////////////////////////////////////////////
DJShowView::DJShowView( DJGameUser* user, QWidget* parent )
	:Q3CanvasView(parent),m_user(user)
{	
	setRealSize( SHOW_WIDTH,SHOW_HEIGHT );
	m_alignment	= 0;
	m_x	= 0;
	m_y	= 0;
	
	Q3Canvas* canvas	= new Q3Canvas( this );
	canvas->setAdvancePeriod ( 200 );
	setCanvas( canvas );
	
	setHScrollBarMode(Q3ScrollView::AlwaysOff);
	setVScrollBarMode(Q3ScrollView::AlwaysOff);
	
	resize( SHOW_WIDTH,SHOW_HEIGHT );
	//m_resizeTimer	= new QTimer( this );
	//m_resizeTimer->setInterval( 500 );
	//m_resizeTimer->setSingleShot( true );
	//connect( m_resizeTimer, SIGNAL(timeout()), SLOT(handleShowResized()) );
	
	setUser( user );
}

DJShowView::~DJShowView()
{
	//all items on canvas should have been deleted
	djDebug() << "DJShowView destructor" << canvas()->allItems().size();
	clearAllItems();
}
void DJShowView::setUser( DJGameUser* user )
{
	djDebug()<<"DJShowView::setUser"<<user;
	m_user	= user;
	quint32 showId	= 0;
	if ( user )
		showId	= user->showId();
	clearAllItems();
	
	createDefaultItems();
	showDefaultShow();
	
	if ( 0 != showId ) {
		QString path	= "xml/show/1%1.xml";
		if ( user && DJGAME_GENDER_FEMALE == user->gender() )
			path	= "xml/show/2%1.xml";
			
    	QString	xmlPath	= path.arg( showId, 8, 16, QChar('0') );
    	QFile	file( xmlPath );
    	if ( file.exists() ) {
    		createCustomItems( xmlPath );
    	}else {
        	QUrl	remoteUrl( HTTP_WWW_HOST + xmlPath );
        	if ( showId > KEEP_XML_MAX_SHOWID ) {
#ifdef DJ_OEM
				return;
#else        		
        		xmlPath.clear();
#endif        		
        	}
        	if ( m_showXmls.contains( showId ) ) {
        		xmlPath	= m_showXmls.value( showId );
        		createCustomItems( xmlPath );
        	}else {
        		DJRemoteToLocalFile	*r2lShowXml	= new DJRemoteToLocalFile( remoteUrl, xmlPath, this );
        		connect( r2lShowXml, SIGNAL(localFileDone(const QString&)), SLOT(showXmlDone(const QString&)) );
        	}
    	}
	}
}
QSize DJShowView::sizeHint() const
{
	djDebug() << "sizehint" << m_realSize;
	return m_realSize;
}
void DJShowView::setAlignment( Qt::Alignment flag )
{
	if ( m_alignment != flag ) {
		m_alignment	= flag;
		//adjust the current position
    	matrimove( m_x, m_y );
	}
}
void DJShowView::matrimove( const QPoint& point )
{
	matrimove( point.x(), point.y() );
}
void DJShowView::matrimove( int x, int y )
{
	m_x	= x;
	m_y	= y;
	
	//transformed coordinate
	int tx	= x;
	int ty	= y;
	
	if ( !m_externalMatrix.isIdentity() ) {
		m_externalMatrix.map( x, y, &tx, &ty );
	}
	
	move( tx, ty );
}
void DJShowView::move( const QPoint& point )
{
	move( point.x(), point.y() );
}
void DJShowView::move( int x, int y )
{
	if( m_alignment & Qt::AlignRight )
		x -= width();
	else if( m_alignment & Qt::AlignHCenter )
		x -= width() >> 1;
	if( m_alignment & Qt::AlignBottom )
		y -= height();
	else if( m_alignment & Qt::AlignVCenter )
		y -= height() >> 1;
		
	Q3CanvasView::move( x, y );
}
void DJShowView::setRealSize( const QSize& size )
{
	m_realSize	= size;
}
void DJShowView::setRealSize( int width, int height )
{
	m_realSize.setWidth( width );
	m_realSize.setHeight( height );
}
QMatrix DJShowView::scaleMatrix() const
{
	return QMatrix(m_externalMatrix.m11(),0,0,m_externalMatrix.m22(),0,0);
}
void DJShowView::setExternalMatrix( const QMatrix& matrix )
{
	m_externalMatrix	= matrix;
	
	resize( static_cast<int>(m_realSize.width() * matrix.m11()),
			static_cast<int>( m_realSize.height() * matrix.m22()) );
	
	QMatrix sMatrix	= scaleMatrix();
	
	foreach( DJShowItem *item, m_defaultItems ) {
		item->setExternalMatrix( sMatrix );
	}
	foreach( DJShowItem *item, m_customItems ) {
		item->setExternalMatrix( sMatrix );
	}
	foreach( DJShowItem *item, m_effectItems ) {
		item->setExternalMatrix( sMatrix );
	}
	//adjust the current position
	matrimove( m_x, m_y );
}
void DJShowView::clearAllItems()
{
	djDebug() << "DJShowView::clearAllItems";
	djDebug() << "m_defaultItems.size()" << m_defaultItems.size();
	qDeleteAll( m_defaultItems );
	m_defaultItems.clear();
	djDebug() << "m_customItems.size()" << m_customItems.size();
	qDeleteAll( m_customItems );
	m_customItems.clear();
	djDebug() << "m_effectItems.size()" << m_effectItems.size();
	qDeleteAll( m_effectItems );
	m_effectItems.clear();
}
void DJShowView::createDefaultItems()
{
	djDebug() << "DJShowView::createDefaultItems";
	qDeleteAll( m_defaultItems );
	m_defaultItems.clear();
	
	DJShowItem	*item	= new DJShowItem( this, QString(), m_user, 0, 0, 100, false );
	m_defaultItems << item;
}
void DJShowView::showDefaultShow()
{
	foreach( DJShowItem *item, m_defaultItems ) {
		item->show();
	}
}
void DJShowView::hideDefaultShow()
{
	foreach( DJShowItem *item, m_defaultItems ) {
		item->hide();
	}
}
void DJShowView::createCustomItems( const QString& xmlPath )
{
	djDebug() << "DJShowView::createCustomItems";
	
	qDeleteAll( m_customItems );
	m_customItems.clear();
	
	QFile file( xmlPath );
	QDomDocument	domDocument;
	domDocument.setContent( &file, true );
	QDomElement domRoot = domDocument.documentElement();
	if ( domRoot.tagName() != "djshow" )
		return;
	/*	
	QDomElement domSize = domRoot.firstChildElement("size");
	int width	= SHOW_WIDTH;
	int height	= SHOW_HEIGHT;
	if ( !domSize.isNull() ) {
		width	= domSize.firstChildElement("width").text().toInt();
		height	= domSize.firstChildElement("height").text().toInt();
	}
	djDebug() << "resize canvas";
	canvas()->resize(width,height);
	*/
	QDomElement domItems = domRoot.firstChildElement("items");
	if ( domItems.isNull() )
		return;
	QDomElement domItem = domItems.firstChildElement();
	while( !domItem.isNull() ) {
		djDebug() << "domItem" << domItem.tagName();
		QString name	= domItem.firstChildElement("filename").text();
		double	wscale	= domItem.firstChildElement("wscale").text().toDouble();
		double	hscale	= domItem.firstChildElement("hscale").text().toDouble();
		double	x	= domItem.firstChildElement("x").text().toDouble();
		double	y	= domItem.firstChildElement("y").text().toDouble();
		double	z	= domItem.firstChildElement("z").text().toDouble();
		bool	isAnimated	= domItem.firstChildElement("animated").text().toUInt();
		if ( !name.isEmpty() ) {
			QMatrix m;
			if ( 0 != wscale && 0 != hscale ) {				
				m.setMatrix( wscale,0,0,hscale,0,0);
			}
			DJShowItem	*item	= new DJShowItem( this, name, m_user, x, y, z, isAnimated, m);
			connect( item, SIGNAL(itemIsReady()), SLOT(customItemIsReady()) );
			m_customItems << item;
		}
		domItem	= domItem.nextSiblingElement();
	}
	
	//foreach( DJShowItem *item, m_customItems ) {
		//item->description();
	//}
	customItemIsReady();
}
void DJShowView::showCustomShow()
{	
	foreach( DJShowItem *item, m_customItems ) {
		item->show();
	}
}
void DJShowView::hideCustomShow()
{
	foreach( DJShowItem *item, m_customItems ) {
		item->hide();
	}
} 
bool DJShowView::isAllCustomItemsReady()
{
	bool	isReady	= true;
	foreach( DJShowItem *item, m_customItems ) {
		if ( !item->isReady() ) {
			isReady	= false;
		}
	}
	return isReady;
}
void DJShowView::addEffect( const QString& name, int second )
{
	djDebug() << "DJShowView::addEffect" << name;
	if ( name.isEmpty() )
		return;
	DJShowItem*	item;
	if ( m_effectItems.contains( name ) ) {
		item	= m_effectItems.value( name );
	}else {
		item	= new DJShowItem( this, name, m_user, 0, 0, 1000, true );
		m_effectItems.insert( name, item );
	}
	item->setLifeTime( second );
	item->show();
}
void DJShowView::resizeEvent( QResizeEvent * event )
{
	djDebug() << "DJShowView::resizeEvent";
	Q3CanvasView::resizeEvent( event );
	//NOTE: canvas size should be visible width height not width height	
	canvas()->resize( visibleWidth(), visibleHeight() );
	//m_resizeTimer->start();
}
void DJShowView::contentsMouseReleaseEvent( QMouseEvent * e )
{
	djDebug() << "DJShowView::contentsMouseReleaseEvent";
	Q3CanvasView::contentsMouseReleaseEvent(e);
		
	if ( Qt::RightButton == e->button() ) {
		quint32 userId	= 0;
		if ( m_user ) {
			userId	= m_user->userId();
		}
		emit rightClicked( userId );
	}
}
/*
void DJShowView::contextMenuEvent ( QContextMenuEvent * e )
{
	djDebug() << "DJShowView::contextMenuEvent";
	
	m_effectMenu->exec( e->globalPos() );
}
*/
void DJShowView::showXmlDone( const QString& filePath )
{
	if ( m_user && m_user->showId() ) {
		m_showXmls.insert( m_user->showId(), filePath );
	}
	createCustomItems( filePath );
}
void DJShowView::customItemIsReady()
{
	if ( isAllCustomItemsReady() ) {
		hideDefaultShow();
		showCustomShow();
	}
}

/*
void DJShowView::handleShowResized()
{
	djDebug() << "DJShowView::handleShowResized";
	
	foreach( DJShowItem *item, m_defaultItems ) {
		item->canvasResized( m_realSize, size() );
	}
	foreach( DJShowItem *item, m_customItems ) {
		item->canvasResized( m_realSize, size() );
	}
	foreach( DJShowItem *item, m_effectItems ) {
		item->canvasResized( m_realSize, size() );
	}
}
*/
