/***************************** LICENSE START ***********************************

 Copyright 2013 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include "MvQLayerViewLevel.h"

//#include <QDebug>

#include <QAction>
#include <QDropEvent>
#include <QMenu>

#include "Assertions.hpp"
#include "ObjectList.h"
#include "Root.h"

//==================================================================
//
//	MvQLayerViewLevelModel
//
//==================================================================

MvQLayerViewLevelModel::MvQLayerViewLevelModel(QObject* parent) :
    QAbstractItemModel(parent),
    presentableId_(2)
{
}

MvQLayerViewLevelModel::~MvQLayerViewLevelModel()
{
    icons_.clear();
}

int MvQLayerViewLevelModel::columnCount(const QModelIndex& parent) const
{
    return parent.isValid() ? 0 : 1;
}

int MvQLayerViewLevelModel::rowCount(const QModelIndex& index) const
{
    if (!index.isValid())
        return icons_.count();
    else
        return 0;
}

QVariant MvQLayerViewLevelModel::data(const QModelIndex& index, int role) const
{
    if (role != Qt::DisplayRole && role != Qt::DecorationRole &&
        role != Qt::ForegroundRole && role != Qt::UserRole &&
        role != Qt::FontRole)
        return {};

    if (!index.isValid())
        return {};

    if (index.row() < 0 || index.row() >= icons_.count())
        return {};

    MvQLayerContentsIcon icon = icons_[index.row()];

    // qDebug() << "MvQLayerViewLevelModel::data " << icon.name() << icon.type() << icon.id();

    switch (role) {
        case Qt::DecorationRole: {
            return icon.pixmap();
        }

        case Qt::DisplayRole: {
            return icon.name();
        }

            //      case Qt::UserRole:
            //         return icon->path();
        default: {
            break;
        }
    }

    return {};
}


QModelIndex MvQLayerViewLevelModel::index(int row, int column, const QModelIndex& /*parent */) const
{
    return createIndex(row, column, (void*)nullptr);
}

QModelIndex MvQLayerViewLevelModel::parent(const QModelIndex& /*index*/) const
{
    return {};
}

void MvQLayerViewLevelModel::setIcons(MvIconList& iconList)
{
    // Clear current list of icons
    beginResetModel();
    icons_.clear();

    // Add new icons
    auto lCursor = iconList.begin();
    while (lCursor != iconList.end()) {
        MvIcon mvicon = *lCursor;
        MvQLayerContentsIcon icon(QString(mvicon.IconName()), QString(mvicon.IconClass()), QString::number(mvicon.Id()), false);

        icons_ << icon;
        ++lCursor;
    }

    endResetModel();
}

MvQLayerContentsIcon* MvQLayerViewLevelModel::indexToIcon(const QModelIndex& index)
{
    MvQLayerContentsIcon* icon = nullptr;
    if (!index.isValid() || index.column() < 0 || index.column() > icons_.count())
        return icon;

    icon = &icons_[index.row()];

    return icon;
}

#if 0
bool MvQLayerViewLevelModel::add( const MvQLayerContentsIcon& icon )
{
   if( icons_.contains(icon) )
      return false;

   beginResetModel();
   icons_ << icon;
   endResetModel();

   return true;
}

void MvQLayerViewLevelModel::remove( const MvQLayerContentsIcon& icon )
{
   beginResetModel();
   icons_.removeAll(icon);
   endResetModel();
}
#endif

void MvQLayerViewLevelModel::reset(int presId)
{
    // Update model if view has changed
    //   if ( presId == presentableId_ )
    //      return;

    // Retrieve icons from the DataBase associated to this presentable/view
    presentableId(presId);
    MvIconList iconList;
    if (!this->getIconsFromDB(presId, iconList))
        return;  // presentable not found or no icons found

    // Update list of icons
    setIcons(iconList);
}

int MvQLayerViewLevelModel::getIconsFromDB(int presId, MvIconList& iconList)
{
    // Get Presentable associated to the input Id
    Presentable* sp = Root::Instance().FindSuperPage();
    Presentable* pres = sp->FindBranch(presId);
    if (!pres)
        return 0;  // presentable not found

    // Retrieve icons from the DataBase associated to this presentable/view
    MvIconDataBase& dataBase = pres->IconDataBase();
    dataBase.RetrieveIcon(presentableId(), iconList);

    // Remove dataUnit icons
    auto listCursor = iconList.begin();
    MvListCursor foundCursor;
    while (listCursor != iconList.end()) {
        MvRequest req = (*listCursor).Request();
        if (ObjectList::IsDataUnit(req.getVerb())) {
            // Keep a copy of the found iterator
            foundCursor = listCursor;

            // Increment, so we can continue our search
            ++listCursor;

            // Delete icon from List
            iconList.erase(foundCursor);
        }
        else
            ++listCursor;  // increment, so we can continue our search
    }

    return iconList.size();
}


