/* This file is part of the KDE project
   Copyright (C) 2003,2005 Jaroslaw Staniek <js@iidea.pl>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this program; see the file COPYING.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "KexiConnSelector.h"

#include <kexidb/drivermanager.h>
#include <kexidb/connectiondata.h>

#include <kexi.h>
#include "KexiConnSelectorBase.h"
//#include "KexiOpenExistingFile.h"
#include <widget/kexiprjtypeselector.h>
#include <widget/kexidbconnectionwidget.h>

#include <tdeapplication.h>
#include <kiconloader.h>
#include <kmimetype.h>
#include <tdelocale.h>
#include <kdebug.h>
#include <tdeconfig.h>
#include <kurlcombobox.h>
#include <tdetoolbar.h>
#include <tdepopupmenu.h>
#include <tdetoolbarbutton.h>
#include <tdeactionclasses.h>

#include <tqlabel.h>
#include <tqpushbutton.h>
#include <tqlayout.h>
#include <tqcheckbox.h>
#include <tqtooltip.h>
#include <tqtextedit.h>
#include <tqgroupbox.h>
#include <tqwidgetstack.h>
#include <tqbuttongroup.h>

ConnectionDataLVItem::ConnectionDataLVItem(KexiDB::ConnectionData *data, 
	const KexiDB::Driver::Info& info, TQListView *list)
	: TQListViewItem(list)
	, m_data(data)
{
	update(info);
}

ConnectionDataLVItem::~ConnectionDataLVItem() 
{
}

void ConnectionDataLVItem::update(const KexiDB::Driver::Info& info)
{
	setText(0, m_data->caption+"  ");
	const TQString &sfile = i18n("File");
	TQString drvname = info.caption.isEmpty() ? m_data->driverName : info.caption;
	if (info.fileBased)
		setText(1, sfile + " ("+drvname+")  " );
	else
		setText(1, drvname+"  " );
	setText(2, (info.fileBased ? (TQString("<")+sfile.lower()+">") : m_data->serverInfoString(true))+"  " );
}

/*================================================================*/

//! @internal
class KexiConnSelectorWidgetPrivate
{
public:
	KexiConnSelectorWidgetPrivate()
	: conn_sel_shown(false)
	, file_sel_shown(false)
	, confirmOverwrites(true)
	{
	}
	
	TQWidget* openExistingWidget;
	KexiPrjTypeSelector* prjTypeSelector;
	TQString startDirOrVariable;
	TQWidgetStack *stack;
	TQGuardedPtr<KexiDBConnectionSet> conn_set;
	KexiDB::DriverManager manager;
	bool conn_sel_shown;//! helper
	bool file_sel_shown;
	bool confirmOverwrites;
};

/*================================================================*/

