#include "opt_general.h"
#include "common.h"
#include "iconwidget.h"

#include <qbuttongroup.h>
#include <qwhatsthis.h>
#include <qcheckbox.h>
#include <qradiobutton.h>
#include <qcombobox.h>
#include <qlineedit.h>
#include <qsignalmapper.h>
#include <qpixmap.h>
#include <qpainter.h>
#include <qcolordialog.h>

#include "opt_general_roster.h"
#include "opt_general_docking.h"
#include "opt_general_misc.h"
#include "opt_general_notify.h"
#include "opt_general_groupchat.h"

//----------------------------------------------------------------------------
// OptionsTabGeneral
//----------------------------------------------------------------------------

OptionsTabGeneral::OptionsTabGeneral(QObject *parent)
: MetaOptionsTab(parent, "general", "", tr("General"), tr("General options"), "psi/psi16")
{
	addTab( new OptionsTabGeneralRoster(this) );
	addTab( new OptionsTabGeneralDocking(this) );
	addTab( new OptionsTabGeneralMisc(this) );
	addTab( new OptionsTabGeneralNotifications(this) );
	addTab( new OptionsTabGeneralGroupchat(this) );
}

//----------------------------------------------------------------------------
// OptionsTabGeneralRoster
//----------------------------------------------------------------------------

OptionsTabGeneralRoster::OptionsTabGeneralRoster(QObject *parent)
: OptionsTab(parent, "general_roster", "general", tr("Roster"), tr("Configure your roster"))
{
	w = 0;
	bg_defAct = 0;
}

OptionsTabGeneralRoster::~OptionsTabGeneralRoster()
{
	if ( bg_defAct )
		delete bg_defAct;
}

QWidget *OptionsTabGeneralRoster::widget()
{
	if ( w )
		return 0;

	w = new GeneralRosterUI();
	GeneralRosterUI *d = (GeneralRosterUI *)w;

	bg_defAct = new QButtonGroup;
	bg_defAct->setRadioButtonExclusive( true );
	bg_defAct->insert( d->rb_defActMsg,  0 );
	bg_defAct->insert( d->rb_defActChat, 1 );

	QWhatsThis::add(d->ck_useleft,
		tr("Normally, right-clicking with the mouse on a contact will activate the context-menu."
		"  Check this option if you'd rather use a left-click."));
	QWhatsThis::add(d->ck_singleclick,
		tr("Normally, a double-click on a contact will invoke the default action."
		"  Check this option if you'd rather invoke with a single-click."));

	QWhatsThis::add(d->rb_defActMsg,
		tr("Make the default action open a chat window."));
	QWhatsThis::add(d->rb_defActChat,
		tr("Make the default action open a normal message window."));

	QWhatsThis::add(d->ck_showself,
		tr("If checked, always show the self-contact in roster, "
		   "otherwise it is shown only when multiple resources are connected to your account."));

	return w;
}

void OptionsTabGeneralRoster::applyOptions(Options *opt)
{
	if ( !w )
		return;

	GeneralRosterUI *d = (GeneralRosterUI *)w;
	opt->useleft = d->ck_useleft->isChecked();
	opt->singleclick = d->ck_singleclick->isChecked();
	opt->defaultAction = bg_defAct->id(bg_defAct->selected());
	opt->alwaysShowSelf = d->ck_showself->isChecked();
}

void OptionsTabGeneralRoster::restoreOptions(const Options *opt)
{
	if ( !w )
		return;

	GeneralRosterUI *d = (GeneralRosterUI *)w;
	d->ck_useleft->setChecked( opt->useleft );
	d->ck_singleclick->setChecked( opt->singleclick );
	bg_defAct->setButton( opt->defaultAction );
	d->ck_showself->setChecked( opt->alwaysShowSelf );
}

//----------------------------------------------------------------------------
// OptionsTabGeneralDocking
//----------------------------------------------------------------------------

OptionsTabGeneralDocking::OptionsTabGeneralDocking(QObject *parent)
: OptionsTab(parent, "general_docking", "general", tr("Docking"), tr("Configure the Psi docklet"))
{
	w = 0;
}

