/***************************************************************************
 *   Copyright (C) 2005-2007 by Stephen Leaf <smileaf@gmail.com>           *
 *   Copyright (C) 2006 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 "tdmtheme.h"

#include <kdialog.h>
#include <tdeglobal.h>
#include <tdeio/job.h>
#include <tdeio/netaccess.h>
#include <tdelocale.h>
#include <tdemessagebox.h>
#include <kprogress.h>
#include <kstandarddirs.h>
#include <ktar.h>
#include <kurlrequester.h>
#include <kurlrequesterdlg.h>
#include <tdeparts/genericfactory.h>

#include <tqcheckbox.h>
#include <tqdir.h>
#include <tqlayout.h>
#include <tqlabel.h>
#include <tqptrlist.h>
#include <tqpixmap.h>
#include <tqpushbutton.h>
#include <tqlistview.h>
#include <tqwhatsthis.h>
#include <tqwidget.h>

#include <unistd.h>

class ThemeData : public TQListViewItem {
  public:
	ThemeData( TQListView *parent = 0 ) : TQListViewItem( parent ) {}

	TQString name;
	TQString path;
	TQString screenShot;
	TQString copyright;
	TQString description;
};

typedef KGenericFactory<TDMThemeWidget, TQWidget> tdmthemeFactory;
K_EXPORT_COMPONENT_FACTORY( kcm_tdmtheme, tdmthemeFactory("kcmtdmtheme"))

TDMThemeWidget::TDMThemeWidget( TQWidget *parent, const char *name, const TQStringList& )
	: TDECModule(parent, name), config( 0L )
{
	TQGridLayout *ml = new TQGridLayout( this );
	ml->setSpacing( KDialog::spacingHint() );
	ml->setMargin( KDialog::marginHint() );

	sakWarning = new TQLabel( this );
	sakWarning->setText( i18n( "Theming is not available due to enabled Secure Attention Key (SAK) support" ) );
	ml->addMultiCellWidget( sakWarning, 0, 0, 0, 2 );
	sakWarning->hide();

	cUseTheme = new TQCheckBox( this );
	cUseTheme->setText( i18n( "En&able TDM Themes" ) );
	ml->addMultiCellWidget( cUseTheme, 0, 0, 0, 2 );

	themeWidget = new TQListView( this );
	themeWidget->addColumn( i18n( "Theme" ) );
	themeWidget->addColumn( i18n( "Author" ) );
	themeWidget->setAllColumnsShowFocus( true );
	themeWidget->setShowSortIndicator( true );
	themeWidget->setRootIsDecorated( false );
	TQWhatsThis::add( themeWidget, i18n("This is a list of installed themes.\n"
	                                "Click the one to be used.") );

	ml->addMultiCellWidget( themeWidget, 1, 3, 0, 1 );

	preview = new TQLabel( this );
	preview->setFixedSize( TQSize( 200, 150 ) );
	preview->setScaledContents( true );
	TQWhatsThis::add(preview, i18n("This is a screen shot of what TDM will look like.") );

	ml->addWidget( preview, 1, 2 );

	info = new TQLabel( this );
	info->setMaximumWidth( 200 );
	info->setAlignment( int( TQLabel::AlignTop | TQLabel::WordBreak) );
	TQWhatsThis::add(info, i18n("This contains information about the selected theme.") );

	ml->addMultiCellWidget( info, 3, 4, 2, 2 );

	bInstallTheme = new TQPushButton( i18n("Install &new theme"), this );
	TQWhatsThis::add(bInstallTheme, i18n("This will install a theme into the theme directory.") );

	ml->addWidget( bInstallTheme, 4, 0 );

	bRemoveTheme = new TQPushButton( i18n("&Remove theme"), this );
	TQWhatsThis::add(bRemoveTheme, i18n("This will remove the selected theme.") );

	ml->addWidget( bRemoveTheme, 4, 1 );

	connect( themeWidget, TQ_SIGNAL(selectionChanged()), TQ_SLOT(themeSelected()) );
	connect( bInstallTheme, TQ_SIGNAL(clicked()), TQ_SLOT(installNewTheme()) );
	connect( bRemoveTheme, TQ_SIGNAL(clicked()), TQ_SLOT(removeSelectedThemes()) );
	connect( cUseTheme, TQ_SIGNAL( toggled( bool ) ), TQ_SLOT( toggleUseTheme( bool ) ) );

	TQStringList themeDirs = TDEGlobal::dirs()->findDirs("data","tdm/");
	themeDir = TDEGlobal::dirs()->findDirs("data","tdm/").last();
	TQDir d;
	for ( TQStringList::Iterator dirs = themeDirs.begin(); dirs != themeDirs.end(); ++dirs ) {
		kdDebug() << "Loading themes... ( " + *dirs + "themes/" + " )" << endl;
		d.setPath( *dirs + "themes/" );
		d.setFilter( TQDir::Dirs );
		TQStringList list = d.entryList();
		for ( TQStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
			if (*it == "." || *it == "..") continue;
			insertTheme( *dirs + "themes/" + *it );
		}
	}

	load();

	if (getuid() != 0 || !config->checkConfigFilesWritable( true )) {
		cUseTheme->setEnabled( false );
		setReadOnly(true);
	}
}

void TDMThemeWidget::selectTheme( const TQString &path )
{
	for ( TQListViewItemIterator tdi( themeWidget ); tdi.current(); tdi++ ) {
		ThemeData * td = ((ThemeData *)*tdi);
		if (td->path == path) {
			themeWidget->clearSelection();
			themeWidget->setSelected(td, true );
			updateInfoView( td );
		}
	}
}

void TDMThemeWidget::load()
{
	TQString tdmrc = TDEGlobal::dirs()->findResource("config", "tdm/tdmdistrc");
	if ( tdmrc.isEmpty() ) {
		tdmrc = TDEGlobal::dirs()->findResource("config", "tdm/tdmrc");
	}
	if ( tdmrc.isEmpty() ) {
		kdError() << "Failed to find tdm resource file tdmrc!" << endl;

		KMessageBox msgBox;
		msgBox.sorry(0, i18n("I can't find the configuration file for the Login Manager, tdm. Check you have set up the Login Manager from the Control Center, and that you have permision to read and write the Login Manager's configuration file.\n\n You must set-up the Login Manager before you can use its themes."), i18n("Can't find Configuration File"));

		delete config;
		config = NULL;
	} else {
		kdDebug() << "Loading... ( " + tdmrc + " )" << endl;

		delete config;
		config = new TDEConfig( tdmrc );

		config->setGroup( "X-*-Greeter" );
		bool sakEnabled = config->readBoolEntry( "UseSAK", false );
		if (sakEnabled) {
			// FIXME
			// Integrate TDE_BINDIR with Autotools and use this line instead of the one below it...
			// if (system(TDE_BINDIR "/tsak checkdeps") != 0) {
			if (system("tsak checkdeps") != 0) {
				sakEnabled = false;
			}
		}
		if (sakEnabled) {
			cUseTheme->hide();
			sakWarning->show();
			cUseTheme->setEnabled(false);
			setReadOnly(true);
		}
		else {
			sakWarning->hide();
			cUseTheme->show();
			cUseTheme->setEnabled(true);
			setReadOnly(false);
		}

		config->setGroup( "X-*-Greeter" );
		cUseTheme->setChecked( config->readBoolEntry( "UseTheme", false ) );

		selectTheme( config->readEntry( "Theme", themeDir + "circles" ) );
	}
}

void TDMThemeWidget::save()
{
	kdDebug() << "Saving: Theme " << defaultTheme->path << " - UseTheme " << cUseTheme->isChecked() << endl;
	config->writeEntry( "Theme", defaultTheme->path );
	config->writeEntry( "UseTheme", cUseTheme->isChecked() );
	config->sync();
}

void TDMThemeWidget::defaults()
{
	selectTheme( themeDir + "circles" );

	emit changed(true);
}

void TDMThemeWidget::toggleUseTheme(bool useTheme) {
	setReadOnly( useTheme );
	emit changed(true);
}

void TDMThemeWidget::setReadOnly(bool ro)
{
	if (!cUseTheme->isEnabled()) {
		ro = true;
	}
	themeWidget->setEnabled( ro );
	bInstallTheme->setEnabled( ro );
	bRemoveTheme->setEnabled( ro );
}

void TDMThemeWidget::insertTheme( const TQString &_theme )
{
	TDEConfig * themeConfig;
	TQString name;

	kdDebug() << "Looking for " << _theme << "/KdmGreeterTheme.desktop" << endl;
	themeConfig = new TDEConfig( _theme + "/KdmGreeterTheme.desktop");
	themeConfig->setGroup( "GdmGreeterTheme" );
	name = themeConfig->readEntry( "Name" );
	if (name.isEmpty()) {
		kdDebug() << "Looking for " << _theme << "/GdmGreeterTheme.desktop" << endl;
		themeConfig = new TDEConfig( _theme + "/GdmGreeterTheme.desktop");
		themeConfig->setGroup( "GdmGreeterTheme" );

		name = themeConfig->readEntry( "Name" );
		if (name.isEmpty())
			return;
	}

	for ( TQListViewItemIterator tdi( themeWidget ); tdi.current(); tdi++ ) {
		ThemeData * td = ((ThemeData *)*tdi);
		if (td->name == name)
			return;
	}
	kdDebug() << "Adding theme " << name << endl;

	ThemeData *child = new ThemeData( themeWidget );
	child->setText( 0, name );
	child->setText( 1, themeConfig->readEntry( "Author" ) );
	child->name = name;
	child->path = _theme;
	child->screenShot = themeConfig->readEntry( "Screenshot" );
	child->copyright = themeConfig->readEntry( "Copyright" );
	child->description = themeConfig->readEntry( "Description" );
}

void TDMThemeWidget::updateInfoView( ThemeData *theme )
{
	if(theme) {
		info->setText(
			((theme->copyright.length() > 0)
				? i18n("<qt><strong>Copyright:</strong> %1<br/></qt>")
					.arg(theme->copyright)
				: "") +
			((theme->description.length() > 0)
				? i18n("<qt><strong>Description:</strong> %1</qt>")
					.arg(theme->description)
				: "") );
		preview->setPixmap( theme->path + '/' + theme->screenShot );
		preview->setText( theme->screenShot.isEmpty() ?
			i18n("Screenshot not available") : TQString() );
	} else {
		info->setText(i18n("No theme selected."));
		preview->setPixmap(NULL);
		preview->setText(i18n("Screenshot not available"));
	}
}

void TDMThemeWidget::installNewTheme()
{
	KURLRequesterDlg fileRequester( TQString(), this, i18n("Drag or Type Theme URL").utf8() );
	fileRequester.urlRequester()->setMode( KFile::File | KFile::Directory | KFile::ExistingOnly );
	KURL themeURL = fileRequester.getURL();
	if (themeURL.isEmpty())
		return;

	TQString themeTmpFile;

	if (!TDEIO::NetAccess::download( themeURL, themeTmpFile, this )) {
		TQString sorryText;
		if (themeURL.isLocalFile())
			sorryText = i18n("Unable to find the TDM theme archive %1.").arg(themeURL.prettyURL());
		else
			sorryText = i18n("Unable to download the TDM theme archive;\n"
			                 "please check that address %1 is correct.").arg(themeURL.prettyURL());
		KMessageBox::sorry( this, sorryText );
		return;
	}

	TQPtrList<KArchiveDirectory> foundThemes;

	KTar archive( themeTmpFile );
	archive.open( IO_ReadOnly );

	const KArchiveDirectory *archDir = archive.directory();
	TQStringList entries = archDir->entries();
	for (TQStringList::Iterator ent = entries.begin(); ent != entries.end(); ++ent) {
		const KArchiveEntry *possibleDir = archDir->entry( *ent );
		if (possibleDir->isDirectory()) {
			const KArchiveDirectory *subDir =
				static_cast<const KArchiveDirectory *>( possibleDir );
			if (subDir->entry( "KdmGreeterTheme.desktop" ))
				foundThemes.append( subDir );
			else if (subDir->entry( "GdmGreeterTheme.desktop" ))
				foundThemes.append( subDir );
		}
	}

	if (foundThemes.isEmpty())
		KMessageBox::error( this, i18n("The file is not a valid TDM theme archive.") );
	else {
		KProgressDialog progressDiag( this,
			i18n("Installing TDM themes").utf8(), TQString() );
		progressDiag.setModal( true );
		progressDiag.setAutoClose( true );
		progressDiag.progressBar()->setTotalSteps( foundThemes.count() );
		progressDiag.show();

		for ( KArchiveDirectory * ard = foundThemes.first(); foundThemes.current(); foundThemes.next() ) {
			progressDiag.setLabel(
				i18n("<qt>Installing <strong>%1</strong> theme</qt>").arg(ard->name()) );

			TQString path = themeDir + "themes/" + ard->name();
			kdDebug() << "Unpacking new theme to " << path << endl;
			ard->copyTo( path, true );
			if (TQDir( path ).exists())
				insertTheme( path );

			progressDiag.progressBar()->setValue( progressDiag.progressBar()->value() + 1 );
			if (progressDiag.wasCancelled())
				break;
		}
		emit changed(true);
	}

	archive.close();

	TDEIO::NetAccess::removeTempFile( themeTmpFile );
}

void TDMThemeWidget::themeSelected()
{
	if (themeWidget->selectedItem()) {
		defaultTheme = (ThemeData *)(themeWidget->selectedItem());
		updateInfoView( defaultTheme );
	} else
		updateInfoView( 0 );
	emit changed(true);
}

void TDMThemeWidget::removeSelectedThemes()
{
	TQListViewItem * themes = themeWidget->selectedItem();
	if (!themes)
		return;
	if (KMessageBox::questionYesNoList( this,
			i18n("Are you sure you want to remove this TDM theme?"),
			themes->text(0), i18n("Remove theme?") ) != KMessageBox::Yes)
		return;
	TDEIO::del( ((ThemeData *)themes)->path ); // XXX error check

	themeWidget->takeItem( themes );
}

#include "tdmtheme.moc"