KexiConnSelectorWidget::KexiConnSelectorWidget( KexiDBConnectionSet& conn_set, 
	const TQString& startDirOrVariable, TQWidget* parent, const char* name )
	: TQWidget( parent, name )
	,d(new KexiConnSelectorWidgetPrivate())
{
	d->conn_set = &conn_set;
	d->startDirOrVariable = startDirOrVariable;
	TQString none, iconname = KMimeType::mimeType( KexiDB::Driver::defaultFileBasedDriverMimeType() )->icon(none,0);
	const TQPixmap &icon = TDEGlobal::iconLoader()->loadIcon( iconname, TDEIcon::Desktop );
	setIcon( icon );

	TQVBoxLayout* globalLyr = new TQVBoxLayout( this );

	//create header with radio buttons
	d->openExistingWidget = new TQWidget(this, "openExistingWidget");
	TQVBoxLayout* openExistingWidgetLyr = new TQVBoxLayout( d->openExistingWidget );
//	TQLabel* lbl = new TQLabel(i18n("<b>Select existing Kexi project to open:</b>"), openExistingWidget);
//	openExistingWidgetLyr->addWidget( lbl );
	d->prjTypeSelector = new KexiPrjTypeSelector( d->openExistingWidget );
	connect(d->prjTypeSelector->buttonGroup,TQ_SIGNAL(clicked(int)),this,TQ_SLOT(slotPrjTypeSelected(int)));
	openExistingWidgetLyr->addWidget( d->prjTypeSelector );
	openExistingWidgetLyr->addSpacing( KDialogBase::spacingHint() );
	TQFrame* line = new TQFrame( d->openExistingWidget, "line" );
	line->setFrameShape( TQFrame::HLine );
	line->setFrameShadow( TQFrame::Sunken );
	openExistingWidgetLyr->addWidget( line );
	globalLyr->addWidget(d->openExistingWidget);

	d->stack = new TQWidgetStack(this, "stack");
	globalLyr->addWidget(d->stack);

//	m_file = new KexiOpenExistingFile( this, "KexiOpenExistingFile");
//	m_file->btn_advanced->setIconSet( SmallIconSet("1downarrow") );
	m_fileDlg = 0;
		
//	addWidget(m_file);
//	connect(m_file->btn_advanced,TQ_SIGNAL(clicked()),this,TQ_SLOT(showAdvancedConn()));

	m_remote = new KexiConnSelectorBase(d->stack, "conn_sel");
	m_remote->icon->setPixmap( DesktopIcon("network") );
	m_remote->icon->setFixedSize( m_remote->icon->pixmap()->size() );
//	m_remote->btn_back->setIconSet( SmallIconSet("1uparrow") );
	connect(m_remote->btn_add, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotRemoteAddBtnClicked()));
	connect(m_remote->btn_edit, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotRemoteEditBtnClicked()));
	connect(m_remote->btn_remove, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotRemoteRemoveBtnClicked()));
	TQToolTip::add(m_remote->btn_add, i18n("Add a new database connection"));
	TQToolTip::add(m_remote->btn_edit, i18n("Edit selected database connection"));
	TQToolTip::add(m_remote->btn_remove, i18n("Remove selected database connections"));
	d->stack->addWidget(m_remote);
	if (m_remote->layout())
		m_remote->layout()->setMargin(0);
//	connect(m_remote->btn_back,TQ_SIGNAL(clicked()),this,TQ_SLOT(showSimpleConn()));
	connect(m_remote->list,TQ_SIGNAL(doubleClicked(TQListViewItem*)),
		this,TQ_SLOT(slotConnectionItemExecuted(TQListViewItem*)));
	connect(m_remote->list,TQ_SIGNAL(returnPressed(TQListViewItem*)),
		this,TQ_SLOT(slotConnectionItemExecuted(TQListViewItem*)));
	connect(m_remote->list,TQ_SIGNAL(selectionChanged()),
		this,TQ_SLOT(slotConnectionSelectionChanged()));
}

KexiConnSelectorWidget::~KexiConnSelectorWidget()
{
	delete d;
}

/*void KexiConnSelectorWidget::disconnectShowSimpleConnButton()
{
	m_remote->btn_back->disconnect(this,TQ_SLOT(showSimpleConn()));
}*/

void KexiConnSelectorWidget::showAdvancedConn()
{
	slotPrjTypeSelected(2);
	d->prjTypeSelector->buttonGroup->setButton(2);
}

//void KexiConnSelectorWidget::showAdvancedConn()
void KexiConnSelectorWidget::slotPrjTypeSelected(int id)
{
	if (id==1) {//file-based prj type
		showSimpleConn();
	}
	else if (id==2) {//server-based prj type
		if (!d->conn_sel_shown) {
			d->conn_sel_shown=true;
		
			//show connections (on demand):
			for (KexiDB::ConnectionData::ListIterator it(d->conn_set->list()); it.current(); ++it) {
				addConnectionData( it.current() );
	//			else {
	//this error should be more verbose:
	//				kdWarning() << "KexiConnSelector::KexiConnSelector(): no driver found for '" << it.current()->driverName << "'!" << endl;
	//			}
			}
			if (m_remote->list->firstChild()) {
				m_remote->list->setSelected(m_remote->list->firstChild(),true);
			}
			m_remote->descriptionEdit->setPaletteBackgroundColor(palette().active().background());
			m_remote->descGroupBox->layout()->setMargin(2);
			m_remote->list->setFocus();
			slotConnectionSelectionChanged();
		}
		d->stack->raiseWidget(m_remote);
	}
}

ConnectionDataLVItem* KexiConnSelectorWidget::addConnectionData( KexiDB::ConnectionData* data )
{
	const KexiDB::Driver::Info info( d->manager.driverInfo(data->driverName) );
//	if (!info.name.isEmpty()) {
	return new ConnectionDataLVItem(data, info, m_remote->list);
//	}
}

