/*
 *  Copyright (C) 2003 by Unai Garro <ugarro@users.sourceforge.net>
 *  Copyright (C) 2004 by Enrico Ros <rosenric@dei.unipd.it>
 *  Copyright (C) 2004 by Stephan Kulow <coolo@kde.org>
 *  Copyright (C) 2004 by Oswald Buddenhagen <ossi@kde.org>
 *
 *  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; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "kdmthemer.h"
#include "kdmitem.h"
#include "kdmpixmap.h"
#include "kdmrect.h"
#include "kdmlist.h"
#include "kdmlabel.h"
#include "kdmbutton.h"

#include <kdm_greet.h> // debug stuff
#include <kfdialog.h> // kfmsgbox

#include <klocale.h>
#include <kconfig.h>
#include <kconfiggroup.h>

#include <QEvent>
#include <QMouseEvent>
#include <QPaintEvent>
#include <QFile>
#include <QFileInfo>
#include <QPainter>

#include <unistd.h>

/*
 * KdmThemer. The main theming interface
 */
KdmThemer::KdmThemer( const QString &_filename,
                      const QMap<QString, bool> &showTypes, QWidget *w )
	: QObject()
	, m_showTypes( showTypes )
	, rootItem( 0 )
	, m_geometryOutdated( true )
	, m_geometryInvalid( true )
	, m_widget( 0 )
{
	// read the XML file and create DOM tree
	QString filename = _filename;
	if (!::access( QFile::encodeName( filename + "/KdmGreeterTheme.desktop" ), R_OK )) {
		KConfig _cfg( filename + "/KdmGreeterTheme.desktop", KConfig::SimpleConfig );
		KConfigGroup cfg( &_cfg, "KdmGreeterTheme" );
		filename += '/' + cfg.readEntry( "Greeter" );
	}
	QFile opmlFile( filename );
	if (!opmlFile.open( QIODevice::ReadOnly )) {
		KFMsgBox::box( w, errorbox, i18n( "Cannot open theme file %1" , filename) );
		return;
	}
	QDomDocument domTree;
	if (!domTree.setContent( &opmlFile )) {
		KFMsgBox::box( w, errorbox, i18n( "Cannot parse theme file %1" , filename) );
		return;
	}
	// generate all the items defined in the theme
	const QDomElement &theme = domTree.documentElement();
	// Get its tag, and check it's correct ("greeter")
	if (theme.tagName() != "greeter") {
		KFMsgBox::box( w, errorbox, i18n( "%1 does not seem to be a correct theme file" , filename) );
		return;
	}

	// Set the root (screen) item
	rootItem = new KdmRect( this, theme );

	basedir = QFileInfo( filename ).absolutePath();

	generateItems( rootItem, theme );
}

KdmThemer::~KdmThemer()
{
}

void
KdmThemer::setWidget( QWidget *w )
{
	if ((m_widget = w)) {
		rootItem->updateVisible();
		m_widget->setPalette( rootItem->style.palette );
		m_widget->setFont( rootItem->style.font.font );
		rootItem->plugActions();
	}
}

KdmItem *
KdmThemer::findNode( const QString &item ) const
{
	return rootItem->findChild<KdmItem *>( item );
}

void
KdmThemer::slotNeedPlacement()
{
	m_geometryOutdated = m_geometryInvalid = true;
	if (widget())
		widget()->update();
}

void
KdmThemer::slotNeedPlugging()
{
	if (widget())
		rootItem->plugActions();
}

void
KdmThemer::update( int x, int y, int w, int h )
{
	if (widget())
		widget()->update( x, y, w, h );
}

// BEGIN other functions

