/* This file is part of the KDE project
   Original file (mailmerge.cpp): Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@kde.org>
   Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org>

   This library 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 library 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 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 "KWClassicSerialDataSource.h"
#include "KWClassicSerialDataSource.moc"
#include "KWMailMergeDataBase.h"
#include <kinputdialog.h>
#include <tqlabel.h>
#include <tqhbox.h>
#include <tqlayout.h>
#include <tqvbox.h>
#include <tqpushbutton.h>
#include <tqlineedit.h>
#include <tqvalidator.h>
#include <tdelocale.h>
#include <kdebug.h>
#include <tqtoolbutton.h>
#include <tqtooltip.h>
#include <kiconloader.h>
#include <tqheader.h>
#include "KWDocument.h"
#include "defs.h"

#define KWSLCPBarIcon( x ) BarIcon( x, db->KWInstance() )

/******************************************************************
 *
 * Class: KWClassicSerialDataSource
 *
 ******************************************************************/

KWClassicSerialDataSource::KWClassicSerialDataSource(TDEInstance *inst,TQObject *parent)
	: KWMailMergeDataSource(inst,parent)
//    : doc( doc_ )
{
}

KWClassicSerialDataSource::~KWClassicSerialDataSource()
{
}

TQString KWClassicSerialDataSource::getValue( const TQString &name, int record ) const
{
    int num = record;
/*    if ( num == -1 )
        num = doc->getMailMergeRecord(); Is this really needed ?*/

    if ( num < 0 || num > (int)db.count() )
        return name;

    return db[ num ][ name ];
}

void KWClassicSerialDataSource::setValue( const TQString &name, const TQString &value, int record )
{
    int num = record;
/*    if ( num == -1 )
        num = doc->getMailMergeRecord(); Is this really needed?*/

    if ( num < 0 || num > (int)db.count() )
        return;

    db[ num ][ name ] = value;
}

void KWClassicSerialDataSource::appendRecord()
{
    DbRecord record( sampleRecord );
    db.append( record );
}

void KWClassicSerialDataSource::addEntry( const TQString &name )
{
    sampleRecord[ name ] = i18n( "No Value" );
    Db::Iterator it = db.begin();
    for ( ; it != db.end(); ++it )
        ( *it )[ name ] = sampleRecord[ name ];
}

void KWClassicSerialDataSource::removeEntry( const TQString &name )
{
    sampleRecord.remove( name );
    Db::Iterator it = db.begin();
    for ( ; it != db.end(); ++it )
        ( *it ).remove( name );
}

void KWClassicSerialDataSource::removeRecord( int i )
{
    if ( (i < 0) || (i > (int)db.count() - 1) )
        return;

	kdDebug()<<TQString("Removing record %1").arg(i)<<endl;

    Db::Iterator it = db.at( i);
    db.remove( it );
}

void KWClassicSerialDataSource::save( TQDomDocument &doc, TQDomElement &parent)
{
	TQDomElement def=doc.createElement(TQString::fromLatin1("DEFINITION"));
	parent.appendChild(def);
	for (DbRecord::Iterator it=sampleRecord.begin();it!=sampleRecord.end();++it)
	{
		TQDomElement defEnt=doc.createElement(TQString::fromLatin1("FIELD"));
		defEnt.setAttribute(TQString::fromLatin1("name"),it.key());
		def.appendChild(defEnt);
	}
	TQDomElement cont=doc.createElement(TQString::fromLatin1("CONTENT"));
	parent.appendChild(cont);
	for (Db::Iterator dbI=db.begin();dbI!=db.end();++dbI)
	{
		TQDomElement rec=doc.createElement(TQString::fromLatin1("RECORD"));
		cont.appendChild(rec);
		for (DbRecord::Iterator it=sampleRecord.begin();it!=sampleRecord.end();++it)
		{
			TQDomElement recEnt=doc.createElement(TQString::fromLatin1("ITEM"));
			recEnt.setAttribute(TQString::fromLatin1("name"),it.key());
			recEnt.setAttribute(TQString::fromLatin1("data"),(*dbI)[it.key()]);
			rec.appendChild(recEnt);
		}
	}
}