void KexiConnSelectorWidget::showSimpleConn()
{
	d->prjTypeSelector->buttonGroup->setButton(1);
	if (!d->file_sel_shown) {
		d->file_sel_shown=true;
		m_fileDlg = new KexiStartupFileDialog( d->startDirOrVariable, KexiStartupFileDialog::Opening,
			d->stack, "openExistingFileDlg");
		m_fileDlg->setConfirmOverwrites( d->confirmOverwrites );
//		static_cast<TQVBoxLayout*>(m_file->layout())->insertWidget( 2, m_fileDlg );
		d->stack->addWidget(m_fileDlg);

		for (TQWidget *w = parentWidget(true);w;w=w->parentWidget(true)) {
			if (w->isDialog()) {
//#ifndef TQ_WS_WIN
				connect(m_fileDlg,TQ_SIGNAL(rejected()),static_cast<TQDialog*>(w),TQ_SLOT(reject()));
//#endif
//				connect(m_fileDlg,TQ_SIGNAL(cancelled()),static_cast<TQDialog*>(w),TQ_SLOT(reject()));
				break;
			}
		}
	}
	d->stack->raiseWidget(m_fileDlg);
}

int KexiConnSelectorWidget::selectedConnectionType() const
{
	return (d->stack->visibleWidget()==m_fileDlg) ? FileBased : ServerBased;
}

/*ConnectionDataLVItem* KexiConnSelectorWidget::selectedConnectionDataItem() const
{
	if (selectedConnectionType()!=KexiConnSelectorWidget::ServerBased)
		return 0;
	ConnectionDataLVItem *item = 0; // = static_cast<ConnectionDataLVItem*>(m_remote->list->selectedItem());
	for (TQListViewItemIterator it(m_remote->list); it.current(); ++it) {
		if (it.current()->isSelected()) {
			if (item)
				return 0; //multiple
			item = static_cast<ConnectionDataLVItem*>(it.current());
		}
	}
	return item;
}*/

KexiDB::ConnectionData* KexiConnSelectorWidget::selectedConnectionData() const
{
	ConnectionDataLVItem *item = static_cast<ConnectionDataLVItem*>(m_remote->list->selectedItem()); //ConnectionDataItem();
	if (!item)
		return 0;
	return item->data();
}

TQString KexiConnSelectorWidget::selectedFileName()
{
	if (selectedConnectionType()!=KexiConnSelectorWidget::FileBased)
		return TQString();
	return m_fileDlg->currentFileName();
}

void KexiConnSelectorWidget::setSelectedFileName(const TQString& fileName)
{
	if (selectedConnectionType()!=KexiConnSelectorWidget::FileBased)
		return;
	return m_fileDlg->setSelection(fileName);
}

void KexiConnSelectorWidget::slotConnectionItemExecuted(TQListViewItem *item)
{
	emit connectionItemExecuted(static_cast<ConnectionDataLVItem*>(item));
}

void KexiConnSelectorWidget::slotConnectionSelectionChanged()
{
	ConnectionDataLVItem* item = static_cast<ConnectionDataLVItem*>(m_remote->list->selectedItem());
	//update buttons availability
/*	ConnectionDataLVItem *singleItem = 0;
	bool multi = false;
	for (TQListViewItemIterator it(m_remote->list); it.current(); ++it) {
		if (it.current()->isSelected()) {
			if (singleItem) {
				singleItem = 0;
				multi = true;
				break;
			}
			else
				singleItem = static_cast<ConnectionDataLVItem*>(it.current());
		}
	}*/
	m_remote->btn_edit->setEnabled(item);
	m_remote->btn_remove->setEnabled(item);
	m_remote->descriptionEdit->setText(item ? item->data()->description : TQString());
	emit connectionItemHighlighted(item);
}

TQListView* KexiConnSelectorWidget::connectionsList() const
{
	return m_remote->list;
}

void KexiConnSelectorWidget::setFocus()
{
	TQWidget::setFocus();
	if (d->stack->visibleWidget()==m_fileDlg)
		m_fileDlg->setFocus(); //m_fileDlg->locationWidget()->setFocus();
	else
		m_remote->list->setFocus();
}

