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

 Copyright 2012 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 "MvQLayerWidget.h"

//#include <QDebug>

#include <QAction>
#include <QLabel>
#include <QHBoxLayout>
#include <QMenu>
#include <QSlider>
#include <QSpinBox>
#include <QToolButton>
#include <QVBoxLayout>

#include "MgQLayerItem.h"
#include "MgQSceneItem.h"
#include "MvQLayerContentsIcon.h"
#include "MvQLayerModel.h"
#include "MvQLayerSuperPage.h"
#include "MvQLayerViewLevel.h"
#include "MvQMethods.h"
#include "MvQStreamOper.h"

#include "ObjectList.h"
#include "PlotMod.h"
#include "Root.h"
#include "MvLog.h"

MvQLayerWidget::MvQLayerWidget(MgQPlotScene* scene, QWidget* parent) :
    QWidget(parent)
{
    auto* layerVb = new QVBoxLayout;
    layerVb->setContentsMargins(2, 2, 2, 2);
    setLayout(layerVb);

    // Top level: model and view initializations
    spModel_ = new MvQLayerSuperPageModel(this);
    spView_ = new MvQLayerSuperPageView(spModel_, this);
    layerVb->addWidget(MvQ::makeLabelPanel(tr("Top Level"), this, -1));
    layerVb->addWidget(spView_);

    // View level: model and view initializations
    vlModel_ = new MvQLayerViewLevelModel(this);
    vlView_ = new MvQLayerViewLevelView(vlModel_, this);
    layerVb->addWidget(MvQ::makeLabelPanel(tr("View Level"), this, -1));
    layerVb->addWidget(vlView_);

    // Layer Level: model and view initializations
    view_ = new MvQLayerView(this);
    view_->setItemDelegate(new MvQLayerDelegate());
    layerVb->addWidget(MvQ::makeLabelPanel(tr("Layer Level"), this, -1));
    layerVb->addWidget(view_);

    model_ = new MvQLayerModel(scene);
    filterModel_ = new MvQLayerFilterModel(this);
    filterModel_->setSourceModel(model_);
    view_->setLayerModel(model_, filterModel_);

    view_->setDragEnabled(true);
    view_->setAcceptDrops(true);
    view_->setDropIndicatorShown(true);
    view_->setDragDropMode(QAbstractItemView::DragDrop);

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

    // Context menu
    view_->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(view_, SIGNAL(customContextMenuRequested(const QPoint&)),
            this, SLOT(slotContextMenu(const QPoint&)));
    // Slider
    auto* hb = new QHBoxLayout;
    layerVb->addLayout(hb);

    auto* label = new QLabel(tr("Transparency (%)"));
    hb->addWidget(label);

    trSlider_ = new QSlider;
    trSlider_->setOrientation(Qt::Horizontal);
    trSlider_->setMinimum(0);
    trSlider_->setMaximum(100);
    trSlider_->setToolTip(tr("Change layer transparency"));
    hb->addWidget(trSlider_);

    trSpin_ = new QSpinBox;
    trSpin_->setMinimum(0);
    trSpin_->setMaximum(100);
    trSpin_->setToolTip(tr("Change layer transparency"));
    hb->addWidget(trSpin_);

    initTrWidgets_ = false;

    connect(trSlider_, SIGNAL(valueChanged(int)),
            this, SLOT(slotTrSliderValueChanged(int)));

    connect(trSlider_, SIGNAL(sliderReleased()),
            this, SLOT(slotTrSliderReleased()));

    connect(trSpin_, SIGNAL(valueChanged(int)),
            this, SLOT(slotTrSpinValueChanged(int)));

    // Buttons
    hb = new QHBoxLayout;
    layerVb->addLayout(hb);

    topTb_ = new QToolButton(this);
    topTb_->setToolTip(tr("Move the current layer to the top"));
    topTb_->setAutoRaise(true);
    topTb_->setIcon(QPixmap(QString::fromUtf8(":/uPlot/arrow_top.svg")));

    upTb_ = new QToolButton(this);
    upTb_->setToolTip(tr("Move the current layer up"));
    upTb_->setAutoRaise(true);
    upTb_->setIcon(QPixmap(QString::fromUtf8(":/uPlot/arrow_up.svg")));

    downTb_ = new QToolButton(this);
    downTb_->setToolTip(tr("Move the current layer down"));
    downTb_->setAutoRaise(true);
    downTb_->setIcon(QPixmap(QString::fromUtf8(":/uPlot/arrow_down.svg")));

    bottomTb_ = new QToolButton(this);
    bottomTb_->setToolTip(tr("Move the current layer to the bottom"));
    bottomTb_->setAutoRaise(true);
    bottomTb_->setIcon(QPixmap(QString::fromUtf8(":/uPlot/arrow_bottom.svg")));

    infoTb_ = new QToolButton(this);
    infoTb_->setToolTip(tr("Show layer details"));
    infoTb_->setAutoRaise(true);
    infoTb_->setIcon(QPixmap(QString::fromUtf8(":/uPlot/info_light.svg")));

    hb->addWidget(topTb_);
    hb->addWidget(upTb_);
    hb->addWidget(downTb_);
    hb->addWidget(bottomTb_);
    hb->addStretch(1.);
    hb->addWidget(infoTb_);

    // Signal/slot functions
    connect(topTb_, SIGNAL(clicked()),
            this, SLOT(slotMoveTop()));

    connect(upTb_, SIGNAL(clicked()),
            this, SLOT(slotMoveUp()));

    connect(downTb_, SIGNAL(clicked()),
            this, SLOT(slotMoveDown()));

    connect(bottomTb_, SIGNAL(clicked()),
            this, SLOT(slotMoveBottom()));

    connect(infoTb_, SIGNAL(clicked()),
            this, SLOT(slotShowInfo()));

    connect(view_, SIGNAL(clicked(const QModelIndex&)),
            this, SLOT(slotSelectLayer(const QModelIndex&)));

    connect(model_, SIGNAL(layerDragFinished()),
            this, SLOT(slotCheckItemStatus()));

    connect(model_, SIGNAL(layerTransparencyChanged(QString, int)),
            this, SIGNAL(layerTransparencyChanged(QString, int)));

    connect(model_, SIGNAL(layerVisibilityChanged(QString, bool)),
            this, SIGNAL(layerVisibilityChanged(QString, bool)));

    connect(model_, SIGNAL(layerStackingOrderChanged(QList<QPair<QString, int> >)),
            this, SIGNAL(layerStackingOrderChanged(QList<QPair<QString, int> >)));

    connect(view_, SIGNAL(iconDropped(const MvQDrop&, const QModelIndex&)),
            this, SLOT(slotIconDropped(const MvQDrop&, const QModelIndex&)));

    connect(spView_, SIGNAL(iconDropped(const MvQDrop&)),
            this, SLOT(slotIconDroppedTopLevel(const MvQDrop&)));

    connect(vlView_, SIGNAL(iconDropped(const MvQDrop&)),
            this, SLOT(slotIconDroppedViewLevel(const MvQDrop&)));
}