//=================================================================
//
//	MvQLayerViewLevelView
//
//=================================================================

MvQLayerViewLevelView::MvQLayerViewLevelView(MvQLayerViewLevelModel* model, QWidget* parent) :
    QListView(parent),
    model_(model)
{
    // Set behaviour
    setViewMode(QListView::IconMode);
    setFlow(QListView::LeftToRight);
    setMovement(QListView::Snap);
    setWrapping(false);
    setResizeMode(QListView::Adjust);
    //   setIconSize(QSize(48, 48));
    //   setMaximumHeight(75);
    setSpacing(5);

    QFont font;
    QFontMetrics fm(font);
    setMaximumHeight(fm.size(Qt::TextExpandTabs, "A").height() + 32 + 10 + 5 + 10);

    // Double click
    connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
            this, SLOT(slotDoubleClickItem(const QModelIndex&)));

    // Context menu
    createContextMenu();
    setContextMenuPolicy(Qt::ActionsContextMenu);
    // setContextMenuPolicy(Qt::CustomContextMenu);
    // connect(this, SIGNAL(customContextMenuRequested(const QPoint&)),
    //         this, SLOT(slotContextMenu(const QPoint&)));

    // Drag and Drop settings
    setMouseTracking(true);
    setAcceptDrops(true);
    setDragEnabled(true);
    setDropIndicatorShown(true);
    setDragDropMode(QAbstractItemView::DragDrop);

    setModel(model);
}

MvQLayerViewLevelView::~MvQLayerViewLevelView()
{
    foreach (QAction* ac, actions_) {
        delete ac;
        ac = nullptr;
    }
}

void MvQLayerViewLevelView::slotDoubleClickItem(const QModelIndex& index)
{
    if (!index.isValid())
        return;

    // Get icon from the model
    MvQLayerContentsIcon* icon = model_->indexToIcon(index);
    if (!icon)
        return;

    // Start editor
    icon->startEditor();
}

#if 0
void MvQLayerViewLevelView::slotContextMenu(const QPoint& pos)
{
   // Get index from position
   QModelIndex index = this->indexAt(pos); 
   if( !index.isValid() )
      return;

   // Get icon from the model
   MvQLayerContentsIcon *icon = model_->indexToIcon(index);
   if(!icon)
      return;

   //Insert new key
   QList<QAction*> actions;
   QAction *actionEdit = new QAction(this);
   actionEdit->setObjectName(QString::fromUtf8("actionEdit"));
   actionEdit->setText(tr("Edit in Plot"));
   QFont font = actionEdit->font();
   font.setWeight(QFont::Bold);
   actionEdit->setFont(font);
   actions.append(actionEdit);
   if(!icon->canBeEdited())
      actionEdit->setEnabled(false); 

   //Inser new key
   QAction *actionSave = new QAction(this);
   actionSave->setObjectName(QString::fromUtf8("actionSave"));
   actionSave->setText(tr("Save to Disk"));
   actions.append(actionSave);
   if(!icon->canBeSaved())
      actionSave->setEnabled(false); 

   QAction *actionDelete = new QAction(this);
   actionDelete->setObjectName(QString::fromUtf8("actionDelete"));
   actionDelete->setText(tr("Remove from Plot"));
   actions.append(actionDelete);
   if(!icon->canBeDeleted())
      actionDelete->setEnabled(false); 

   QAction *res = QMenu::exec(actions,this->mapToGlobal(pos));   
   if(res == actionEdit)
      icon->startEditor();
   else if(res == actionSave)
      icon->saveIcon();
   else if(res == actionDelete)
      icon->deleteIcon();

   foreach(QAction *ac,actions)
   {
      delete ac;
      ac = 0;
   }
}

#else

