/*
    Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
    Copyright (c) 2010 Andras Mantia <andras@kdab.com>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 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
    Lesser General Public License for more details.

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


#include "emptytrashcommand_p.h"
#include "util_p.h"
#include "imapsettings.h"

#include <KDebug>
#include <KLocale>
#include <KMessageBox>

#include "akonadi/entitytreemodel.h"
#include "akonadi/kmime/specialmailcollections.h"
#include "akonadi/itemfetchjob.h"
#include "akonadi/itemdeletejob.h"
#include "akonadi/agentmanager.h"
#include "kmime/kmime_message.h"
 
EmptyTrashCommand::EmptyTrashCommand(const QAbstractItemModel* model, QObject* parent)
  : CommandBase( parent ),
    mModel( model ), 
    the_trashCollectionFolder( -1 ),
    mNumberOfTrashToEmpty( 0 )
{
}

EmptyTrashCommand::EmptyTrashCommand(const Akonadi::Collection& folder, QObject* parent)
  : CommandBase( parent ),
    mModel( 0 ), 
    the_trashCollectionFolder( -1 ),
    mFolder( folder ),
    mNumberOfTrashToEmpty( 0 )
{
}


void EmptyTrashCommand::execute()
{
  if ( !mFolder.isValid() && !mModel ) {
    emitResult( Failed );
    return;
  }

  if ( !mFolder.isValid() ) { //expunge all
    const QString title = i18n("Empty Trash");
    const QString text = i18n("Are you sure you want to empty the trash folders of all accounts?");
    if (KMessageBox::warningContinueCancel(0, text, title,
                                          KStandardGuiItem::cont(), KStandardGuiItem::cancel(),
                                          QLatin1String( "confirm_empty_trash" ) )
        != KMessageBox::Continue)
    {
      emitResult( OK );
      return;
    }
    Akonadi::Collection trash = trashCollectionFolder();
    QList<Akonadi::Collection> trashFolder;
    trashFolder<<trash;

    const Akonadi::AgentInstance::List lst = agentInstances();
    foreach ( const Akonadi::AgentInstance& type, lst ) {
      if ( type.identifier().contains( IMAP_RESOURCE_IDENTIFIER ) ) {
        if ( type.status() == Akonadi::AgentInstance::Broken )
          continue;
        OrgKdeAkonadiImapSettingsInterface *iface = Util::createImapSettingsInterface( type.identifier() );
        if ( iface->isValid() ) {
          const int trashImap = iface->trashCollection();
          if ( trashImap != trash.id() ) {
            trashFolder<<Akonadi::Collection( trashImap );
          }
        }
        delete iface;
      }
    }
    mNumberOfTrashToEmpty = trashFolder.count();
    for (int i = 0; i < mNumberOfTrashToEmpty; ++i) {
      expunge( trashFolder.at( i ) );
    }
  } else {
    if ( folderIsTrash( mFolder ) ) {
      mNumberOfTrashToEmpty++;
      expunge( mFolder );
    } else {
      emitResult( OK ); 
    }
    
  }
}

void EmptyTrashCommand::expunge( const Akonadi::Collection & col )
{
  if ( col.isValid() ) {
    Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob( col,this );
    connect( job, SIGNAL(result(KJob*)), this, SLOT(slotExpungeJob(KJob*)) );
  } else {
    kDebug()<<" Try to expunge an invalid collection :"<<col;
    emitResult( Failed ); 
  }
}

void EmptyTrashCommand::slotExpungeJob( KJob *job )
{
  if ( job->error() ) {
    Util::showJobError( job );
    emitResult( Failed );
    return;
  }
  Akonadi::ItemFetchJob *fjob = dynamic_cast<Akonadi::ItemFetchJob*>( job );
  if ( !fjob ) {
    emitResult( Failed );
    return;
  }
  const Akonadi::Item::List lstItem = fjob->items();
  if ( lstItem.isEmpty() ) {
    emitResult( OK );
    return;
  }
  Akonadi::ItemDeleteJob *jobDelete = new Akonadi::ItemDeleteJob( lstItem, this );
  connect( jobDelete, SIGNAL(result(KJob*)), this, SLOT(slotDeleteJob(KJob*)) );

}

void EmptyTrashCommand::slotDeleteJob( KJob *job )
{
  if ( job->error() ) {
    Util::showJobError( job );
    emitResult( Failed );
  }
  emitResult( OK );
}

Akonadi::AgentInstance::List EmptyTrashCommand::agentInstances()
{
  Akonadi::AgentInstance::List relevantInstances;
  foreach ( const Akonadi::AgentInstance &instance, Akonadi::AgentManager::self()->instances() ) {
    if ( instance.type().mimeTypes().contains( KMime::Message::mimeType() ) &&
         instance.type().capabilities().contains( QLatin1String( "Resource" ) ) &&
         !instance.type().capabilities().contains( QLatin1String( "Virtual" ) ) ) {
      relevantInstances << instance;
    }
  }
  return relevantInstances;
}

Akonadi::Collection EmptyTrashCommand::collectionFromId(const Akonadi::Collection::Id& id) const
{
  const QModelIndex idx = Akonadi::EntityTreeModel::modelIndexForCollection(
    mModel, Akonadi::Collection(id)
  );
  return idx.data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
}

Akonadi::Collection EmptyTrashCommand::trashCollectionFolder()
{
  if ( the_trashCollectionFolder < 0 )
    the_trashCollectionFolder = Akonadi::SpecialMailCollections::self()->defaultCollection( Akonadi::SpecialMailCollections::Trash ).id();
  return collectionFromId( the_trashCollectionFolder );
}

bool EmptyTrashCommand::folderIsTrash( const Akonadi::Collection & col )
{
  if ( col == Akonadi::SpecialMailCollections::self()->defaultCollection( Akonadi::SpecialMailCollections::Trash ) )
    return true;
  const Akonadi::AgentInstance::List lst = agentInstances();
  foreach ( const Akonadi::AgentInstance& type, lst ) {
    if ( type.status() == Akonadi::AgentInstance::Broken )
      continue;
    if ( type.identifier().contains( IMAP_RESOURCE_IDENTIFIER ) ) {
      OrgKdeAkonadiImapSettingsInterface *iface = Util::createImapSettingsInterface( type.identifier() );
      if ( iface->isValid() ) {
        if ( iface->trashCollection() == col.id() ) {
          delete iface;
          return true;
        }
      }
      delete iface;
    }
  }
  return false;
}

void EmptyTrashCommand::emitResult( Result value )
{
  emit result( value );
  mNumberOfTrashToEmpty--;
  if ( mNumberOfTrashToEmpty <= 0 ) {
    deleteLater();
  }
}