QWidget *OptionsTabGeneralDocking::widget()
{
	if ( w )
		return 0;

	w = new GeneralDockingUI();
	GeneralDockingUI *d = (GeneralDockingUI *)w;

	connect(d->ck_docklet, SIGNAL(toggled(bool)), d->ck_dockDCstyle, SLOT(setEnabled(bool)));
	connect(d->ck_docklet, SIGNAL(toggled(bool)), d->ck_dockHideMW,  SLOT(setEnabled(bool)));
	connect(d->ck_docklet, SIGNAL(toggled(bool)), d->ck_dockToolMW,  SLOT(setEnabled(bool)));

	QWhatsThis::add(d->ck_docklet,
		tr("Makes Psi use a docklet icon, also known as system tray icon."));
	QWhatsThis::add(d->ck_dockDCstyle,
		tr("Normally, single-clicking on the Psi docklet icon brings the main window to"
		" the foreground.  Check this option if you would rather use a double-click."));
	QWhatsThis::add(d->ck_dockHideMW,
		tr("Starts Psi with only the docklet icon visible."));
	QWhatsThis::add(d->ck_dockToolMW,
		tr("Prevents Psi from taking up a slot on the taskbar and makes the main "
		"window use a small titlebar."));

	return w;
}

void OptionsTabGeneralDocking::applyOptions(Options *opt)
{
	if ( !w )
		return;

	GeneralDockingUI *d = (GeneralDockingUI *)w;
	opt->useDock = d->ck_docklet->isChecked();
	opt->dockDCstyle = d->ck_dockDCstyle->isChecked();
	opt->dockHideMW = d->ck_dockHideMW->isChecked();
	opt->dockToolMW = d->ck_dockToolMW->isChecked();
}

void OptionsTabGeneralDocking::restoreOptions(const Options *opt)
{
	if ( !w )
		return;

	GeneralDockingUI *d = (GeneralDockingUI *)w;
	d->ck_docklet->setChecked( opt->useDock );
	d->ck_dockDCstyle->setChecked( opt->dockDCstyle );
	d->ck_dockHideMW->setChecked( opt->dockHideMW );
	d->ck_dockToolMW->setChecked( opt->dockToolMW );

	if( !d->ck_docklet->isChecked() ) {
		d->ck_dockDCstyle->setEnabled(false);
		d->ck_dockHideMW->setEnabled(false);
		d->ck_dockToolMW->setEnabled(false);
	}
}

//----------------------------------------------------------------------------
// OptionsTabGeneralMisc
//----------------------------------------------------------------------------

OptionsTabGeneralMisc::OptionsTabGeneralMisc(QObject *parent)
: OptionsTab(parent, "general_misc", "general", tr("Misc"), tr("Miscellaneous settings"))
{
	w = 0;
	bg_delChats = 0;
}

OptionsTabGeneralMisc::~OptionsTabGeneralMisc()
{
	if ( bg_delChats )
		delete bg_delChats;
}

QWidget *OptionsTabGeneralMisc::widget()
{
	if ( w )
		return 0;

	w = new GeneralMiscUI();
	GeneralMiscUI *d = (GeneralMiscUI *)w;

	// chat
	QWhatsThis::add(d->ck_chatSays,
		tr("<P>Changes the normal chat style from:</P>"
		"<P>[01:23:45] &lt;MyName&gt; Hi</P>"
		"<P>[01:23:56] &lt;YourName&gt; How are you?</P>"
		"<P>to:</P>"
		"<P>[01:23:45] MyName says:</P>"
		"<P>Hi</P>"
		"<P>[01:23:56] YourName says:</P>"
		"<P>How are you?</P>"));
	QWhatsThis::add(d->ck_chatSoftReturn,
		tr("<P>When checked, pressing Enter in a chat window will send your message."
		   "  You must use Shift+Enter in order to create a newline in the chat message."
		   "  If unchecked, messages are sent by pressing Alt-S or Control-Enter, just as they are with regular messages.</P>"));

	// misc
	bg_delChats = new QButtonGroup;
	bg_delChats->setRadioButtonExclusive( true );
	bg_delChats->insert( d->rb_delChatsClose, 0 );
	bg_delChats->insert( d->rb_delChatsHour,  1 );
	bg_delChats->insert( d->rb_delChatsDay,   2 );
	bg_delChats->insert( d->rb_delChatsNever, 3 );

	QWhatsThis::add(d->ck_alwaysOnTop,
		tr("Makes the main Psi window always be in front of other windows."));
	QWhatsThis::add(d->ck_keepSizes,
		tr("Makes Psi remember window size and positions for chats and messages."
		"  If disabled, the windows will always appear in their default positions and sizes."));
	QWhatsThis::add(d->ck_jidComplete,
		tr("Enables as-you-type JID autocompletion in message dialog."));
	QWhatsThis::add(d->ck_grabUrls,
		tr("Automatically attaches URLs from clipboard to the messages when enabled"));

	QString s = tr("<P>Controls how long the chat log will be kept in memory after the"
		" chat window is closed.</P>");
	QWhatsThis::add(d->rb_delChatsClose, s +
		tr("<P>This option does not keep the chat log in memory.</P>"));
	QWhatsThis::add(d->rb_delChatsHour, s +
		tr("<P>This option keeps the chat log for 1 hour before deleting it.</P>"));
	QWhatsThis::add(d->rb_delChatsDay, s +
		tr("<P>This option keeps the chat log for 1 day before deleting it.</P>"));
	QWhatsThis::add(d->rb_delChatsNever, s +
		tr("<P>This options keeps the chat log forever.</P>"));

	// links
	QWhatsThis::add(d->cb_link,
		tr("Selects what applications to use for handling URLs and e-mail addresses."
		"  You can choose between the system default and custom applications."));

	s = tr("Enter the path to the application's executable and choose \"Custom\" in the list above.");
	QWhatsThis::add(d->le_linkBrowser,
		tr("Specify what custom browser application to use for handling URLs here.") + "  " + s);
	QWhatsThis::add(d->le_linkMailer,
		tr("Specify what custom mailer application to use for handling e-mail addresses here.") + "  " + s);

	return w;
}