MgQLayerItem* MvQLayerWidget::currentLayer()
{
    QModelIndex modelIndex = filterModel_->mapToSource(view_->currentIndex());
    int row = modelIndex.row();
    return model_->rowToLayer(row);
}

QString MvQLayerWidget::currentLayerText()
{
    QModelIndex modelIndex = filterModel_->mapToSource(view_->currentIndex());
    return model_->data(modelIndex).toString();
}

void MvQLayerWidget::slotSelectLayer(MgQLayerItem* layer)
{
    int row = model_->layerToRow(layer);
    QModelIndex index = filterModel_->mapFromSource(model_->index(row, 0));
    slotSelectLayer(index);
}

void MvQLayerWidget::slotSelectLayer(const QModelIndex& index)
{
#if 0   
   QModelIndex modelIndexCur = filterModel_->mapToSource(view_->currentIndex());
   QModelIndex modelIndex = filterModel_->mapToSource(index);
//   QModelIndex modelIndex = filterModel_->mapFromSource(index);
   if( modelIndex != modelIndexCur )
   {
      //QModelIndex proxyIndex = filterModel_->mapFromSource(index);
      //view_->setCurrentIndex(proxyIndex);
      view_->setCurrentIndex(index);
   }
#endif

    int value = model_->transparency(filterModel_->mapToSource(index));

    slotCheckItemStatus();

    initTrWidgets_ = true;
    trSlider_->setValue(value);
    trSpin_->setValue(value);
    initTrWidgets_ = false;
}