void
KdmThemer::widgetEvent( QEvent *e )
{
	if (!rootItem)
		return;
	switch (e->type()) {
	case QEvent::MouseMove:
		{
			QMouseEvent *me = static_cast<QMouseEvent *>(e);
			rootItem->mouseEvent( me->x(), me->y() );
		}
		break;
	case QEvent::MouseButtonPress:
		{
			QMouseEvent *me = static_cast<QMouseEvent *>(e);
			rootItem->mouseEvent( me->x(), me->y(), true );
		}
		break;
	case QEvent::MouseButtonRelease:
		{
			QMouseEvent *me = static_cast<QMouseEvent *>(e);
			rootItem->mouseEvent( me->x(), me->y(), false, true );
		}
		break;
	case QEvent::Resize:
		m_geometryOutdated = true;
		widget()->update();
		break;
	case QEvent::Paint:
		if (m_geometryOutdated) {
			debug() << "==== updating geometry ====";
			QStack<QSize> ps;
			QRect rect( QPoint( 0, 0 ), widget()->size() );
			rootItem->setGeometry( ps, rect, m_geometryInvalid );
			if (debugLevel & DEBUG_THEMING)
				showStructure();
			m_geometryOutdated = m_geometryInvalid = false;
		}
		{
			QRect paintRect = static_cast<QPaintEvent *>(e)->rect();
			//kDebug() << "paint on: " << paintRect;

			QPainter p( widget() );
			rootItem->paint( &p, paintRect, false, true );
			rootItem->showWidget();
		}
		break;
	default:
		break;
	}
}

void
KdmThemer::paintBackground( QPaintDevice *dev, const QRect &rect, bool primaryScreen )
{
	debug() << "==== setting background geometry ====";
	QStack<QSize> ps;
	rootItem->setGeometry( ps, rect, true );
	QPainter p( dev );
	rootItem->paint( &p, rect, true, primaryScreen );
}

void
KdmThemer::generateItems( KdmItem *parent, const QDomNode &node )
{
	/*
	 * Go through each of the child nodes
	 */
	const QDomNodeList &subnodeList = node.childNodes();
	for (int nod = 0; nod < subnodeList.count(); nod++) {
		QDomNode subnode = subnodeList.item( nod );
		QDomElement el = subnode.toElement();
		QString tagName = el.tagName();

		if (tagName == "item") {
			QString type = el.attribute( "type" );
			KdmItem *newItem;
			if (type == "label")
				newItem = new KdmLabel( parent, subnode );
			else if (type == "button")
				newItem = new KdmButton( parent, subnode );
			else if (type == "pixmap")
				newItem = new KdmPixmap( parent, subnode );
			else if (type == "rect")
				newItem = new KdmRect( parent, subnode );
			else if (type == "entry") {
				//newItem = new KdmEntry( parent, subnode );
				newItem = new KdmRect( parent, subnode );
				newItem->setType( type );
			} else if (type=="list")
				newItem = new KdmList( parent, subnode );
			else if (type == "svg")
				newItem = new KdmPixmap( parent, subnode );
			else
				continue;
			if (!newItem->isVisible()) {
				delete newItem;
				continue;
			}
			connect( newItem, SIGNAL(needUpdate( int, int, int, int )),
			         SLOT(update( int, int, int, int )) );
			connect( newItem, SIGNAL(needPlacement()),
			         SLOT(slotNeedPlacement()) );
			connect( newItem, SIGNAL(needPlugging()),
			         SLOT(slotNeedPlugging()) );
			connect( newItem, SIGNAL(activated( const QString & )),
			         SIGNAL(activated( const QString & )) );
			generateLayouts( newItem, subnode );
		}
	}
}

void
KdmThemer::generateLayouts( KdmItem *parent, const QDomNode &node )
{
	const QDomNodeList &subnodeList = node.childNodes();
	for (int nod = 0; nod < subnodeList.count(); nod++) {
		QDomNode subnode = subnodeList.item( nod );
		QString tagName = subnode.toElement().tagName();

		if (tagName == "box") {
			parent->setBoxLayout( subnode );
			generateItems( parent, subnode );
		} else if (tagName == "fixed") {
			parent->setFixedLayout( subnode );
			generateItems( parent, subnode );
		}
	}
}

void
KdmThemer::showStructure()
{
	QDebug( QtDebugMsg ) << "======= item tree =======";
	rootItem->showStructure( QString() );
}

void
KdmThemer::setTypeVisible( const QString &t, bool show )
{
	m_showTypes[t] = show;
	rootItem->updateVisible();
}

#include "kdmthemer.moc"
