/* This file is part of the KDE project
   Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@kde.org>

   Modified by Joseph wenninger, 2001

   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 "KWDocument.h"
#include "KWMailMergeDataBase.h"
#include "KWMailMergeDataBase.moc"
#include <KoCustomVariablesDia.h>
#include "defs.h"

#include <tdelocale.h>
#include <kdebug.h>
#include <kstdaction.h>
#include <tdeaction.h>
#include <tdemessagebox.h>
#include <kseparator.h>
#include <kservice.h>
#include <tdemainwindow.h>

#include <tqfile.h>
#include <tqvbox.h>
#include <tqspinbox.h>
#include <tqlayout.h>
#include <tqlabel.h>
#include <tqpushbutton.h>

/******************************************************************
 *
 * Class: KWMailMergeDataBase
 *
 ******************************************************************/

KWMailMergeDataBase::KWMailMergeDataBase( KWDocument *doc_ )
    : TQObject(doc_,doc_->dcopObject()->objId()+".MailMergeDataBase"),
    KWordMailMergeDatabaseIface(TQCString(doc_->dcopObject()->objId()+".MailMergeDataBase")),
      m_version(0),
      doc( doc_ )
{
   plugin=0; //loadPlugin("classic");
   rejectdcopcall=false;
}

TQStringList KWMailMergeDataBase::availablePlugins()
{
    TQStringList tmp;
    TDETrader::OfferList pluginOffers=TDETrader::self()->query(TQString::fromLatin1("KWord/MailMergePlugin"),TQString());
    for (TDETrader::OfferList::Iterator it=pluginOffers.begin();*it;++it)
    {
        tmp.append((*it)->property("X-TDE-InternalName").toString());
        kdDebug()<<"Found mail merge plugin: "<< (*it)->name()<<endl;
    }
    return tmp;
}

bool KWMailMergeDataBase::isConfigDialogShown()
{
    return rejectdcopcall;
}

bool KWMailMergeDataBase::loadPlugin(const TQString &name,const TQString &command)
{
    if (rejectdcopcall)return false;
    TQString constrain=TQString("[X-TDE-InternalName] =='"+name+"'");
    kdDebug()<<constrain<<endl;
    TDETrader::OfferList pluginOffers=TDETrader::self()->query(TQString::fromLatin1("KWord/MailMergePlugin"),constrain);
    KService::Ptr it=pluginOffers.first();

    TQVariant verProp=it->property("X-TDE-PluginVersion");
    int version=verProp.toInt();

    if (it)
    {
        KWMailMergeDataSource *tmp=loadPlugin(it->library());
        if (!tmp)
        {
            kdDebug()<<"Couldn't load plugin"<<endl;
            return false; //Plugin couldn't be loaded
        }
        //Plugin found and loaded
        if (command=="silent") {
            return  askUserForConfirmationAndConfig(tmp,false,0,version);
        }
        else
        {
            if (command=="open") action=KWSLOpen;
            else if (command=="create") action=KWSLCreate;
            else action=KWSLUnspecified;
            return askUserForConfirmationAndConfig(tmp,true,0,version);
        }
    }
    else
    {
        kdDebug()<<"No plugin found"<<endl;
        return false; //No plugin with specified name found
    }
}

KWMailMergeDataSource *KWMailMergeDataBase::openPluginFor(int type,int &version)
{
    version=0;
    KWMailMergeDataSource *ret=0;
    TQString constrain=TQString("'%1' in [X-TDE-Capabilities]").arg(((type==KWSLCreate)?KWSLCreate_text:KWSLOpen_text));
    kdDebug()<<constrain<<endl;
    TDETrader::OfferList pluginOffers=TDETrader::self()->query(TQString::fromLatin1("KWord/MailMergePlugin"),constrain);

    //Only for debugging
    for (TDETrader::OfferList::Iterator it=pluginOffers.begin();*it;++it)
    {
        kdDebug()<<"Found mail merge plugin: "<< (*it)->name()<<endl;
    }

    if (!pluginOffers.count())
    {
        //Sorry no suitable plugins found
        kdDebug()<<"No plugins found"<<endl;
        KMessageBox::sorry(0,i18n("No plugins supporting the requested action were found."));
    }
    else
    {

        KWMailMergeChoosePluginDialog *dia=new KWMailMergeChoosePluginDialog(pluginOffers);
        if (dia->exec()==TQDialog::Accepted)
        {
            TQVariant verProp=(*(pluginOffers.at(dia->currentPlugin())))->property("X-TDE-PluginVersion");
            version=verProp.toInt();

            ret=loadPlugin((*(pluginOffers.at(dia->currentPlugin())))->library());
        }

    }
    return ret;
}

