/* dbViewerWidget.cc		KPilot
**
** Copyright (C) 2003 by Dan Pilone.
** Copyright (C) 2003 Reinhold Kainhofer <reinhold@kainhofer.com>
**	Written 2003 by Reinhold Kainhofer and Adriaan de Groot
**
** This is the generic DB viewer widget.
*/

/*
** 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 in a file called COPYING; if not, write to
** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
** MA 02110-1301, USA.
*/

/*
** Bug reports and questions can be sent to kde-pim@kde.org
*/


#include "options.h"

#include <unistd.h>
#include <stdio.h>

#include <pi-file.h>
#include <pi-dlp.h>

#include <tqlayout.h>
#include <tqdir.h>
#include <tqregexp.h>
#include <tqlistview.h>

#include <klistbox.h>
#include <ktextedit.h>
#include <kpushbutton.h>
#include <kcombobox.h>
#include <kmessagebox.h>

#include "listCat.h"
#include "listItems.h"

#include "dbviewerWidget.h"
#include "pilotLocalDatabase.h"
#include "pilotDatabase.h"
#include "pilotRecord.h"
#include "dbFlagsEditor.h"
#include "dbRecordEditor.h"
#include "dbAppInfoEditor.h"
#include "kpilotConfig.h"


#include "dbviewerWidget.moc"


GenericDBWidget::GenericDBWidget(TQWidget *parent, const TQString &dbpath) :
	PilotComponent(parent,"component_generic",dbpath), fDB(0L)
{
	FUNCTIONSETUP;
	setupWidget();
	fRecList.setAutoDelete(true);
}


void GenericDBWidget::setupWidget()
{
	TQGridLayout *g = new TQGridLayout( this, 1, 1, SPACING);

	fDBList = new KListBox( this );
	g->addWidget( fDBList, 0, 0 );
	fDBType = new KComboBox( FALSE, this );
	g->addWidget( fDBType, 1, 0 );
	fDBType->insertItem( i18n( "All Databases" ) );
	fDBType->insertItem( i18n( "Only Applications (*.prc)" ) );
	fDBType->insertItem( i18n( "Only Databases (*.pdb)" ) );

	TQGridLayout *g1 = new TQGridLayout( 0, 1, 1);
	fDBInfo = new KTextEdit( this );
	fDBInfo->setSizePolicy( TQSizePolicy( (TQSizePolicy::SizeType)3, (TQSizePolicy::SizeType)0, 0, 0, fDBInfo->sizePolicy().hasHeightForWidth() ) );
	fDBInfo->setReadOnly( TRUE );
	g1->addWidget( fDBInfo, 0, 0 );
	fDBInfoButton = new KPushButton( i18n( "General Database &Information" ), this );
	g1->addWidget( fDBInfoButton, 1, 0 );
	fAppInfoButton = new KPushButton( i18n( "&Application Info Block (Categories etc.)" ), this );
	g1->addWidget( fAppInfoButton, 2, 0 );

	TQGridLayout *g2 = new TQGridLayout( 0, 1, 1);
	fRecordList = new KListView( this );
	g2->addMultiCellWidget( fRecordList, 0, 0, 0, 2 );
	fRecordList->addColumn(i18n("Rec. Nr."));
	fRecordList->addColumn(i18n("Length"));
	fRecordList->addColumn(i18n("Record ID"));
	fRecordList->setAllColumnsShowFocus(true);
	fRecordList->setResizeMode( KListView::LastColumn );
	fRecordList->setFullWidth( TRUE );
	fRecordList->setItemsMovable( FALSE );

	fAddRecord = new KPushButton( i18n("&Add..."), this );
	g2->addWidget( fAddRecord, 1, 0 );
	fEditRecord = new KPushButton( i18n("&Edit..."), this );
	g2->addWidget( fEditRecord, 1, 1 );
	fDeleteRecord = new KPushButton( i18n("&Delete"), this );
	g2->addWidget( fDeleteRecord, 1, 2 );

	g1->addLayout( g2, 3, 0 );


	g->addMultiCellLayout( g1, 0, 1, 1, 1 );
	resize( TQSize(682, 661).expandedTo(minimumSizeHint()) );

	connect(fDBList, TQT_SIGNAL(highlighted(const TQString &)),
		this, TQT_SLOT(slotSelected(const TQString &)));
	connect(fDBType, TQT_SIGNAL(activated(int)),
		this, TQT_SLOT(slotDBType(int)));
	connect(fDBInfoButton,  TQT_SIGNAL(clicked()),
		this, TQT_SLOT(slotShowDBInfo()));
	connect(fAppInfoButton,  TQT_SIGNAL(clicked()),
		this, TQT_SLOT(slotShowAppInfo()));
	connect(fAddRecord,  TQT_SIGNAL(clicked()),
		this, TQT_SLOT(slotAddRecord()));
	connect(fEditRecord,  TQT_SIGNAL(clicked()),
		this, TQT_SLOT(slotEditRecord()));
	connect(fDeleteRecord,  TQT_SIGNAL(clicked()),
		this, TQT_SLOT(slotDeleteRecord()));
	connect(fRecordList, TQT_SIGNAL(executed(TQListViewItem*)),
		this, TQT_SLOT(slotEditRecord(TQListViewItem*)));

}