void KWClassicSerialDataSource::load( TQDomElement& parentElem )
{
	db.clear();
	sampleRecord.clear();
	TQDomNode defNd=parentElem.namedItem("DEFINITION");
	if (defNd.isNull()) return;
	TQDomElement def=defNd.toElement();
	for (TQDomElement defEnt=def.firstChild().toElement();!defEnt.isNull();defEnt=defEnt.nextSibling().toElement())
	{
		sampleRecord[defEnt.attribute(TQString::fromLatin1("name"))]=i18n( "No Value" );
	}
	TQDomNode contNd=parentElem.namedItem("CONTENT");
	if (contNd.isNull()) return;
	for (TQDomNode rec=contNd.firstChild();!rec.isNull();rec=rec.nextSibling())
	{
		appendRecord();
		for (TQDomElement recEnt=rec.firstChild().toElement();!recEnt.isNull();recEnt=recEnt.nextSibling().toElement())
		{
			setValue(recEnt.attribute(TQString::fromLatin1("name")),
				recEnt.attribute(TQString::fromLatin1("data")),db.count()-1);
		}
	}
}

bool KWClassicSerialDataSource::showConfigDialog(TQWidget *par,int action)
{
   if (action==KWSLCreate)
   {
   	db.clear();
   	sampleRecord.clear();
   }
   KWClassicMailMergeEditor *dia=new KWClassicMailMergeEditor( par, this );
   bool ret=(dia->exec()==TQDialog::Accepted);
   delete dia;
   return ret;
}


/******************************************************************
 *
 * Class: KWClassicMailMergeEditorListItem
 *
 ******************************************************************/

KWClassicMailMergeEditorListItem::KWClassicMailMergeEditorListItem( TQListView *parent )
    : TQListViewItem( parent )
{
    editWidget = new TQLineEdit( listView()->viewport() );
    listView()->addChild( editWidget );
}

KWClassicMailMergeEditorListItem::KWClassicMailMergeEditorListItem( TQListView *parent, TQListViewItem *after )
    : TQListViewItem( parent, after )
{
    editWidget = new TQLineEdit( listView()->viewport() );
    listView()->addChild( editWidget );
}

KWClassicMailMergeEditorListItem::~KWClassicMailMergeEditorListItem()
{
    delete editWidget;
}

void KWClassicMailMergeEditorListItem::setText( int i, const TQString &text )
{
    TQListViewItem::setText( i, text );
    if ( i == 1 )
        editWidget->setText( text );
}

TQString KWClassicMailMergeEditorListItem::text( int i ) const
{
    if ( i == 1 )
        return editWidget->text();
    return TQListViewItem::text( i );
}

void KWClassicMailMergeEditorListItem::setup()
{
    setHeight( TQMAX( listView()->fontMetrics().height(),
                     editWidget->sizeHint().height() ) );
    if ( listView()->columnWidth( 1 ) < editWidget->sizeHint().width() )
        listView()->setColumnWidth( 1, editWidget->sizeHint().width() );
}

void KWClassicMailMergeEditorListItem::update()
{
    editWidget->resize( listView()->header()->cellSize( 1 ), height() );
    listView()->moveChild( editWidget, listView()->header()->cellPos( 1 ),
                           listView()->itemPos( this ) + listView()->contentsY() );
    editWidget->show();
}

/******************************************************************
 *
 * Class: KWClassicMailMergeEditorList
 *
 ******************************************************************/

KWClassicMailMergeEditorList::KWClassicMailMergeEditorList( TQWidget *parent, KWClassicSerialDataSource *db_ )
    : TQListView( parent ), db( db_ )
{
    setSorting( -1 );
    addColumn( i18n( "Name" ) );
    addColumn( i18n( "Value" ) );
    header()->setMovingEnabled( false );
    connect( header(), TQ_SIGNAL( sizeChange( int, int, int ) ),
             this, TQ_SLOT( columnSizeChange( int, int, int ) ) );
//     connect( header(), TQ_SIGNAL( sectionClicked( int ) ),
//           this, TQ_SLOT( sectionClicked( int ) ) );
    disconnect( header(), TQ_SIGNAL( sectionClicked( int ) ),
                this, TQ_SLOT( changeSortColumn( int ) ) );

    currentRecord = -1;
}

void KWClassicMailMergeEditorList::invalidateCurrentRecord()
{
	currentRecord=-1;
}

KWClassicMailMergeEditorList::~KWClassicMailMergeEditorList()
{
    if ( currentRecord == -1 )
        return;

    TQListViewItemIterator lit( this );
    TQMap< TQString, TQString >::ConstIterator it = db->getRecordEntries().begin();
    for ( ; it != db->getRecordEntries().end(); ++it ) {
        TQListViewItem *item = 0;
        item = lit.current();
        ++lit;
        if ( currentRecord != -1 && item )
            db->setValue( it.key(), item->text( 1 ), currentRecord );
    }
}

void KWClassicMailMergeEditorList::columnSizeChange( int c, int, int )
{
    if ( c == 0 || c == 1 )
        updateItems();
}

void KWClassicMailMergeEditorList::sectionClicked( int )
{
    updateItems();
}