KWMailMergeDataSource *KWMailMergeDataBase::loadPlugin(const TQString& name)
{
  if (!name.isEmpty())
  {
      // get the library loader instance

      KLibLoader *loader = KLibLoader::self();

      // try to load the library
      TQString libname=name;
//      TQString libname("lib%1");
      KLibrary *lib = loader->library(TQFile::encodeName(libname));
      if (lib) {
          // get the create_ function
          TQString factory=TQString("create_%1").arg(name);
          void *create = lib->symbol(TQFile::encodeName(factory));

          if (create)
          {
              // create the module
              KWMailMergeDataSource * (*func)(TDEInstance*,TQObject*);
              func = (KWMailMergeDataSource* (*)(TDEInstance*,TQObject*)) create;
              KWMailMergeDataSource *tmpsource =func(KWFactory::instance(),this);
              if (tmpsource)
              {
                  TQDataStream tmpstream(tmpsource->info,IO_WriteOnly);
                  tmpstream<<name;
              }
              return tmpsource;
          }
      }
      kdWarning() << "Couldn't load plugin " << name <<  endl;
  }
  else
      kdWarning()<< "No plugin name specified" <<endl;
  return 0;
}

bool KWMailMergeDataBase::isSampleRecord() {
    return (0>doc->mailMergeRecord());
}

TQString KWMailMergeDataBase::getValue( const TQString &name, int record ) const
{
    if (plugin)
    {
        if (record==-1) record=doc->mailMergeRecord();
        return plugin->getValue(name,record);
    }
    else
        return TQString("");
}


void KWMailMergeDataBase::refresh(bool force)
{
    if (plugin) plugin->refresh(force);
}

const TQMap< TQString, TQString > &KWMailMergeDataBase::getRecordEntries() const
{
    if (plugin)
        return plugin->getRecordEntries();
    else
        return emptyMap;
}

int KWMailMergeDataBase::getNumRecords() const
{
    if (plugin)
        return plugin->getNumRecords();
    else
        return 0;

}


void KWMailMergeDataBase::showConfigDialog(TQWidget *par)
{
    rejectdcopcall=true;
    KWMailMergeConfigDialog *dia=new KWMailMergeConfigDialog(par,this);
    dia->exec();
    delete dia;
    rejectdcopcall=false;
}


bool KWMailMergeDataBase::askUserForConfirmationAndConfig(KWMailMergeDataSource *tmpPlugin,bool config,TQWidget *par,int version)
{
    if (tmpPlugin)
    {
        bool replaceit=false;
        if (!config) replaceit=true;
        else
            replaceit=tmpPlugin->showConfigDialog(par,action);
        if (replaceit)
        {
            if (plugin)
            {
                if (KMessageBox::warningContinueCancel(par,
                            i18n("Do you really want to replace the current datasource?"),
                            TQString(),TQString(),TQString(),true)== KMessageBox::Cancel)
                {
                    delete tmpPlugin;
                    tmpPlugin=0;
                    return false;
                }
                delete plugin;
            }
            m_version=version;
            plugin=tmpPlugin;
        }
        else
        {
            delete tmpPlugin;
            tmpPlugin=0;
            return false;
        }
    }
    tmpPlugin->setObjId(TQCString(objId()+".MailMergePlugin"));
    return true;
}



TQDomElement KWMailMergeDataBase::save(TQDomDocument &doc) const
{
    kdDebug()<<"KWMailMergeDataBase::save()"<<endl;
    TQDomElement parentElem=doc.createElement("MAILMERGE");
    if (plugin)
    {
        kdDebug()<<"KWMailMergeDataBase::save() There is really something to save"<<endl;
        TQDomElement el=doc.createElement(TQString::fromLatin1("PLUGIN"));

        TQDataStream ds(plugin->info,IO_ReadOnly);
        TQString libname;
        ds>>libname;
        el.setAttribute("library",libname);
        parentElem.appendChild(el);
        kdDebug()<<"KWMailMergeDataBase::save() Calling datasource save()"<<endl;
        TQDomElement el2=doc.createElement(TQString::fromLatin1("DATASOURCE"));
        plugin->save(doc,el2);
        parentElem.appendChild(el2);

    }
    kdDebug()<<"KWMailMergeDataBase::save() leaving now"<<endl;
    return parentElem;
    // if (plugin) plugin->save(parentElem); // Not completely sure, perhaps the database itself has to save something too (JoWenn)
}