GenericDBWidget::~GenericDBWidget()
{
	FUNCTIONSETUP;
	if (fDB) KPILOT_DELETE(fDB);
}


void GenericDBWidget::showComponent()
{
	FUNCTIONSETUP;
	fDBInfo->setText(TQString());
	slotDBType(0);

	fDBList->show();
	fDBInfo->show();
}

void GenericDBWidget::hideComponent()
{
	reset();
}

void GenericDBWidget::slotSelected(const TQString &dbname)
{
	FUNCTIONSETUP;
#ifdef DEBUG
	DEBUGKPILOT << fname << ": Selected DB " << dbname << endl;
#endif
	struct DBInfo dbinfo;
	TQString display;
	fRecList.clear();
	fRecordList->clear();

	if (fDB) KPILOT_DELETE(fDB);
	currentDB=dbname;

	if (!shown) return;

	if (dbname.endsWith(CSL1(".pdb")) || dbname.endsWith(CSL1(".PDB")))
	{
		// We are dealing with a database
		currentDBtype=eDatabase;

		currentDB.remove( TQRegExp(CSL1(".(pdb|PDB)$")) );

		fDB=new PilotLocalDatabase(dbPath(), currentDB, false);
		if (!fDB || !fDB->isOpen())
		{
			fDBInfo->setText(i18n("<B>Warning:</B> Cannot read "
				"database file %1.").arg(currentDB));
			return;
		}
		dbinfo=fDB->getDBInfo();
		display.append(i18n("<B>Database:</B> %1, %2 records<BR>")
			.arg(TQString::fromLatin1(dbinfo.name)).arg(fDB->recordCount()));
		char buff[5];
		set_long(buff, dbinfo.type);
		buff[4]='\0';
		TQString tp = TQString::fromLatin1(buff);
		set_long(buff, dbinfo.creator);
		buff[4]='\0';
		TQString cr = TQString::fromLatin1(buff);
		display.append(i18n("<B>Type:</B> %1, <B>Creator:</B> %2<br><br>").arg(tp).arg(cr));

		int currentRecord = 0;
		PilotRecord *pilotRec;

#ifdef DEBUG
		DEBUGKPILOT << fname << ": Reading database "<<dbname<<"..." << endl;
#endif

		while ((pilotRec = fDB->readRecordByIndex(currentRecord)) != 0L)
		{
//			if (!(pilotRec->isDeleted()) )
			{
				PilotListViewItem*item=new PilotListViewItem(fRecordList,
					TQString::number(currentRecord), TQString::number(pilotRec->size()),
					TQString::number(pilotRec->id()),
					TQString(),
					pilotRec->id(), pilotRec);
				item->setNumericCol(0, true);
				item->setNumericCol(1, true);
				item->setNumericCol(2, true);
			}
			fRecList.append(pilotRec);

			currentRecord++;
		}

#ifdef DEBUG
		DEBUGKPILOT << fname
			<< ": Total " << currentRecord << " records" << endl;
#endif

	}
	else
	{
		// we are dealing with an application
		currentDBtype=eApplication;

		TQCString filename = TQFile::encodeName(dbPath() + CSL1("/") + dbname);
		const char *s = filename;
		struct pi_file *pf = pi_file_open(const_cast<char *>(s));
		if (!pf)
		{
			fDBInfo->setText(i18n("<B>Warning:</B> Cannot read "
				"application file %1.").arg(dbname));
			return;
		}
#if PILOT_LINK_NUMBER < PILOT_LINK_0_12_0
		if (pi_file_get_info(pf,&dbinfo))
		{
			fDBInfo->setText(i18n("<B>Warning:</B> Cannot read "
				"application file %1.").arg(dbname));
			return;
		}
#else
		pi_file_get_info(pf,&dbinfo);
#endif
		display.append(i18n("<B>Application:</B> %1<BR><BR>").arg(dbname));
	}
	enableWidgets(currentDBtype==eDatabase);

	TQDateTime ttime;

	ttime.setTime_t(dbinfo.createDate);
	display.append(i18n("Created: %1<BR>").arg(ttime.toString()));

	ttime.setTime_t(dbinfo.modifyDate);
	display.append(i18n("Modified: %1<BR>").arg(ttime.toString()));

	ttime.setTime_t(dbinfo.backupDate);
	display.append(i18n("Backed up: %1<BR>").arg(ttime.toString()));

	fDBInfo->setText(display);
}

void GenericDBWidget::slotDBType(int mode)
{
	FUNCTIONSETUP;
	if (!shown) return;

	reset();

	TQDir dir(dbPath());
	switch (mode)
	{
		case 1:
			dir.setNameFilter(CSL1("*.prc")); break;
		case 2:
			dir.setNameFilter(CSL1("*.pdb")); break;
		case 0:
		default:
			dir.setNameFilter(CSL1("*.pdb;*.prc")); break;
	}
	TQStringList l = dir.entryList();
	fDBList->insertStringList(l);
}