static int om_x11browse[] = { 0, 2, 1 };

void OptionsTabGeneralMisc::applyOptions(Options *opt)
{
	if ( !w )
		return;

	GeneralMiscUI *d = (GeneralMiscUI *)w;

	// chat
	opt->chatSays       = d->ck_chatSays->isChecked();
	opt->chatSoftReturn = d->ck_chatSoftReturn->isChecked();

	// misc
	opt->alwaysOnTop = d->ck_alwaysOnTop->isChecked();
	opt->keepSizes   = d->ck_keepSizes->isChecked();
	opt->jidComplete = d->ck_jidComplete->isChecked();
	opt->grabUrls    = d->ck_grabUrls->isChecked();
	opt->delChats    = bg_delChats->id( bg_delChats->selected() );

	// links
#ifdef Q_WS_X11
	opt->browser = om_x11browse[ d->cb_link->currentItem() ];
#else
	opt->browser = d->cb_link->currentItem();
#endif
	opt->customBrowser = d->le_linkBrowser->text();
	opt->customMailer  = d->le_linkMailer->text();
}

void OptionsTabGeneralMisc::restoreOptions(const Options *opt)
{
	if ( !w )
		return;

	GeneralMiscUI *d = (GeneralMiscUI *)w;

	// chat
	d->ck_chatSays->setChecked( opt->chatSays );
	d->ck_chatSoftReturn->setChecked( opt->chatSoftReturn );

	// misc
#ifdef Q_WS_MAC
	d->ck_alwaysOnTop->setEnabled( false );
#else
	d->ck_alwaysOnTop->setChecked( opt->alwaysOnTop );
#endif
	d->ck_keepSizes->setChecked( opt->keepSizes );
	d->ck_jidComplete->setChecked( opt->jidComplete );
	d->ck_grabUrls->setChecked( opt->grabUrls );

	bg_delChats->setButton( opt->delChats );

	// links
	connect(d->cb_link, SIGNAL(activated(int)), SLOT(selectBrowser(int)));
#ifdef Q_WS_WIN
	d->cb_link->insertItem(tr("Windows Default Browser/Mail"));
	d->cb_link->insertItem(tr("Custom"));
	d->cb_link->setCurrentItem( opt->browser );
	selectBrowser( opt->browser );
#endif
#ifdef Q_WS_X11
	d->cb_link->insertItem(tr("KDE Default Browser/Mail"));
	d->cb_link->insertItem(tr("GNOME2 Default Browser/Mail"));
	d->cb_link->insertItem(tr("Custom"));
	int rbi = om_x11browse[ opt->browser ];
	d->cb_link->setCurrentItem( rbi );
	selectBrowser( rbi );
#endif
#ifdef Q_WS_MAC
	d->cb_link->insertItem(tr("MacOS Default Browser/Mail"));
	d->cb_link->setCurrentItem( opt->browser );
	selectBrowser( opt->browser );
#endif
	d->le_linkBrowser->setText( opt->customBrowser );
	d->le_linkMailer->setText( opt->customMailer );
}