void KWMailMergeDataBase::load( const TQDomElement& parentElem )
{
    TQDomNode dn=parentElem.namedItem("PLUGIN");
    if (dn.isNull()) return;
    TQDomElement el=dn.toElement();
    plugin=loadPlugin(el.attribute("library"));

    dn=parentElem.namedItem("DATASOURCE");
    if (dn.isNull()) return;
    el=dn.toElement();
    if (plugin) plugin->load(el);
}


int KWMailMergeDataBase::version() {
    kdDebug()<<"KWMailMergeDataBase::version:"<<m_version<<endl;
    return m_version;
}


/******************************************************************
 *
 * Class: KWMailMerge ChoosePluginDialog
 *
 ******************************************************************/

KWMailMergeChoosePluginDialog::KWMailMergeChoosePluginDialog( TDETrader::OfferList offers )
    : KDialogBase( Plain, i18n( "Mail Merge Setup" ), Ok | Cancel, Ok,
      /*parent*/ 0, "", true ), pluginOffers( offers )
{
  TQWidget *back = plainPage();
  TQVBoxLayout *layout = new TQVBoxLayout( back, 0, spacingHint() );

  TQLabel *label = new TQLabel( i18n( "&Available sources:" ), back );
  chooser = new TQComboBox( false, back );
  label->setBuddy( chooser );
  descriptionLabel = new TQLabel( back );
  descriptionLabel->hide();
  descriptionLabel->setAlignment( WordBreak );
  descriptionLabel->setFrameShape( TQFrame::Box );
  descriptionLabel->setFrameShadow( TQFrame::Sunken );

  TQSize old_sizeHint;
  for ( TDETrader::OfferList::Iterator it = pluginOffers.begin(); *it; ++it )
  {
    chooser->insertItem( (*it)->name() );
    old_sizeHint = descriptionLabel->sizeHint();
    descriptionLabel->setText( (*it)->comment() );
    if (descriptionLabel->sizeHint().width()*descriptionLabel->sizeHint().height() > old_sizeHint.width()*old_sizeHint.height())
        descriptionLabel->setMinimumSize(descriptionLabel->sizeHint() );
  }
  descriptionLabel->show();

  connect( chooser, TQT_SIGNAL( activated( int ) ),
           this, TQT_SLOT( pluginChanged( int ) ) );

  layout->addWidget( label );
  layout->addWidget( chooser );
  layout->addWidget( descriptionLabel );
  layout->addStretch( 1 );

  pluginChanged( 0 );
}

KWMailMergeChoosePluginDialog::~KWMailMergeChoosePluginDialog()
{
}

int KWMailMergeChoosePluginDialog::currentPlugin() const
{
  return chooser->currentItem();
}

void KWMailMergeChoosePluginDialog::pluginChanged( int pos )
{
  descriptionLabel->setText( (*pluginOffers.at( pos ))->comment() );
}

/******************************************************************
 *
 * Class: KWMailMergeConfigDialog
 *
 ******************************************************************/

KWMailMergeConfigDialog::KWMailMergeConfigDialog(TQWidget *parent,KWMailMergeDataBase *db)
    : KDialogBase(Plain, i18n( "Mail Merge Setup" ), Close, Close, parent, "", true )
{
    db_=db;
    TQWidget *back = plainPage();
    TQVBoxLayout *layout=new TQVBoxLayout(back);
//    TQVBox *back = new TQVBox( page );
    layout->setSpacing( KDialog::spacingHint() );

//    TQVBox *row1 = new TQVBox( back );
//    row1->setSpacing( KDialog::spacingHint() );

    TQLabel *l = new TQLabel( i18n( "Datasource:" ),back );
//    l->setMaximumHeight( l->sizeHint().height() );
    layout->addWidget(l);

    TQHBox *row1=new TQHBox(back);
    layout->addWidget(row1);
    row1->setSpacing( KDialog::spacingHint() );
    edit=new TQPushButton(i18n("Edit Current..."),row1);
    create=new TQPushButton(i18n("Create New..."),row1);
    open=new TQPushButton(i18n("Open Existing..."),row1);

    KSeparator *separator1 = new KSeparator(back);
    layout->addWidget(separator1);

    l = new TQLabel( i18n( "Merging:" ),back );
    layout->addWidget(l);
//  l->setMaximumHeight( l->sizeHint().height() );
    TQHBox *row2=new TQHBox(back);
    layout->addWidget(row2);
    row2->setSpacing( KDialog::spacingHint() );
    preview=new TQPushButton(i18n("Print Preview..."),row2);
    document=new TQPushButton(i18n("Create New Document"),row2);
    document->hide();
    (void) new TQWidget(row2);
    layout->addStretch();

    KSeparator *separator2 = new KSeparator(back);
    layout->addWidget(separator2);

    enableDisableEdit();

    connect(edit,TQT_SIGNAL(clicked()), this, TQT_SLOT(slotEditClicked()));
    connect(create,TQT_SIGNAL(clicked()),this,TQT_SLOT(slotCreateClicked()));
    connect(open,TQT_SIGNAL(clicked()),this,TQT_SLOT(slotOpenClicked()));
    connect(preview,TQT_SIGNAL(clicked()),this,TQT_SLOT(slotPreviewClicked()));
    connect(document,TQT_SIGNAL(clicked()),this,TQT_SLOT(slotDocumentClicked()));
}