void GenericDBWidget::reset()
{
	FUNCTIONSETUP;
	fDBList->clear();
	fDBInfo->clear();
	fRecordList->clear();
	if (fDB)  KPILOT_DELETE(fDB);
	currentDB=TQString();
}

void GenericDBWidget::slotAddRecord()
{
	FUNCTIONSETUP;
	pi_buffer_t *b = pi_buffer_new(0);
	PilotRecord *rec=new PilotRecord(b, 0, 0, 0);
	PilotListViewItem*item=new PilotListViewItem(fRecordList,
		TQString::number(-1), TQString::number(rec->size()),
		TQString::number(rec->id()), TQString(),
		rec->id(), rec);
	if (slotEditRecord(item))
	{
		fRecList.append(rec);
	}
	else
	{
		KPILOT_DELETE(item);
		KPILOT_DELETE(rec);
	}
}

bool GenericDBWidget::slotEditRecord(TQListViewItem*item)
{
	FUNCTIONSETUP;
	PilotListViewItem*currRecItem=dynamic_cast<PilotListViewItem*>(item);
	if (currRecItem)
	{
		PilotRecord*rec=(PilotRecord*)currRecItem->rec();
		int nr=currRecItem->text(0).toInt();
		DBRecordEditor*dlg=new DBRecordEditor(rec, nr, this);
		if (dlg->exec())
		{
			currRecItem->setText(1, TQString::number(rec->size()));
			currRecItem->setText(2, TQString::number(rec->id()));
			fRecordList->triggerUpdate();
			writeRecord(rec);
			KPILOT_DELETE(dlg);
			return true;
		}
		KPILOT_DELETE(dlg);
	}
	else
	{
		// Either nothing selected, or some error occurred...
		KMessageBox::information(this, i18n("You must select a record for editing."), i18n("No Record Selected"), CSL1("norecordselected"));
	}
	return false;
}
void GenericDBWidget::slotEditRecord()
{
	slotEditRecord(fRecordList->selectedItem());
}

void GenericDBWidget::slotDeleteRecord()
{
	FUNCTIONSETUP;
	PilotListViewItem*currRecItem=dynamic_cast<PilotListViewItem*>(fRecordList->selectedItem());
	if (currRecItem && (KMessageBox::questionYesNo(this, i18n("<qt>Do you really want to delete the selected record? This cannot be undone.<br><br>Delete record?<qt>"), i18n("Deleting Record"), KStdGuiItem::del(), KStdGuiItem::cancel())==KMessageBox::Yes) )
	{
		PilotRecord*rec=(PilotRecord*)currRecItem->rec();
		rec->setDeleted();
		writeRecord(rec);
		// fRecordList->triggerUpdate();
		KPILOT_DELETE(currRecItem);
	}
}

void GenericDBWidget::slotShowAppInfo()
{
	FUNCTIONSETUP;
	if (!fDB) return;
	char*appBlock=new char[0xFFFF];
	int len=fDB->readAppBlock((unsigned char*)appBlock, 0xFFFF);
	DBAppInfoEditor*dlg=new DBAppInfoEditor(appBlock, len, this);
	if (dlg->exec())
	{
		fDB->writeAppBlock( (unsigned char*)(dlg->appInfo), dlg->len );

		KPilotConfig::addAppBlockChangedDatabase(getCurrentDB());
		KPilotSettings::writeConfig();
	}
	KPILOT_DELETE(dlg);
	delete[] appBlock;
}

void GenericDBWidget::slotShowDBInfo()
{
	FUNCTIONSETUP;
	if ( !fDB || !shown ) return;
	DBInfo db=fDB->getDBInfo();
	DBFlagsEditor*dlg=new DBFlagsEditor(&db, this);
	if (dlg->exec())
	{
#ifdef DEBUG
		DEBUGKPILOT<<"OK pressed, assiging DBInfo, flags="<<
			db.flags<<",  miscFlag="<<db.miscFlags<<endl;
#endif
		fDB->setDBInfo(db);

		KPilotConfig::addFlagsChangedDatabase(getCurrentDB());
		KPilotSettings::writeConfig();

		slotSelected(fDBList->currentText());
	}
	KPILOT_DELETE(dlg);
}

void GenericDBWidget::enableWidgets(bool enable)
{
	//FUNCTIONSETUP;
	fDBInfoButton->setEnabled(enable);
	fAppInfoButton->setEnabled(enable);
	fRecordList->setEnabled(enable);
	fAddRecord->setEnabled(enable);
	fEditRecord->setEnabled(enable);
	fDeleteRecord->setEnabled(enable);
}

void GenericDBWidget::writeRecord(PilotRecord*r)
{
	// FUNCTIONSETUP;
	if (fDB && r)
	{
		fDB->writeRecord(r);
		markDBDirty(getCurrentDB());
	}
}