void MvQLayerWidget::slotTrSpinValueChanged(int value)
{
    if (initTrWidgets_)
        return;

    trSlider_->setValue(value);
    changeTransparency(value);
}

void MvQLayerWidget::slotTrSliderValueChanged(int value)
{
    if (initTrWidgets_)
        return;

    initTrWidgets_ = true;
    trSpin_->setValue(value);
    initTrWidgets_ = false;
}

void MvQLayerWidget::slotTrSliderReleased()
{
    int value = trSlider_->value();
    changeTransparency(value);
}

void MvQLayerWidget::changeTransparency(int value)
{
    QModelIndex modeIndex = filterModel_->mapToSource(view_->currentIndex());
    model_->setTransparency(modeIndex, value);
}

void MvQLayerWidget::slotMoveTop()
{
    QModelIndex modelIndex = filterModel_->mapToSource(view_->currentIndex());
    model_->moveTop(modelIndex);

    QModelIndex proxyIndex = filterModel_->mapFromSource(model_->index(0, 0));
    view_->setCurrentIndex(proxyIndex);

    slotCheckItemStatus();
}

void MvQLayerWidget::slotMoveUp()
{
    QModelIndex modelIndex = filterModel_->mapToSource(view_->currentIndex());
    int row = modelIndex.row();

    model_->moveUp(modelIndex);

    QModelIndex proxyIndex = filterModel_->mapFromSource(model_->index(row - 1, 0));
    view_->setCurrentIndex(proxyIndex);

    slotCheckItemStatus();
}

void MvQLayerWidget::slotMoveBottom()
{
    QModelIndex modelIndex = filterModel_->mapToSource(view_->currentIndex());
    model_->moveBottom(modelIndex);

    int num = model_->rowCount(QModelIndex());
    QModelIndex proxyIndex = filterModel_->mapFromSource(model_->index(num - 1, 0));
    view_->setCurrentIndex(proxyIndex);

    slotCheckItemStatus();
}

void MvQLayerWidget::slotMoveDown()
{
    QModelIndex modelIndex = filterModel_->mapToSource(view_->currentIndex());
    int row = modelIndex.row();

    model_->moveDown(modelIndex);

    QModelIndex proxyIndex = filterModel_->mapFromSource(model_->index(row + 1, 0));
    view_->setCurrentIndex(proxyIndex);

    slotCheckItemStatus();
}

void MvQLayerWidget::slotShowInfo()
{
    QModelIndex idx = filterModel_->mapToSource(view_->currentIndex());
    emit layerInfoRequested(model_->layerFromAnyLevel(idx));
}

void MvQLayerWidget::slotCheckItemStatus()
{
    QModelIndex modelIndex = filterModel_->mapToSource(view_->currentIndex());
    if (!modelIndex.isValid()) {
        trSlider_->setEnabled(false);
        trSpin_->setEnabled(false);
        topTb_->setEnabled(false);
        upTb_->setEnabled(false);
        bottomTb_->setEnabled(false);
        downTb_->setEnabled(false);
    }
    else {
        trSlider_->setEnabled(true);
        trSpin_->setEnabled(true);

        int row = modelIndex.row();
        int num = model_->rowCount(QModelIndex());

        if (num == 1) {
            topTb_->setEnabled(false);
            upTb_->setEnabled(false);
            downTb_->setEnabled(false);
            bottomTb_->setEnabled(false);
        }
        else if (row == 0) {
            topTb_->setEnabled(false);
            upTb_->setEnabled(false);
            downTb_->setEnabled(true);
            bottomTb_->setEnabled(true);
        }
        else if (row == num - 1) {
            topTb_->setEnabled(true);
            upTb_->setEnabled(true);
            downTb_->setEnabled(false);
            bottomTb_->setEnabled(false);
        }
        else {
            topTb_->setEnabled(true);
            upTb_->setEnabled(true);
            downTb_->setEnabled(true);
            bottomTb_->setEnabled(true);
        }
    }
}

