/*
    Copyright (C) 2000 Oswald Buddenhagen <ossi@kde.org>
    Based on several other files.

    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 Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#include "kdm-conv.h"

#include <KColorScheme>
#include <KComboBox>
#include <KDialog>
#include <KLocale>
#include <KConfig>
#include <KConfigGroup>

#include <QButtonGroup>
#include <QCheckBox>
#include <QGroupBox>
#include <QLabel>
#include <QListWidget>
#include <QRadioButton>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QVBoxLayout>

extern KConfig *config;


KDMConvenienceWidget::KDMConvenienceWidget( QWidget *parent )
	: QWidget( parent )
{
	QString wtstr;

	QLabel *paranoia = new QLabel(
		i18n("<big><b><center>Attention<br/>"
	            "Read help</center></b></big>"), this );
	QPalette p;
	p.setBrush( QPalette::WindowText,
		KColorScheme( QPalette::Active, KColorScheme::Window )
			.foreground( KColorScheme::NegativeText ) );
	paranoia->setPalette( p );

	QSizePolicy vpref( QSizePolicy::Minimum, QSizePolicy::Fixed );

	alGroup = new QGroupBox( i18n("Enable Au&to-Login"), this );
	alGroup->setCheckable( true );
	alGroup->setSizePolicy( vpref );
	QVBoxLayout *laygroup2 = new QVBoxLayout( alGroup );
	laygroup2->setSpacing( KDialog::spacingHint() );

	alGroup->setWhatsThis( i18n("Turn on the auto-login feature."
	                            " This applies only to KDM's graphical login."
	                            " Think twice before enabling this!") );
	connect( alGroup, SIGNAL(toggled( bool )), SIGNAL(changed()) );

	userlb = new KComboBox( alGroup );

	QLabel* u_label = new QLabel( i18n("Use&r:"), alGroup );
	u_label->setBuddy( userlb );
	QHBoxLayout *hlpl1 = new QHBoxLayout();
	laygroup2->addItem( hlpl1 );
	hlpl1->setSpacing( KDialog::spacingHint() );
	hlpl1->addWidget( u_label );
	hlpl1->addWidget( userlb );
	hlpl1->addStretch( 1 );
	connect( userlb, SIGNAL(highlighted( int )), SIGNAL(changed()) );
	wtstr = i18n("Select the user to be logged in automatically.");
	u_label->setWhatsThis( wtstr );
	userlb->setWhatsThis( wtstr );
	autoLockCheck = new QCheckBox( i18n("Loc&k session"), alGroup );
	laygroup2->addWidget( autoLockCheck );
	connect( autoLockCheck, SIGNAL(toggled( bool )), SIGNAL(changed()) );
	autoLockCheck->setWhatsThis( i18n(
		"The automatically started session "
		"will be locked immediately (provided it is a KDE session). This can "
		"be used to obtain a super-fast login restricted to one user.") );

	puGroup = new QGroupBox( i18nc("@title:group", "Preselect User"), this );

	puGroup->setSizePolicy( vpref );

	npRadio = new QRadioButton( i18nc("@option:radio preselected user", "&None"), puGroup );
	ppRadio = new QRadioButton( i18nc("@option:radio preselected user", "Prev&ious"), puGroup );
	ppRadio->setWhatsThis( i18n(
		"Preselect the user that logged in previously. "
		"Use this if this computer is usually used several consecutive times by one user.") );
	spRadio = new QRadioButton( i18nc("@option:radio preselected user", "Specif&y"), puGroup );
	spRadio->setWhatsThis( i18n(
		"Preselect the user specified in the combo box below. "
		"Use this if this computer is predominantly used by a certain user.") );
	QButtonGroup *buttonGroup = new QButtonGroup( puGroup );
	connect( buttonGroup, SIGNAL(buttonClicked( int )), SLOT(slotPresChanged()) );
	connect( buttonGroup, SIGNAL(buttonClicked( int )), SIGNAL(changed()) );
	buttonGroup->addButton( npRadio );
	buttonGroup->addButton( ppRadio );
	buttonGroup->addButton( spRadio );
	QVBoxLayout *laygroup5 = new QVBoxLayout( puGroup );
	laygroup5->setSpacing( KDialog::spacingHint() );
	laygroup5->addWidget( npRadio );
	laygroup5->addWidget( ppRadio );

	puserlb = new KComboBox( true, puGroup );

	pu_label = new QLabel( i18n("Us&er:"), puGroup );
	pu_label->setBuddy( puserlb );
	connect( puserlb, SIGNAL(editTextChanged( const QString & )), SIGNAL(changed()) );
	wtstr = i18n(
		"Select the user to be preselected for login. "
		"This box is editable, so you can specify an arbitrary non-existent "
		"user to mislead possible attackers.");
	pu_label->setWhatsThis( wtstr );
	puserlb->setWhatsThis( wtstr );
	QBoxLayout *hlpl = new QHBoxLayout();
	laygroup5->addItem( hlpl );
	hlpl->setSpacing( KDialog::spacingHint() );
	hlpl->setMargin( 0 );
	hlpl->addWidget( spRadio );
	hlpl->addWidget( pu_label );
	hlpl->addWidget( puserlb );
	hlpl->addStretch( 1 );
	cbjumppw = new QCheckBox( i18nc("@option:check action", "Focus pass&word"), puGroup );
	laygroup5->addWidget( cbjumppw );
	cbjumppw->setWhatsThis( i18n(
		"When this option is on, KDM will place the cursor "
		"in the password field instead of the user field after preselecting a user. "
		"Use this to save one key press per login, if the preselection usually "
		"does not need to be changed.") );
	connect( cbjumppw, SIGNAL(toggled( bool )), SIGNAL(changed()) );

	npGroup = new QGroupBox( i18n("Enable Password-&Less Logins"), this );
	QVBoxLayout *laygroup3 = new QVBoxLayout( npGroup );
	laygroup3->setSpacing( KDialog::spacingHint() );

	npGroup->setCheckable( true );

	npGroup->setWhatsThis( i18n(
		"When this option is checked, the checked users from "
		"the list below will be allowed to log in without entering their "
		"password. This applies only to KDM's graphical login. "
		"Think twice before enabling this!") );

	connect( npGroup, SIGNAL(toggled( bool )), SIGNAL(changed()) );

	QLabel *pl_label = new QLabel( i18n("No password re&quired for:"), npGroup );
	laygroup3->addWidget( pl_label );
	npuserlv = new QListWidget( npGroup );
	laygroup3->addWidget( npuserlv );
	pl_label->setBuddy( npuserlv );
	npuserlv->setWhatsThis( i18n(
		"Check all users you want to allow a password-less login for. "
		"Entries denoted with '@' are user groups. Checking a group is like "
		"checking all users in that group.") );

	btGroup = new QGroupBox( i18nc("@title:group", "Miscellaneous"), this );
	QVBoxLayout *laygroup4 = new QVBoxLayout( btGroup );
	laygroup4->setSpacing( KDialog::spacingHint() );

	cbarlen = new QCheckBox( i18n("Automatically log in again after &X server crash"), btGroup );
	cbarlen->setWhatsThis( i18n(
		"When this option is on, a user will be "
		"logged in again automatically when their session is interrupted by an "
		"X server crash; note that this can open a security hole: if you use "
		"a screen locker than KDE's integrated one, this will make "
		"circumventing a password-secured screen lock possible.") );
	//TODO a screen locker _other_ than
	laygroup4->addWidget( cbarlen );
	connect( cbarlen, SIGNAL(toggled( bool )), SIGNAL(changed()) );

	QGridLayout *main = new QGridLayout( this );
	main->setSpacing( 10 );
	main->addWidget( paranoia, 0, 0 );
	main->addWidget( alGroup, 1, 0 );
	main->addWidget( puGroup, 2, 0 );
	main->addWidget( npGroup, 0, 1, 4, 1 );
	main->addWidget( btGroup, 4, 0, 1, 2 );
	main->setColumnStretch( 0, 1 );
	main->setColumnStretch( 1, 2 );
	main->setRowStretch( 3, 1 );

	connect( userlb, SIGNAL(activated( const QString & )),
	         SLOT(slotSetAutoUser( const QString & )) );
	connect( puserlb, SIGNAL(editTextChanged( const QString & )),
	         SLOT(slotSetPreselUser( const QString & )) );
	connect( npuserlv, SIGNAL(itemClicked( QListWidgetItem * )),
	         SLOT(slotUpdateNoPassUser( QListWidgetItem * )) );

}

void KDMConvenienceWidget::makeReadOnly()
{
	alGroup->setEnabled( false ); // this sucks
	//userlb->setEnabled( false );
	//autoLockCheck->setEnabled( false );
	npGroup->setEnabled( false ); // this sucks, too
	//npuserlv->setEnabled( false );
	cbarlen->setEnabled( false );
	npRadio->setEnabled( false );
	ppRadio->setEnabled( false );
	spRadio->setEnabled( false );
	puserlb->setEnabled( false );
	cbjumppw->setEnabled( false );
}

void KDMConvenienceWidget::slotPresChanged()
{
	bool en = spRadio->isChecked();
	pu_label->setEnabled( en );
	if (!alGroup->isEnabled()) // read-only
	   return;
	puserlb->setEnabled( en );
	cbjumppw->setEnabled( !npRadio->isChecked() );
}

void KDMConvenienceWidget::save()
{
	KConfigGroup configGrp = config->group( "X-:0-Core" );
	configGrp.writeEntry( "AutoLoginEnable", alGroup->isChecked() );
	configGrp.writeEntry( "AutoLoginUser", userlb->currentText() );
	configGrp.writeEntry( "AutoLoginLocked", autoLockCheck->isChecked() );

	configGrp = config->group( "X-:*-Core" );
	configGrp.writeEntry( "NoPassEnable", npGroup->isChecked() );
	configGrp.writeEntry( "NoPassUsers", noPassUsers );

	config->group( "X-*-Core" ).writeEntry( "AutoReLogin", cbarlen->isChecked() );

	configGrp = config->group( "X-:*-Greeter" );
	configGrp.writeEntry( "PreselectUser",
	                      npRadio->isChecked() ? "None" :
	                      ppRadio->isChecked() ? "Previous" :
	                      "Default" );
	configGrp.writeEntry( "DefaultUser", puserlb->currentText() );
	configGrp.writeEntry( "FocusPasswd", cbjumppw->isChecked() );
}


void KDMConvenienceWidget::load()
{
	KConfigGroup configGrp = config->group( "X-:0-Core" );
	bool alenable = configGrp.readEntry( "AutoLoginEnable", false );
	autoUser = configGrp.readEntry( "AutoLoginUser" );
	autoLockCheck->setChecked( configGrp.readEntry( "AutoLoginLocked", false ) );
	if (autoUser.isEmpty())
		alenable = false;
	alGroup->setChecked( alenable );

	configGrp = config->group( "X-:*-Core" );
	npGroup->setChecked( configGrp.readEntry( "NoPassEnable", false ) );
	noPassUsers = configGrp.readEntry( "NoPassUsers", QStringList() );

	cbarlen->setChecked( config->group( "X-*-Core" ).readEntry( "AutoReLogin", false ) );

	configGrp = config->group( "X-:*-Greeter" );
	QString presstr = configGrp.readEntry( "PreselectUser", "None" );
	if (presstr == "Previous")
		ppRadio->setChecked( true );
	else if (presstr == "Default")
		spRadio->setChecked( true );
	else
		npRadio->setChecked( true );
	preselUser = configGrp.readEntry( "DefaultUser" );
	cbjumppw->setChecked( configGrp.readEntry( "FocusPasswd", false ) );

	slotPresChanged();
}


void KDMConvenienceWidget::defaults()
{
	alGroup->setChecked( false );
	autoLockCheck->setChecked( false );
	npRadio->setChecked( true );
	npGroup->setChecked( false );
	cbarlen->setChecked( false );
	cbjumppw->setChecked( false );
	autoUser = "";
	preselUser = "";
	noPassUsers.clear();

	slotPresChanged();
}


void KDMConvenienceWidget::slotSetAutoUser( const QString &user )
{
	autoUser = user;
}

void KDMConvenienceWidget::slotSetPreselUser( const QString &user )
{
	preselUser = user;
}

void KDMConvenienceWidget::slotUpdateNoPassUser( QListWidgetItem *item )
{
	if (!item)
		return;
	int ind = noPassUsers.indexOf( item->text() );
	if (item->checkState() == Qt::Checked) {
		if (ind < 0) {
			noPassUsers.append( item->text() );
			emit changed();
		}
	} else {
		if (ind >= 0) {
			noPassUsers.removeAt( ind );
			emit changed();
		}
	}
}

void KDMConvenienceWidget::slotClearUsers()
{
	userlb->clear();
	puserlb->clear();
	npuserlv->clear();
	if (!autoUser.isEmpty())
		userlb->addItem( autoUser );
	if (!preselUser.isEmpty())
		puserlb->addItem( preselUser );
}

void KDMConvenienceWidget::slotAddUsers( const QMap<QString,int> &users )
{
	QMap<QString,int>::const_iterator it;
	for (it = users.begin(); it != users.end(); ++it) {
		if (it.value() > 0) {
			if (it.key() != autoUser)
				userlb->addItem( it.key() );
			if (it.key() != preselUser)
				puserlb->addItem( it.key() );
		}
		if (it.value() != 0) {
			QListWidgetItem *item = new QListWidgetItem( it.key(), npuserlv );
			item->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled |
			                Qt::ItemIsUserCheckable );
			item->setCheckState(  noPassUsers.contains( it.key() ) ?
			                      Qt::Checked : Qt::Unchecked );
		}
	}

	if (userlb->model())
		userlb->model()->sort( 0 );

	if (puserlb->model())
		puserlb->model()->sort( 0 );

	npuserlv->sortItems();

	userlb->setCurrentItem( autoUser );
	puserlb->setCurrentItem( preselUser );
}

void KDMConvenienceWidget::slotDelUsers( const QMap<QString,int> &users )
{
	QMap<QString,int>::const_iterator it;
	for (it = users.begin(); it != users.end(); ++it) {
		if (it.value() > 0) {
			int idx = userlb->findText( it.key() );
			if (it.key() != autoUser && idx != -1)
				userlb->removeItem( idx );
			idx = puserlb->findText( it.key() );
			if (it.key() != preselUser && idx != -1)
				puserlb->removeItem( idx );
		}
		if (it.value() != 0)
			delete npuserlv->findItems( it.key(), Qt::MatchExactly ).first();
	}
}

#include "kdm-conv.moc"