void KWMailMergeConfigDialog::enableDisableEdit()
{
    if (!db_->plugin)
    {
        preview->setEnabled(false);
        document->setEnabled(false);
        edit->setEnabled(false);
    }
    else
    {
        preview->setEnabled(true);
        document->setEnabled(true);
        edit->setEnabled(true);
    }
}

void KWMailMergeConfigDialog::slotEditClicked()
{db_->action=KWSLEdit;
 if (db_->plugin) db_->plugin->showConfigDialog((TQWidget*)parent(),KWSLEdit);
}

void KWMailMergeConfigDialog::slotCreateClicked()
{
    db_->action=KWSLCreate;
    doNewActions();
//done(TQDialog::Accepted);
}

void KWMailMergeConfigDialog::doNewActions()
{
    int tmpVersion;
    KWMailMergeDataSource *tmpPlugin=db_->openPluginFor(db_->action,tmpVersion);
    if (tmpPlugin)
    {
        if (db_->askUserForConfirmationAndConfig(tmpPlugin,true,this,tmpVersion))

            enableDisableEdit();
    }
}


void KWMailMergeConfigDialog::slotOpenClicked()
{
    db_->action=KWSLOpen;
    doNewActions();
}

void KWMailMergeConfigDialog::slotPreviewClicked()
{
    db_->action=KWSLMergePreview;
    TDEMainWindow *mw=dynamic_cast<TDEMainWindow*>(((TQWidget *)parent())->topLevelWidget());
    if (mw)
    {
        TDEAction *ac=mw->actionCollection()->action(KStdAction::stdName(KStdAction::PrintPreview));
        if (ac) ac->activate();
        else kdWarning()<<"Toplevel doesn't provide a print preview action"<<endl;
    }
    else
        kdWarning()<<"Toplevel is no TDEMainWindow->no preview"<<endl;
}

void KWMailMergeConfigDialog::slotDocumentClicked()
{
    db_->action=KWSLMergeDocument;
    done(TQDialog::Accepted);
}

KWMailMergeConfigDialog::~KWMailMergeConfigDialog()
{
}

/******************************************************************
 *
 * Class: KWMailMergeVariableInsertDia
 *
 ******************************************************************/

KWMailMergeVariableInsertDia::KWMailMergeVariableInsertDia( TQWidget *parent, KWMailMergeDataBase *db )
  : KDialogBase( Plain, i18n( "Mail Merge - Variable Name" ),
                 Ok | Cancel, Ok, parent, "", true )
{
  m_db=db;
  TQWidget *page = plainPage();

  TQVBoxLayout *layout = new TQVBoxLayout( page, marginHint(), spacingHint() );
  layout->setAutoAdd( true );

  TQLabel *l = new TQLabel( i18n( "Name:" ), page );
  l->setMaximumHeight( l->sizeHint().height() );
  names = new TQListBox( page );

  TQMap< TQString, TQString >::ConstIterator it = db->getRecordEntries().begin();
  for ( ; it != db->getRecordEntries().end(); ++it )
    names->insertItem( m_db->version() ?it.data():it.key(), -1 );

  setInitialSize( TQSize( 350, 400 ) );
  connect( names, TQT_SIGNAL( selectionChanged() ),
           this, TQT_SLOT( slotSelectionChanged() ) );
  connect( names, TQT_SIGNAL( doubleClicked( TQListBoxItem* ) ),
           this, TQT_SLOT( slotOk() ) );

  setFocus();
  enableButtonOK( names->currentItem() != -1 );
}

void KWMailMergeVariableInsertDia::slotSelectionChanged()
{
  enableButtonOK( names->currentItem() != -1 );
}

TQString KWMailMergeVariableInsertDia::getName() const
{
     if (m_db->version()>=1) {
           TQString description=names->text(names->currentItem());
           TQMap< TQString, TQString >::ConstIterator it = m_db->getRecordEntries().begin();
           for ( ; it != m_db->getRecordEntries().end(); ++it )
                   if (description==it.data()) {
                           return it.key();
                   }
       Q_ASSERT(0);
         return ""; // can't happen
     }
       else
           return names->text( names->currentItem() );
}