void MvQLayerWidget::slotDoubleClickItem(const QModelIndex& index1)
{
    QModelIndex index = filterModel_->mapToSource(index1);
    if (model_->layer(index) != nullptr) {
        slotShowInfo();
        return;
    }

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

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

void MvQLayerWidget::slotContextMenu(const QPoint& position)
{
    QModelIndex index = filterModel_->mapToSource(view_->indexAt(position));
    if (!index.isValid())
        return;

    QList<QAction*> actions;
    auto* actionInfo = new QAction(this);
    actionInfo->setObjectName(QString::fromUtf8("actionInfo"));
    actionInfo->setText(tr("Details"));
    actionInfo->setIcon(QPixmap(QString::fromUtf8(":/uPlot/info_light.svg")));
    QFont font = actionInfo->font();
    font.setWeight(QFont::Bold);
    actionInfo->setFont(font);
    actions << actionInfo;

    if (model_->indexToLevel(index) == 0) {
        QAction* res = QMenu::exec(actions, view_->mapToGlobal(position));
        if (res == actionInfo)
            slotShowInfo();
    }
    else if (MvQLayerContentsIcon* icon = model_->indexToIcon(index)) {
        auto* sep = new QAction(this);
        sep->setSeparator(true);
        actions << sep;

        // Insert Edit key
        auto* 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(QKeySequence(tr("Ctrl+E")));
        actions.append(actionEdit);
        if (!icon->canBeEdited())
            actionEdit->setEnabled(false);

        // Insert Save key
        auto* actionSave = new QAction(this);
        actionSave->setObjectName(QString::fromUtf8("actionSave"));
        actionSave->setText(tr("Overwrite on disk"));
        actionSave->setShortcut(QKeySequence::Save);
        actions.append(actionSave);
        if (!icon->canBeSaved())
            actionSave->setEnabled(false);

        // Insert Save As key
        auto* actionSaveAs = new QAction(this);
        actionSaveAs->setObjectName(QString::fromUtf8("actionSaveAs"));
        actionSaveAs->setText(tr("Save as ..."));
        actionSaveAs->setShortcut(QKeySequence::SaveAs);
        actions.append(actionSaveAs);
        if (!icon->canBeSavedAs())
            actionSaveAs->setEnabled(false);

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

        QAction* res = QMenu::exec(actions, view_->mapToGlobal(position));
        if (res == actionInfo)
            slotShowInfo();
        else if (res == actionEdit)
            icon->startEditor();
        else if (res == actionSave)
            icon->saveIcon();
        else if (res == actionSaveAs)
            icon->saveAsIcon();
        else if (res == actionDelete)
            icon->deleteIcon();
    }

    foreach (QAction* ac, actions)
        delete ac;
}

void MvQLayerWidget::slotFrameChanged()
{
}

void MvQLayerWidget::layersAreAboutToChange()
{
    // Save expand state
    QModelIndexList indexLst = model_->match(model_->index(0, 0),
                                             Qt::DisplayRole, "*", -1,
                                             Qt::MatchWildcard | Qt::MatchRecursive);

    expandList_.clear();
    foreach (QModelIndex index, indexLst) {
        QModelIndex proxyIndex = filterModel_->mapFromSource(index);
        if (view_->isExpanded(proxyIndex))
            expandList_ << index;
    }

    // Notify the layer model
    model_->layersAreAboutToChange();
}

/*void MvQLayerWidget::reset(MgQSceneItem *sceneItem,int layerIndex)
{
    model_->resetLayers(sceneItem);

    QModelIndex index=model_->index(layerIndex,0);
    if(!index.isValid())
    {
        index=model_->index(model_->rowCount()-1,0);
    }

    if(index.isValid())
    {
        slotSelectLayer(index);
    }
    else
    {
        slotCheckItemStatus();
    }
}*/

void MvQLayerWidget::reset(MgQSceneItem* sceneItem, MgQLayerItem* layer)
{
    model_->resetLayers(sceneItem);

    int row = model_->layerToRow(layer);
    QModelIndex index = filterModel_->mapFromSource(model_->index(row, 0));
    if (index.isValid()) {
        //		slotSelectLayer(index);
        view_->setCurrentIndex(index);
    }
    else {
        slotCheckItemStatus();
    }

    // Try to restore the expand state
    foreach (QModelIndex index, expandList_) {
        if (model_->hasChildren(index)) {
            QModelIndex proxyIndex = filterModel_->mapFromSource(index);
            view_->setExpanded(proxyIndex, true);
        }
    }
}

void MvQLayerWidget::reset(MgQSceneItem* sceneItem)
{
    MgQLayerItem* layer = nullptr;
    MgQLayerItem* lastLayer = nullptr;

    if (sceneItem) {
        int presId = atoi(sceneItem->layout().id().c_str());
        spModel_->reset();
        vlModel_->reset(presId);
        for (int i = sceneItem->layerItems().count() - 1; i >= 0; i--) {
            MgQLayerItem* item = sceneItem->layerItems().at(i);
            lastLayer = item;

            QString str(item->layer().name().c_str());
            QStringList lst = str.split("/");
            if (!lst.isEmpty()) {
                str = lst.last();
            }

            if (str == lastSelectedLayerText_) {
                layer = item;
            }
        }
    }

    if (!layer) {
        layer = lastLayer;
    }

    // contentsLoaded_=false;
    reset(sceneItem, layer);
    // contentsLoaded_=true;
}


int MvQLayerWidget::layerAtGlobalPos(const QPoint& p)
{
    QPoint pv = view_->mapFromGlobal(p);

    QModelIndex index = filterModel_->mapToSource(view_->indexAt(pv));

    MvQLayerContentsIcon* icon = model_->indexToIcon(index);
    if (!icon)
        return -1;

    return -1;

    // Get the dataUinitId
    /*MvIcon& dropIcon =  cl->GetIconMain ();
    Cached verbTarget = dropIcon.Request ().getVerb ();
    if ( ObjectList::IsDataUnit ( verbTarget ) == true )
         set_value ( id->header, "_CONTENTS_DATAUNIT_ID", "%d", dropIcon.Id());*/

    /*if(index.isValid())
    {
        MgQLayerItem *layer=model_->rowToLayer(index.row());
        if(layer)
        {
            QString str(layer->layer().name().c_str());
        }
    }

    */
}

void MvQLayerWidget::slotIconDropped(const MvQDrop& source, const QModelIndex& target)
{
    // Get the layer information
    MgQLayerItem* layer = model_->layerFromAnyLevel(target);
    if (!layer) {
        MvLog().popup().warn() << "Invalid icon drop! Drop target must be a layer!";
        return;
    }

    // Consistency check
    int duId = 0;
    if (!checkDroppedIcon(source, layer, duId)) {
        MvLog().popup().warn() << "Invalid icon drop! This icon cannot be applied to layer=" << layer->name();
        return;
    }
    // Therefore, if the target icon is a dataunit and all the dropped
    // icons are visdefs then these visdefs should be applied only to this
    // dataunit, not to the whole presentable. In order to do so, the
    // output drawing request should have a tag _CONTENTS_DATAUNIT_ID,
    // containing the dataunit id.

    // Get the target Presentable (Page) id
    // Here, the dropping happened into a layer not a presentable.
    // Therefore, first get the layer's first child icon id and then
    // use this id to find the Presentable id
    // int iconId = atoi(layer->layer().id().c_str());  // layer id
    //   int iconId = atoi((*it).iconId().c_str());
    //   Presentable* pres = Root::Instance().FindSuperPage();
    //   int presId = pres->FindBranchIdByIconId(iconId);

#if 0
// Redraw uPlot: option 1: calls the uPlot redraw function
   // Analyse the dropping to determine the type of action to be taken
   std::string classSource = source.iconClass(0).toStdString();
   std::string classTarget = icon->type().toStdString();
   if ( classSource == classTarget )  // icons have the same type
   {
      // Read source icon request
      const char* cname = source.iconPath(0).toStdString().c_str();
      std::string sname = MakeUserPath(cname);
      MvRequest iconRequest;
      iconRequest.read(sname.c_str());

      // Add some hidden parameters. There are certain functions in Metview
      // that relies on them.
      if ( !(const char*)iconRequest("_NAME") )
         iconRequest("_NAME") = cname.c_str();

      if ( !(const char*)iconRequest("_CLASS") )
         iconRequest("_CLASS") = iconRequest.getVerb();

      // Replace target request in the database by the source request
      dataBase.UpdateIcon( icon->id().toInt(),iconRequest );

      // Redraw the whole map
      pres->HasDrawTask(true);
      pres->DrawTask();
   }
#endif


#if 0
// Redraw uPlot: option 2: calls yourself to redraw the plot
   // Create a new drop request
   MvRequest dropRequest("DROP");
   dropRequest("DROP_ID")   = presId;
   dropRequest("_CONTENTS") = 1;

   // Add the target dataunit request
   MvRequest iconRequest;
   std::string cname;
   std::string sname;

#if 0
   if ( addDU )
   {
      // Create icon path and read its request
      cname = (*it).iconName();
      sname = MakeUserPath(cname);
      iconRequest.setVerb((*it).iconClass().c_str());
      iconRequest("PATH") = sname.c_str();

      // Add some hidden parameters. There are certain functions
      // in Metview that relies on them.
      if ( !(const char*)iconRequest("_NAME") )
         iconRequest("_NAME") = (const char*)cname.c_str();

      if ( !(const char*)iconRequest("_CLASS") )
         iconRequest("_CLASS") = (const char*)(*it).iconClass().c_str();

      dropRequest = dropRequest + iconRequest;
   }
#endif

   // Create the dropped icons request
   for(int i = 0; i < source.iconNum(); i++)
   {
      // Create icon path and read its request
      cname = source.iconPath(i).toStdString();
      sname = MakeUserPath(cname);
      iconRequest.read(sname.c_str());

      // Add some hidden parameters. There are certain functions
      // in Metview that relies on them.
      if ( !(const char*)iconRequest("_NAME") )
         iconRequest("_NAME") = (const char*)cname.c_str();

      if ( !(const char*)iconRequest("_CLASS") )
         iconRequest("_CLASS") = (const char*)source.iconClass(i).toStdString().c_str();

      if ( addDU )
         iconRequest("_CONTENTS_DATAUNIT_ID") = (const char*)(*it).iconId().c_str();

      dropRequest = dropRequest + iconRequest;
   }

   // Call myself to process the request
   std::ostringstream appName;
   appName << "uPlot" << (long int)getpid();
   MvApplication::callService ( appName.str().c_str(),dropRequest,0 );

   return;
#endif
    // Redraw uPlot: option 3: call MvApplication to redraw the plot

    // Create a new drop request
    MvRequest dropRequest("DROP_REQUEST");
    // req("BATCH") = drop->batchNumber();
    dropRequest("ACTION") = 3;

    MvRequest subreq("DROP");
    subreq("DROP_ID") = model_->presentableId();
    subreq("_CONTENTS") = 1;
    if (duId > 0)
        subreq("_CONTENTS_DATAUNIT_ID") = duId;

    // Create the dropped icons request
    if (source.iconNum() > 0) {
        subreq.setValue("ICON_NAME", source.iconPath(0).toStdString().c_str());

        for (int i = 1; i < source.iconNum(); i++) {
            subreq.addValue("ICON_NAME", source.iconPath(i).toStdString().c_str());
        }
    }

#if 0
   for(int i = 0; i < source.iconNum(); i++)
   {
      // Create icon path and read its request
      cname = source.iconPath(i).toStdString();
      sname = MakeUserPath(cname);
      iconRequest.read(sname.c_str());

      // Add some hidden parameters. There are certain functions
      // in Metview that relies on them.
      if ( !(const char*)iconRequest("_NAME") )
         iconRequest("_NAME") = (const char*)cname.c_str();

      if ( !(const char*)iconRequest("_CLASS") )
         iconRequest("_CLASS") = (const char*)source.iconClass(i).toStdString().c_str();

      if ( addDU )
         iconRequest("_CONTENTS_DATAUNIT_ID") = (const char*)(*it).iconId().c_str();

      dropRequest = dropRequest + iconRequest;
   }
#endif

    dropRequest("HEADER") = subreq;

#if 0
   // Add View request if it exists
   if ( owner_ )
   {
   Presentable* pres = Root::Instance().FindSuperPage();
      if(pres)
      {
         MvRequest reqView =pres->GetView().ViewRequest();
         req("_CONTEXT") = reqView;
      }
      //Safety solution
      else
      {
         MvRequest reqView = owner_->Request()("PAGES");
         reqView = reqView("VIEW");
         req("_CONTEXT") = reqView;
      }
   }
#endif

    // Send drop request to the appropriate function
    emit sendDropRequest(&dropRequest);
}

void MvQLayerWidget::slotIconDroppedTopLevel(const MvQDrop& source)
{
    // Redraw uPlot: call MvApplication to redraw the plot
    // Create a new drop request
    MvRequest dropRequest("DROP_REQUEST");
    dropRequest("ACTION") = 3;

    MvRequest subreq("DROP");
    subreq("DROP_ID") = spModel_->presentableId();
    subreq("_CONTENTS") = 1;
    //   if ( duId > 0 )
    //      subreq("_CONTENTS_DATAUNIT_ID") = duId;

    // Create the dropped icons request
    if (source.iconNum() > 0) {
        subreq.setValue("ICON_NAME", source.iconPath(0).toStdString().c_str());

        for (int i = 1; i < source.iconNum(); i++) {
            subreq.addValue("ICON_NAME", source.iconPath(i).toStdString().c_str());
        }
    }

    dropRequest("HEADER") = subreq;

    // Send drop request to the appropriate function
    emit sendDropRequest(&dropRequest);
}

void MvQLayerWidget::slotIconDroppedViewLevel(const MvQDrop& source)
{
    // Redraw uPlot: call MvApplication to redraw the plot
    // Create a new drop request
    MvRequest dropRequest("DROP_REQUEST");
    dropRequest("ACTION") = 3;

    MvRequest subreq("DROP");
    subreq("DROP_ID") = vlModel_->presentableId();
    subreq("_CONTENTS") = 1;

    // Create the dropped icons request
    if (source.iconNum() > 0) {
        subreq.setValue("ICON_NAME", source.iconPath(0).toStdString().c_str());

        for (int i = 1; i < source.iconNum(); i++) {
            subreq.addValue("ICON_NAME", source.iconPath(i).toStdString().c_str());
        }
    }

    dropRequest("HEADER") = subreq;

    // Send drop request to the appropriate function
    emit sendDropRequest(&dropRequest);
}

bool MvQLayerWidget::checkDroppedIcon(const MvQDrop& source, MgQLayerItem* layer, int& duId)
{
    // Special dropping case in Metview.
    // Here, the dropping happened into a Layer not a Presentable.
#if 1
    // Get list of icons related to this layer
    duId = -1;
    MvIconList iconList;
    int layerId = atoi(layer->layer().id().c_str());
    Presentable* pres = Root::Instance().FindSuperPage();
    pres->RetrieveIconsFromLayer(layerId, iconList);
    if (iconList.empty())
        return false;

    // Get the target icon class by taking the first icon from the list.
    // If there is a dataUnit, it is the first in the list
    auto lCursor = iconList.begin();
    // qDebug() << iconList.size() << (*lCursor).IconName() << (*lCursor).IconClass() << (*lCursor).Id();
    std::string targetClass = (*lCursor).IconClass();
#else
    // Get the target icon class by taking the first icon from the list
    duId = -1;
    std::vector<MetviewIcon>::const_iterator it = layer->layer().iconsBegin();
    assert(it != layer->layer().iconsEnd());  // must have at least one icon
    std::string targetClass = (*it).iconClass();
#endif

    // First, check if target and source icons have all the same "class"
    // (e.g., READ and GRIB are both dataunits).
    std::string sourceClass;
    bool targetDu = ObjectList::IsDataUnit(targetClass.c_str());
    bool flag = true;
    for (int i = 0; i < source.iconNum(); i++) {
        sourceClass = source.iconClass(i).toStdString();
        if (targetClass != sourceClass) {
            // Check if both are dataunits
            if (!targetDu || !ObjectList::IsDataUnit(sourceClass.c_str())) {
                flag = false;
                break;
            }
        }
    }

    if (flag)
        return true;

    // Target and source icons have not the same class.
    // Second, check an exception: a visdef dropped on a dataunit.
    // Check if the target layer is a dataunit
    if (!targetDu)
        return false;

    // Check if the dropped icons are all visdefs
    for (int i = 0; i < source.iconNum(); i++) {
        sourceClass = source.iconClass(i).toStdString();
        if (!ObjectList::IsVisDef(sourceClass.c_str()))
            return false;
    }

    // Exception accepted
    duId = (*lCursor).Id();  // atoi((*it).iconId().c_str());

    return true;
}