void KWClassicMailMergeEditorList::updateItems()
{
    TQListViewItemIterator it( this );
    for ( ; it.current(); ++it )
        ( (KWClassicMailMergeEditorListItem*)it.current() )->update();
}

void KWClassicMailMergeEditorList::displayRecord( int i )
{
    if ( i < 0 || i >= db->getNumRecords() )
        return;

    bool create = !firstChild();
    TQListViewItemIterator lit( this );
    TQMap< TQString, TQString >::ConstIterator it = db->getRecordEntries().begin();
    TQListViewItem *after = 0;
    for ( ; it != db->getRecordEntries().end(); ++it ) {
        TQListViewItem *item = 0;
        if ( create ) {
            item = new KWClassicMailMergeEditorListItem( this, after );
            item->setText( 0, it.key() );
            after = item;
        } else {
            item = lit.current();
            ++lit;
            if ( currentRecord != -1 && item )
                db->setValue( it.key(), item->text( 1 ), currentRecord );
        }

        if ( item )
            item->setText( 1, db->getValue( it.key(), i ) );
    }
    updateItems();
    currentRecord = i;
}

/******************************************************************
 *
 * Class: KWClassicMailMergeEditor
 *
 ******************************************************************/

KWClassicMailMergeEditor::KWClassicMailMergeEditor( TQWidget *parent, KWClassicSerialDataSource *db_ )
    : KDialogBase( Plain, i18n( "Mail Merge - Editor" ), Ok | Cancel, Ok, parent, "", true ), db( db_ )
{
    back = plainPage();

    TQVBoxLayout *l = new TQVBoxLayout( back );
    l->setAutoAdd(true);
    l->setSpacing( KDialog::spacingHint() );

    TQHBox *toolbar = new TQHBox( back );

    first = new TQToolButton( toolbar );
    first->setIconSet( SmallIconSet( "go-first" ) );
    first->setFixedSize( first->sizeHint() );
    connect(first, TQ_SIGNAL(clicked()), this, TQ_SLOT(firstRecord()));

    back_ = new TQToolButton( toolbar );
    back_->setIconSet( SmallIconSet( "back" ) );
    back_->setFixedSize( back_->sizeHint() );
    connect(back_, TQ_SIGNAL(clicked()), this, TQ_SLOT(prevRecord()));

    records = new TQSpinBox( 1, db->getNumRecords(), 1, toolbar );
    records->setMaximumHeight( records->sizeHint().height() );
    connect( records, TQ_SIGNAL( valueChanged( int ) ),
             this, TQ_SLOT( changeRecord( int ) ) );

    forward = new TQToolButton( toolbar );
    forward->setIconSet( SmallIconSet( "forward" ) );
    forward->setFixedSize( forward->sizeHint() );
    connect(forward, TQ_SIGNAL(clicked()), this, TQ_SLOT(nextRecord()));

    finish = new TQToolButton( toolbar );
    finish->setIconSet( SmallIconSet( "go-last" ) );
    finish->setFixedSize( finish->sizeHint() );
    connect(finish, TQ_SIGNAL(clicked()), this, TQ_SLOT(lastRecord()));

    TQWidget *sep = new TQWidget( toolbar );
    sep->setMaximumWidth( 10 );

    newRecord = new TQToolButton( toolbar );
    newRecord->setIconSet( SmallIconSet( "sl_addrecord" ) );
    newRecord->setFixedSize( newRecord->sizeHint() );
    connect( newRecord, TQ_SIGNAL( clicked() ),
             this, TQ_SLOT( addRecord() ) );
    TQToolTip::add( newRecord, i18n( "Add record" ) );

    newEntry = new TQToolButton( toolbar );
    newEntry->setIconSet( SmallIconSet( "sl_addentry" ) );
    newEntry->setFixedSize( newEntry->sizeHint() );
    connect( newEntry, TQ_SIGNAL( clicked() ),
             this, TQ_SLOT( addEntry() ) );
    TQToolTip::add( newEntry, i18n( "Add entry" ) );

    deleteRecord = new TQToolButton( toolbar );
    deleteRecord->setIconSet( SmallIconSet( "sl_delrecord" ) );
    deleteRecord->setFixedSize( deleteRecord->sizeHint() );
    connect( deleteRecord, TQ_SIGNAL( clicked() ),
             this, TQ_SLOT( removeRecord() ) );
    TQToolTip::add( deleteRecord, i18n( "Remove record" ) );

    deleteEntry = new TQToolButton( toolbar );
    deleteEntry->setIconSet( SmallIconSet( "sl_delentry" ) );
    deleteEntry->setFixedSize( deleteEntry->sizeHint() );
    connect( deleteEntry, TQ_SIGNAL( clicked() ),
             this, TQ_SLOT( removeEntry() ) );
    TQToolTip::add( deleteEntry, i18n( "Remove entry" ) );

    dbList = new KWClassicMailMergeEditorList( back, db );

    if ( db->getNumRecords() > 0 ) {
        records->setValue( 1 );
	dbList->displayRecord(0);
//        dbList->updateItems();
    } else {
        first->setEnabled(false);
        back_->setEnabled(false);
        forward->setEnabled(false);
        finish->setEnabled(false);
        newRecord->setEnabled(false);
        deleteEntry->setEnabled(false);
        deleteRecord->setEnabled(false);
        records->setEnabled(true);
    }
    setInitialSize( TQSize( 600, 400 ) );
    updateButton();
}