void MvQLayerViewLevelView::createContextMenu()
{
    // Insert Edit key
    actionEdit_ = new QAction(this);
    actionEdit_->setObjectName(QString::fromUtf8("actionEdit"));
    actionEdit_->setText(tr("Edit in Plot"));
    QFont font = actionEdit_->font();
    font.setWeight(QFont::Bold);
    actionEdit_->setFont(font);
    actionEdit_->setShortcut(tr("Ctrl+E"));
    actionEdit_->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    actions_.append(actionEdit_);

    addAction(actionEdit_);
    connect(actionEdit_, SIGNAL(triggered()), this, SLOT(slotEdit()));

    // Insert Save key
    actionSave_ = new QAction(this);
    actionSave_->setObjectName(QString::fromUtf8("actionSave"));
    actionSave_->setText(tr("Save to Disk"));
    actionSave_->setShortcut(QKeySequence::Save);
    actionSave_->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    actions_.append(actionSave_);

    addAction(actionSave_);
    connect(actionSave_, SIGNAL(triggered()), this, SLOT(slotSave()));

    // Insert Save As key
    actionSaveAs_ = new QAction(this);
    actionSaveAs_->setObjectName(QString::fromUtf8("actionSaveAs"));
    actionSaveAs_->setText(tr("Save as ..."));
    actionSaveAs_->setShortcut(QKeySequence::SaveAs);
    actionSaveAs_->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    actions_.append(actionSaveAs_);

    addAction(actionSaveAs_);
    connect(actionSaveAs_, SIGNAL(triggered()), this, SLOT(slotSaveAs()));

    // Insert Delete key
    actionDelete_ = new QAction(this);
    actionDelete_->setObjectName(QString::fromUtf8("actionDelete"));
    actionDelete_->setText(tr("Remove from plot"));
    actionDelete_->setShortcut(QKeySequence::Delete);
    actionDelete_->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    actions_.append(actionDelete_);

    addAction(actionDelete_);
    connect(actionDelete_, SIGNAL(triggered()), this, SLOT(slotDelete()));
}

void MvQLayerViewLevelView::currentChanged(const QModelIndex& current, const QModelIndex& previous)
{
    // Get icon from the model
    MvQLayerContentsIcon* icon = model_->indexToIcon(current);
    if (!icon)
        return;

    // Check options visibility
    bool bvis = icon->canBeEdited() ? true : false;
    actionEdit_->setEnabled(bvis);

    bvis = icon->canBeSaved() ? true : false;
    actionSave_->setEnabled(bvis);

    bvis = icon->canBeSavedAs() ? true : false;
    actionSaveAs_->setEnabled(bvis);

    bvis = icon->canBeDeleted() ? true : false;
    actionDelete_->setEnabled(bvis);

    QListView::currentChanged(current, previous);
}

void MvQLayerViewLevelView::slotEdit()
{
    // Get selected index
    QModelIndex index = currentIndex();

    // Get icon from the model
    MvQLayerContentsIcon* icon = model_->indexToIcon(index);
    if (!icon)
        return;

    // Edit icon
    icon->startEditor();
}

void MvQLayerViewLevelView::slotSave()
{
    // Get selected index
    QModelIndex index = currentIndex();

    // Get icon from the model
    MvQLayerContentsIcon* icon = model_->indexToIcon(index);
    if (!icon)
        return;

    // Save icon
    icon->saveIcon();
}

void MvQLayerViewLevelView::slotSaveAs()
{
    // Get selected index
    QModelIndex index = currentIndex();

    // Get icon from the model
    MvQLayerContentsIcon* icon = model_->indexToIcon(index);
    if (!icon)
        return;

    // Save icon
    icon->saveAsIcon();
}

void MvQLayerViewLevelView::slotDelete()
{
    // Get selected index
    QModelIndex index = currentIndex();

    // Get icon from the model
    MvQLayerContentsIcon* icon = model_->indexToIcon(index);
    if (!icon)
        return;

    // Delete icon
    icon->deleteIcon();
}
#endif

void MvQLayerViewLevelView::dragEnterEvent(QDragEnterEvent* event)
{
    if ((event->proposedAction() == Qt::CopyAction ||
         event->proposedAction() == Qt::MoveAction))
        event->accept();
    else
        event->ignore();
}

void MvQLayerViewLevelView::dragLeaveEvent(QDragLeaveEvent* event)
{
    //   layerId_ = -1;   // initialise with a non-valid value
    //   model_->setHighlightedLayer(QModelIndex(),layerId_);
    event->accept();
}

void MvQLayerViewLevelView::dragMoveEvent(QDragMoveEvent* event)
{
    if ((event->proposedAction() == Qt::CopyAction ||
         event->proposedAction() == Qt::MoveAction))
        event->accept();
    else
        event->ignore();
}

void MvQLayerViewLevelView::dropEvent(QDropEvent* event)
{
    if (event->proposedAction() != Qt::CopyAction &&
        event->proposedAction() != Qt::MoveAction) {
        event->ignore();
        return;
    }

    // Get dropped icon
    MvQDrop drop(event);
    if (drop.hasData()) {
        // Get index from the dropped position (the target icon)
        //      QModelIndex index = this->indexAt(event->pos());
        //      if( !index.isValid() )
        //      {
        //         COUT << "Drop not accepted: MvQLayerView::dropEvent" << std::endl;
        //         return;
        //      }

        // To handle the dropped icon
        emit iconDropped(drop);

        event->accept();
        return;
    }
    else {
        // Relayed base class
        QListView::dropEvent(event);
    }
}