void OptionsTabGeneralMisc::selectBrowser(int x)
{
	if ( !w )
		return;

	bool enableCustom = TRUE;

#ifdef Q_WS_WIN
	if(x == 0)
		enableCustom = FALSE;
#endif
#ifdef Q_WS_X11
	if(x == 0 || x == 1)
		enableCustom = FALSE;
#endif
#ifdef Q_WS_MAC
	if(x == 0)
		enableCustom = FALSE;
#endif

	GeneralMiscUI *d = (GeneralMiscUI *)w;
	d->gb_linkCustom->setEnabled(enableCustom);
}

//----------------------------------------------------------------------------
// OptionsTabGeneralNotifications
//----------------------------------------------------------------------------

OptionsTabGeneralNotifications::OptionsTabGeneralNotifications(QObject *parent)
: OptionsTab(parent, "general_notifications", "general", tr("Notifications"), tr("Configure the popup notifications"))
{
	w = 0;
}

QWidget *OptionsTabGeneralNotifications::widget()
{
	if ( w )
		return 0;

	w = new GeneralNotifyUI();
	//GeneralNotifyUI *d = (GeneralNotifyUI *)w;

	// TODO: add QWhatsThis for all controls on widget

	return w;
}

void OptionsTabGeneralNotifications::applyOptions(Options *opt)
{
	if ( !w )
		return;

	GeneralNotifyUI *d = (GeneralNotifyUI *)w;
	opt->ppIsOn = d->ck_popupOn->isChecked();
	opt->ppMessage = d->ck_popupOnMessage->isChecked();
	opt->ppChat    = d->ck_popupOnChat->isChecked();
	opt->ppHeadline = d->ck_popupOnHeadline->isChecked();
	opt->ppFile    = d->ck_popupOnFile->isChecked();
	opt->ppStatus  = d->ck_popupOnStatus->isChecked();
	opt->ppOnline  = d->ck_popupOnOnline->isChecked();
	opt->ppOffline = d->ck_popupOnOffline->isChecked();
}

void OptionsTabGeneralNotifications::restoreOptions(const Options *opt)
{
	if ( !w )
		return;

	GeneralNotifyUI *d = (GeneralNotifyUI *)w;
	d->ck_popupOn->setChecked( true );
	d->ck_popupOn->setChecked( opt->ppIsOn );
	d->ck_popupOnMessage->setChecked( opt->ppMessage );
	d->ck_popupOnChat->setChecked( opt->ppChat );
	d->ck_popupOnHeadline->setChecked( opt->ppHeadline );
	d->ck_popupOnFile->setChecked( opt->ppFile );
	d->ck_popupOnStatus->setChecked( opt->ppStatus );
	d->ck_popupOnOnline->setChecked( opt->ppOnline );
	d->ck_popupOnOffline->setChecked( opt->ppOffline );
}

//----------------------------------------------------------------------------
// OptionsTabGeneralGroupchat -- TODO: simplify the code
//----------------------------------------------------------------------------

OptionsTabGeneralGroupchat::OptionsTabGeneralGroupchat(QObject *parent)
: OptionsTab(parent, "general_groupchat", "general", tr("Groupchat"), tr("Configure the groupchat"))
{
	w = 0;
}

void OptionsTabGeneralGroupchat::setData(PsiCon *, QWidget *_dlg)
{
	dlg = _dlg;
}

QWidget *OptionsTabGeneralGroupchat::widget()
{
	if ( w )
		return 0;

	w = new GeneralGroupchatUI();
	GeneralGroupchatUI *d = (GeneralGroupchatUI *)w;

	connect(d->pb_nickColor,	   SIGNAL(clicked()), SLOT(chooseGCNickColor()));
	connect(d->lb_nickColors,	   SIGNAL(highlighted(int)), SLOT(selectedGCNickColor()));

	connect(d->pb_addHighlightWord,	   SIGNAL(clicked()), SLOT(addGCHighlight()));
	connect(d->pb_removeHighlightWord, SIGNAL(clicked()), SLOT(removeGCHighlight()));

	connect(d->pb_addNickColor,	   SIGNAL(clicked()), SLOT(addGCNickColor()));
	connect(d->pb_removeNickColor,	   SIGNAL(clicked()), SLOT(removeGCNickColor()));

	// TODO: add QWhatsThis for all controls on widget

	return w;
}

void OptionsTabGeneralGroupchat::applyOptions(Options *opt)
{
	if ( !w )
		return;

	GeneralGroupchatUI *d = (GeneralGroupchatUI *)w;
	opt->gcHighlighting = d->ck_gcHighlights->isChecked();
	opt->gcNickColoring = d->ck_gcNickColoring->isChecked();

	QStringList highlight;
	int i;
	for (i = 0; i < (int)d->lb_highlightWords->count(); i++)
		highlight << d->lb_highlightWords->item(i)->text();
	opt->gcHighlights = highlight;

	QStringList colors;
	for (i = 0; i < (int)d->lb_nickColors->count(); i++)
		colors << d->lb_nickColors->item(i)->text();
	opt->gcNickColors = colors;
}