void KWClassicMailMergeEditor::firstRecord()
{
    records->setValue(1);
    updateButton();
}

void KWClassicMailMergeEditor::prevRecord()
{
    records->setValue(records->value()-1);
    updateButton();
}

void KWClassicMailMergeEditor::nextRecord()
{
    records->setValue(records->value()+1);
    updateButton();
}

void KWClassicMailMergeEditor::lastRecord()
{
    records->setValue(records->maxValue());
    updateButton();
}


void KWClassicMailMergeEditor::updateButton()
{
    int val = records->value();
    first->setEnabled( val > 1);
    back_->setEnabled( val> 1 );
    forward->setEnabled( val < records->maxValue() );
    finish->setEnabled( val < records->maxValue());

}

void KWClassicMailMergeEditor::resizeEvent( TQResizeEvent *e )
{
    KDialogBase::resizeEvent( e );
//    back->resize( size() );
}

void KWClassicMailMergeEditor::changeRecord( int i )
{
    dbList->displayRecord( i - 1 );
}

void KWClassicMailMergeEditor::addEntry()
{
    bool ok;
    TQString value=KInputDialog::getText( i18n("Add Entry"),
					 i18n("Enter entry name:"),
					 TQString(),
					 &ok,
					 this);
    if ((ok) && !value.isEmpty())
    {
        if ( db->getNumRecords() == 0 )
        {
            first->setEnabled(true);
            back_->setEnabled(true);
            forward->setEnabled(true);
            finish->setEnabled(true);
            newRecord->setEnabled(true);
            deleteEntry->setEnabled(true);
            deleteRecord->setEnabled(true);
            records->setEnabled(true);
            addRecord();
        }
        dbList->clear();
        db->addEntry( value );
        changeRecord( records->value() );
        dbList->updateItems();
    }
    updateButton();
}

void KWClassicMailMergeEditor::addRecord()
{
    db->appendRecord();
    records->setRange( records->minValue(), records->maxValue() + 1 );
    records->setValue( db->getNumRecords() );
    updateButton();

}

void KWClassicMailMergeEditor::removeEntry()
{
    TQListViewItem * item = dbList->selectedItem ();
    if ( item )
    {
        db->removeEntry( item->text(0) );
        dbList->clear();
        changeRecord( records->value() );
        dbList->updateItems();
        updateButton();
    }
#if defined( TQ_CC_GNU )
#warning reimplement
#endif
/*
    if ( db->getNumRecords() == 0 )
        return;

    KWMailMergeVariableInsertDia
        *dia = new KWMailMergeVariableInsertDia( this, db );
    if ( dia->exec() == TQDialog::Accepted ) {
        dbList->clear();
        db->removeEntry( dia->getName() );
        changeRecord( records->value() + 1 );
        dbList->updateItems();
    }
    delete dia;
*/
}

void KWClassicMailMergeEditor::removeRecord()
{
    if ( db->getNumRecords() == 0 )
        return;

    db->removeRecord( records->value() - 1 );
    dbList->invalidateCurrentRecord();
    if ( db->getNumRecords() > 0 ) {
        records->setRange( records->minValue(), records->maxValue() - 1 );
        records->setValue( 1 );
        dbList->clear();
        dbList->updateItems();
    } else
    {
        dbList->clear();
        records->setEnabled( false );
    }

    if ( db->getNumRecords() == 0 )
    {
        newRecord->setEnabled(false);
        deleteEntry->setEnabled(false);
        deleteRecord->setEnabled(false);
        records->setEnabled(true);
    }

    updateButton();
}

extern "C" {
	KWORD_MAILMERGE_EXPORT KWMailMergeDataSource *create_kwmailmerge_classic(TDEInstance *inst,TQObject *parent)
	{
		return new KWClassicSerialDataSource(inst,parent);
	}

}
