/*
    Copyright (c) 2006 - 2008 Volker Krause <vkrause@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 "collectionmodel.h"
#include "collectionmodel_p.h"

#include "collectionutils_p.h"
#include "collectionmodifyjob.h"
#include "entitydisplayattribute.h"
#include "monitor.h"
#include "pastehelper.h"
#include "session.h"

#include <kdebug.h>
#include <klocale.h>
#include <kurl.h>
#include <kicon.h>

#include <QtCore/QMimeData>
#include <QtGui/QPixmap>

using namespace Akonadi;

CollectionModel::CollectionModel( QObject * parent ) :
    QAbstractItemModel( parent ),
    d_ptr( new CollectionModelPrivate( this ) )
{
  Q_D( CollectionModel );
  d->init();
}

//@cond PRIVATE
CollectionModel::CollectionModel( CollectionModelPrivate *d,
                                  QObject *parent )
  : QAbstractItemModel( parent ),
    d_ptr( d )
{
  d->init();
}
//@endcond

CollectionModel::~CollectionModel()
{
  Q_D( CollectionModel );
  d->childCollections.clear();
  d->collections.clear();

  delete d->monitor;
  d->monitor = 0;

  delete d;
}

int CollectionModel::columnCount( const QModelIndex & parent ) const
{
  if (parent.isValid() && parent.column() != 0)
    return 0;
  return 1;
}

QVariant CollectionModel::data( const QModelIndex & index, int role ) const
{
  Q_D( const CollectionModel );
  if ( !index.isValid() )
    return QVariant();

  const Collection col = d->collections.value( index.internalId() );
  if ( !col.isValid() )
    return QVariant();

  if ( index.column() == 0 && (role == Qt::DisplayRole || role == Qt::EditRole) ) {
    if ( col.hasAttribute<EntityDisplayAttribute>() &&
         !col.attribute<EntityDisplayAttribute>()->displayName().isEmpty() )
      return col.attribute<EntityDisplayAttribute>()->displayName();
    return col.name();
  }

  switch ( role ) {
    case Qt::DecorationRole:
      if ( index.column() == 0 ) {
        if ( col.hasAttribute<EntityDisplayAttribute>() &&
             !col.attribute<EntityDisplayAttribute>()->iconName().isEmpty() )
          return col.attribute<EntityDisplayAttribute>()->icon();
        return KIcon( CollectionUtils::defaultIconName( col ) );
      }
      break;
    case CollectionIdRole:
      return col.id();
    case CollectionRole:
      return QVariant::fromValue( col );
  }
  return QVariant();
}

QModelIndex CollectionModel::index( int row, int column, const QModelIndex & parent ) const
{
  Q_D( const CollectionModel );
  if (column >= columnCount() || column < 0) return QModelIndex();

  QList<Collection::Id> list;
  if ( !parent.isValid() )
    list = d->childCollections.value( Collection::root().id() );
  else
  {
    if (parent.column() > 0)
       return QModelIndex();
    list = d->childCollections.value( parent.internalId() );
  }

  if ( row < 0 || row >= list.size() )
    return QModelIndex();
  if ( !d->collections.contains( list.at(row) ) )
    return QModelIndex();
  return createIndex( row, column, reinterpret_cast<void*>( d->collections.value( list.at(row) ).id() ) );
}

QModelIndex CollectionModel::parent( const QModelIndex & index ) const
{
  Q_D( const CollectionModel );
  if ( !index.isValid() )
    return QModelIndex();

  Collection col = d->collections.value( index.internalId() );
  if ( !col.isValid() )
    return QModelIndex();


  Collection parentCol = d->collections.value( col.parent() );
  if ( !parentCol.isValid() )
  {
    return QModelIndex();
}
  QList<Collection::Id> list;
  list = d->childCollections.value( parentCol.parent() );

  int parentRow = list.indexOf( parentCol.id() );
  if ( parentRow < 0 )
    return QModelIndex();

  return createIndex( parentRow, 0, reinterpret_cast<void*>( parentCol.id() ) );
}

int CollectionModel::rowCount( const QModelIndex & parent ) const
{
  const  Q_D( CollectionModel );
  QList<Collection::Id> list;
  if ( parent.isValid() )
    list = d->childCollections.value( parent.internalId() );
  else
    list = d->childCollections.value( Collection::root().id() );

  return list.size();
}

QVariant CollectionModel::headerData( int section, Qt::Orientation orientation, int role ) const
{
  if ( section == 0 && orientation == Qt::Horizontal && role == Qt::DisplayRole )
    return i18nc( "@title:column, name of a thing", "Name" );
  return QAbstractItemModel::headerData( section, orientation, role );
}

bool CollectionModel::setData( const QModelIndex & index, const QVariant & value, int role )
{
  Q_D( CollectionModel );
  if ( index.column() == 0 && role == Qt::EditRole ) {
    // rename collection
    Collection col = d->collections.value( index.internalId() );
    if ( !col.isValid() || value.toString().isEmpty() )
      return false;
    col.setName( value.toString() );
    CollectionModifyJob *job = new CollectionModifyJob( col, d->session );
    connect( job, SIGNAL(result(KJob*)), SLOT(editDone(KJob*)) );
    return true;
  }
  return QAbstractItemModel::setData( index, value, role );
}

Qt::ItemFlags CollectionModel::flags( const QModelIndex & index ) const
{
  Q_D( const CollectionModel );

  // Pass modeltest.
  // http://labs.trolltech.com/forums/topic/79
  if (!index.isValid())
    return 0;

  Qt::ItemFlags flags = QAbstractItemModel::flags( index );

  flags = flags | Qt::ItemIsDragEnabled;

  Collection col;
  if ( index.isValid() ) {
    col = d->collections.value( index.internalId() );
    Q_ASSERT( col.isValid() );
  }
  else
    return flags | Qt::ItemIsDropEnabled; // HACK Workaround for a probable bug in Qt

  if ( col.isValid() ) {
    if ( col.rights() & (Collection::CanChangeCollection |
                         Collection::CanCreateCollection |
                         Collection::CanDeleteCollection |
                         Collection::CanCreateItem) )  {
      if ( index.column() == 0 )
        flags = flags | Qt::ItemIsEditable;

      flags = flags | Qt::ItemIsDropEnabled;
    }
  }

  return flags;
}

Qt::DropActions CollectionModel::supportedDropActions() const
{
  return Qt::CopyAction | Qt::MoveAction;
}

QStringList CollectionModel::mimeTypes() const
{
  return QStringList() << QLatin1String( "text/uri-list" );
}

QMimeData *CollectionModel::mimeData(const QModelIndexList &indexes) const
{
    QMimeData *data = new QMimeData();
    KUrl::List urls;
    foreach ( const QModelIndex &index, indexes ) {
        if ( index.column() != 0 )
          continue;

        urls << Collection( index.internalId() ).url();
    }
    urls.populateMimeData( data );

    return data;
}

bool CollectionModel::dropMimeData(const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent)
{
  Q_D( CollectionModel );
  if ( !(action & supportedDropActions()) )
    return false;

  // handle drops onto items as well as drops between items
  QModelIndex idx;
  if ( row >= 0 && column >= 0 )
    idx = index( row, column, parent );
  else
    idx = parent;

  if ( !idx.isValid() )
    return false;

  const Collection parentCol = d->collections.value( idx.internalId() );
  if (!parentCol.isValid())
    return false;

  KJob *job = PasteHelper::paste( data, parentCol, action != Qt::MoveAction );
  connect( job, SIGNAL(result(KJob*)), SLOT(dropResult(KJob*)) );
  return true;
}

Collection CollectionModel::collectionForId(Collection::Id id) const
{
  Q_D( const CollectionModel );
  return d->collections.value( id );
}

void CollectionModel::fetchCollectionStatistics(bool enable)
{
  Q_D( CollectionModel );
  d->fetchStatistics = enable;
  d->monitor->fetchCollectionStatistics( enable );
}

void CollectionModel::includeUnsubscribed(bool include)
{
  Q_D( CollectionModel );
  d->unsubscribed = include;
}



#include "collectionmodel.moc"