void OptionsTabGeneralGroupchat::restoreOptions(const Options *opt)
{
	if ( !w )
		return;

	GeneralGroupchatUI *d = (GeneralGroupchatUI *)w;

	// no need to call dataChanged() when these widgets are modified
	disconnect(d->le_newNickColor,     SIGNAL(textChanged(const QString &)), 0, 0);
	disconnect(d->le_newHighlightWord, SIGNAL(textChanged(const QString &)), 0, 0);
	connect(d->le_newNickColor,	   SIGNAL(textChanged(const QString &)), SLOT(displayGCNickColor()));

	d->ck_gcHighlights->setChecked( true );
	d->ck_gcHighlights->setChecked( opt->gcHighlighting );
	d->ck_gcNickColoring->setChecked( true );
	d->ck_gcNickColoring->setChecked( opt->gcNickColoring );
	d->lb_highlightWords->clear();
	d->lb_highlightWords->insertStringList( opt->gcHighlights );
	d->lb_nickColors->clear();

	QStringList::ConstIterator it = opt->gcNickColors.begin();
	for ( ; it != opt->gcNickColors.end(); ++it)
		addNickColor( *it );

	d->le_newHighlightWord->setText("");
	d->le_newNickColor->setText("#FFFFFF");
}

static QPixmap name2color(QString name)
{
	QColor c(name);
	QPixmap pix(16, 16);
	QPainter p(&pix);

	p.fillRect(0, 0, pix.width(), pix.height(), QBrush(c));
	p.setPen( QColor(0, 0, 0) );
	p.drawRect(0, 0, pix.width(), pix.height());
	p.end();

	return pix;
}

void OptionsTabGeneralGroupchat::addNickColor(QString name)
{
	GeneralGroupchatUI *d = (GeneralGroupchatUI *)w;
	d->lb_nickColors->insertItem(name2color(name), name);
}

void OptionsTabGeneralGroupchat::addGCHighlight()
{
	GeneralGroupchatUI *d = (GeneralGroupchatUI *)w;
	if ( d->le_newHighlightWord->text().isEmpty() )
		return;

	d->lb_highlightWords->insertItem( d->le_newHighlightWord->text() );
	d->le_newHighlightWord->setFocus();
	d->le_newHighlightWord->setText("");

	emit dataChanged();
}

void OptionsTabGeneralGroupchat::removeGCHighlight()
{
	GeneralGroupchatUI *d = (GeneralGroupchatUI *)w;
	int id = d->lb_highlightWords->currentItem();
	if ( id == -1 )
		return;

	d->lb_highlightWords->removeItem(id);

	emit dataChanged();
}

void OptionsTabGeneralGroupchat::addGCNickColor()
{
	GeneralGroupchatUI *d = (GeneralGroupchatUI *)w;
	if ( d->le_newNickColor->text().isEmpty() )
		return;

	addNickColor( d->le_newNickColor->text() );
	d->le_newNickColor->setFocus();
	d->le_newNickColor->setText("");

	emit dataChanged();
}

void OptionsTabGeneralGroupchat::removeGCNickColor()
{
	GeneralGroupchatUI *d = (GeneralGroupchatUI *)w;
	int id = d->lb_nickColors->currentItem();
	if ( id == -1 )
		return;

	d->lb_nickColors->removeItem(id);

	emit dataChanged();
}

void OptionsTabGeneralGroupchat::chooseGCNickColor()
{
	GeneralGroupchatUI *d = (GeneralGroupchatUI *)w;
	QColor c = QColorDialog::getColor(QColor(d->le_newNickColor->text()), dlg);
	if ( c.isValid() ) {
		QString cs = c.name();
		d->le_newNickColor->setText(cs);
	}
}

void OptionsTabGeneralGroupchat::selectedGCNickColor()
{
	GeneralGroupchatUI *d = (GeneralGroupchatUI *)w;
	int id = d->lb_nickColors->currentItem();
	if ( id == -1 )
		return;

	d->le_newNickColor->setText( d->lb_nickColors->text(id) );
}

void OptionsTabGeneralGroupchat::displayGCNickColor()
{
	GeneralGroupchatUI *d = (GeneralGroupchatUI *)w;
	d->pb_nickColor->setPixmap( name2color(d->le_newNickColor->text()) );
}