void KexiConnSelectorWidget::hideHelpers()
{
	d->openExistingWidget->hide();

/*	m_file->lbl->hide();
	m_file->line->hide();
	m_file->spacer->hide();
	m_file->label->hide();
	m_remote->label->hide();
	m_remote->label_back->hide();
	m_remote->btn_back->hide();
	m_remote->icon->hide();*/
}

void KexiConnSelectorWidget::setConfirmOverwrites(bool set)
{
	d->confirmOverwrites = set;
	if (m_fileDlg)
		m_fileDlg->setConfirmOverwrites( d->confirmOverwrites );
}

bool KexiConnSelectorWidget::confirmOverwrites() const
{
	return d->confirmOverwrites;
}

/*static TQString msgUnfinished() { 
	return i18n("To define or change a connection, use command line options or click on .kexis file. "
		"You can find example .kexis file at <a href=\"%1\">here</a>.").arg("") //temporary, please do not change for 0.8!
		+ "\nhttp://www.kexi-project.org/resources/testdb.kexis"; */
//		.arg("http://websvn.kde.org/*checkout*/branches/kexi/0.9/koffice/kexi/tests/startup/testdb.kexis");
//}

void KexiConnSelectorWidget::slotRemoteAddBtnClicked()
{
	KexiDB::ConnectionData data;
	KexiDBConnectionDialog dlg(data, TQString(),
		KGuiItem(i18n("&Add"), "button_ok", i18n("Add database connection")) );
	dlg.setCaption(i18n("Add New Database Connection"));
	if (TQDialog::Accepted!=dlg.exec())
		return;

	//store this conn. data
	KexiDB::ConnectionData *newData = new KexiDB::ConnectionData(*dlg.currentProjectData().connectionData());
	if (!d->conn_set->addConnectionData(newData)) {
		//! @todo msg?
		delete newData;
		return;
	}

	ConnectionDataLVItem* item = addConnectionData(newData);
//	m_remote->list->clearSelection();
	m_remote->list->setSelected(item, true);
	slotConnectionSelectionChanged();
}

void KexiConnSelectorWidget::slotRemoteEditBtnClicked()
{
	ConnectionDataLVItem* item = static_cast<ConnectionDataLVItem*>(m_remote->list->selectedItem());
	if (!item)
		return;
	KexiDBConnectionDialog dlg(*item->data(), TQString(),
		KGuiItem(i18n("&Save"), "document-save", i18n("Save changes made to this database connection")) );
	dlg.setCaption(i18n("Edit Database Connection"));
	if (TQDialog::Accepted!=dlg.exec())
		return;

	KexiDB::ConnectionData *newData = new KexiDB::ConnectionData( *dlg.currentProjectData().connectionData() );
	if (!d->conn_set->saveConnectionData(item->data(), newData)) {
		//! @todo msg?
		delete newData;
		return;
	}
	const KexiDB::Driver::Info info( d->manager.driverInfo(item->data()->driverName) );
	item->update(info);
	slotConnectionSelectionChanged(); //to update descr. edit
}

void KexiConnSelectorWidget::slotRemoteRemoveBtnClicked()
{
	ConnectionDataLVItem* item = static_cast<ConnectionDataLVItem*>(m_remote->list->selectedItem());
	if (!item)
		return;
	if (KMessageBox::Continue!=KMessageBox::warningContinueCancel(0, 
		i18n("Do you want to remove database connection \"%1\" from the list of available connections?")
		.arg(item->data()->serverInfoString(true)), TQString(), KStdGuiItem::del(), TQString(), 
		KMessageBox::Notify|KMessageBox::Dangerous))
		return;

	TQListViewItem* nextItem = item->itemBelow();
	if (!nextItem)
		nextItem = item->itemAbove();
	if (!d->conn_set->removeConnectionData(item->data()))
		return;

	m_remote->list->removeItem(item);
	if (nextItem)
		m_remote->list->setSelected(nextItem, true);
	slotConnectionSelectionChanged();
}

void KexiConnSelectorWidget::hideConnectonIcon()
{
	m_remote->icon->setFixedWidth(0);
	m_remote->icon->setPixmap(TQPixmap());
}

#include "KexiConnSelector.moc"
