#include "MegaTransferView.h"

#include "MegaApplication.h"
#include "MegaMenuItemAction.h"
#include "MessageDialogOpener.h"
#include "Platform.h"
#include "TransfersWidget.h"
#include "Utilities.h"

#include <QIcon>
#include <QScrollBar>
#include <QtConcurrent/QtConcurrent>

#include <utility>

using namespace mega;

const int MAX_ITEMS_FOR_CONTEXT_MENU = 10;

// Multiple seletion

//Single seletion
QString MegaTransferView::cancelSingleActionText()
{
    return (tr("Cancel transfer?"));
}

QString MegaTransferView::clearSingleActionText()
{
    return (tr("Clear transfer?"));
}

// Static messages for context menu
QString MegaTransferView::pauseActionText(qsizetype count)
{
    return tr(
        "Pause transfer",
        "",
        static_cast<int>(std::min(count, static_cast<qsizetype>(std::numeric_limits<int>::max()))));
}

QString MegaTransferView::resumeActionText(qsizetype count)
{
    return tr(
        "Resume transfer",
        "",
        static_cast<int>(std::min(count, static_cast<qsizetype>(std::numeric_limits<int>::max()))));
}

QString MegaTransferView::cancelActionText(qsizetype count)
{
    return tr(
        "Cancel transfer",
        "",
        static_cast<int>(std::min(count, static_cast<qsizetype>(std::numeric_limits<int>::max()))));
}

QString MegaTransferView::clearActionText(qsizetype count)
{
    return tr(
        "Clear transfer",
        "",
        static_cast<int>(std::min(count, static_cast<qsizetype>(std::numeric_limits<int>::max()))));
}

QString MegaTransferView::cancelAndClearActionText(qsizetype count)
{
    return tr(
        "Cancel and clear transfer",
        "",
        static_cast<int>(std::min(count, static_cast<qsizetype>(std::numeric_limits<int>::max()))));
}

QMap<QMessageBox::StandardButton, QString> MegaTransferView::getCancelDialogButtons()
{
    return  QMap<QMessageBox::StandardButton, QString>{{QMessageBox::Yes, tr("Cancel")}, {QMessageBox::No, tr("Don't cancel")}};
}

QMap<QMessageBox::StandardButton, QString> MegaTransferView::getClearDialogButtons()
{
    return  QMap<QMessageBox::StandardButton, QString>{{QMessageBox::Yes,tr("Clear")}, {QMessageBox::No, tr("Don't clear")}};
}

QString MegaTransferView::errorOpeningFileText()
{
    return tr("Error opening file");
}

//Mega transfer view
MegaTransferView::MegaTransferView(QWidget* parent) :
    LoadingSceneView<TransferManagerLoadingItem, QTreeView>(parent),
    mDisableLink(false),
    mKeyNavigation(false),
    mParentTransferWidget(nullptr)
{
    setMouseTracking(true);
    setAutoScroll(false);

    verticalScrollBar()->installEventFilter(this);

    connect(&mOpenUrlWatcher, &QFutureWatcher<bool>::finished, this, &MegaTransferView::onOpenUrlFinished);

    loadingView().setDelayTimeToShowInMs(150);
}

void MegaTransferView::setup()
{
    setContextMenuPolicy(Qt::CustomContextMenu);
}

void MegaTransferView::setup(TransfersWidget* tw)
{
    mParentTransferWidget = tw;

    connect(MegaSyncApp->getTransfersModel(), &TransfersModel::internalMoveStarted, this, &MegaTransferView::onInternalMoveStarted);
    connect(MegaSyncApp->getTransfersModel(), &TransfersModel::internalMoveFinished, this, &MegaTransferView::onInternalMoveFinished);
}

QModelIndexList MegaTransferView::getTransfers(bool onlyVisible, TransferData::TransferStates state)
{
    QModelIndexList indexes;

    auto proxy(qobject_cast<QSortFilterProxyModel*>(model()));
    if(proxy)
    {
        auto sourceModel = MegaSyncApp->getTransfersModel();

        auto rowCount = onlyVisible ? proxy->rowCount(QModelIndex()) : sourceModel->rowCount(QModelIndex());

        for (auto row (0); row < rowCount; ++row)
        {
            auto index (model()->index(row, 0, QModelIndex()));
            auto d (qvariant_cast<TransferItem>(index.data()).getTransferData());
            if(state == TransferData::TRANSFER_NONE || (d && d->getState() & state))
            {
                if (proxy)
                {
                    index = proxy->mapToSource(index);
                }
                indexes.push_back(index);
            }
        }
    }

    return indexes;
}

QModelIndexList MegaTransferView::getSelectedTransfers()
{
    QModelIndexList indexes;

    if(!selectionModel())
    {
        return indexes;
    }

    auto selection = selectionModel()->selection();

    if (selection.size() > 0)
    {
        auto proxy(qobject_cast<QSortFilterProxyModel*>(model()));
        if (proxy)
        {
            selection = proxy->mapSelectionToSource(selection);
        }
        indexes = selection.indexes();
    }

    return indexes;
}

MegaTransferView::SelectedIndexesInfo MegaTransferView::getVisibleCancelOrClearInfo()
{
    SelectedIndexesInfo info;

    auto proxy (qobject_cast<TransfersManagerSortFilterProxyModel*>(model()));

    if(proxy)
    {
        info.isAnyCancellable = proxy->isAnyCancellable();
        info.areAllCancellable = proxy->areAllCancellable();
        info.areAllSync = proxy->areAllSync();
        auto isAnySync = proxy->isAnySync();
        auto isAnyCompleted = proxy->isAnyCompleted();

        if(info.isAnyCancellable)
        {
            info.buttonsText = getCancelDialogButtons();

            if(!isAnySync)
            {
                if(info.areAllCancellable || !isAnyCompleted)
                {
                    info.titleText = cancelTransfersMultiSelectionTitleText();
                    info.actionText = cancelCategoryTransfersDescriptionText();
                }
                else
                {
                    info.titleText = cancelTransfersMultiSelectionTitleText();
                    info.actionText = cancelAndClearDescriptionText();
                }
            }
            else
            {
                if(isAnyCompleted)
                {
                    info.titleText = cancelTransfersMultiSelectionTitleText();
                    info.actionText = cancelAndClearTransfersWithSyncDescriptionText();
                }
                else
                {
                    info.titleText = cancelTransfersMultiSelectionTitleText();
                    info.actionText = cancelTransfersWithSyncDescriptionText();
                }
            }
        }
        else
        {
            info.titleText = clearTransfersMultiSelectionTitleText();
            info.actionText = clearCategoryTransfersDescriptionText();
            info.buttonsText = getClearDialogButtons();
        }
    }

    return info;
}

MegaTransferView::SelectedIndexesInfo MegaTransferView::getSelectedCancelOrClearInfo()
{
    auto indexes = getSelectedTransfers();

    SelectedIndexesInfo info;
    bool isAnyActiveSync(false);
    bool isAnyCompleted(false);

    foreach(auto& index, indexes)
    {
        auto transfer (qvariant_cast<TransferItem>(index.data()).getTransferData());
        if(transfer)
        {
            if(!transfer->isSyncTransfer())
            {
                info.areAllSync = false;

                if(transfer->isActiveOrPending() || transfer->isFailed())
                {
                    info.isAnyCancellable = true;
                }
                else
                {
                    info.areAllCancellable = false;
                }
            }
            else if(!transfer->isCompleted())
            {
                isAnyActiveSync = true;
                info.areAllCancellable = false;
            }

            if(transfer->isCompleted())
            {
                isAnyCompleted = true;
            }
        }
    }


    if(indexes.size() > 1)
    {
        info.buttonsText = getCancelDialogButtons();
        if(isAnyActiveSync)
        {
            if(isAnyCompleted)
            {
                info.titleText = info.isAnyCancellable ? cancelTransfersMultiSelectionTitleText() :
                                                         clearTransfersMultiSelectionTitleText();
                info.actionText = info.isAnyCancellable ?
                                      cancelAndClearSelectedWithSyncDescriptionText() :
                                      clearSelectedCompletedTransfersDescriptionText();
            }
            else if(info.isAnyCancellable)
            {
                info.titleText = cancelTransfersMultiSelectionTitleText();
                info.actionText = cancelSelectedWithSyncsDescriptionText();
            }

        }
        else
        {
            if(isAnyCompleted)
            {
                if(info.isAnyCancellable)
                {
                    info.titleText = cancelTransfersMultiSelectionTitleText();
                    info.actionText = cancelAndClearSelectedDescriptionText();
                }
                else
                {
                    info.titleText = clearTransfersMultiSelectionTitleText();
                    info.actionText = clearSelectedCompletedTransfersDescriptionText();
                    info.buttonsText = getClearDialogButtons();
                }
            }
            else if(info.isAnyCancellable)
            {
                info.titleText = cancelTransfersMultiSelectionTitleText();
                info.actionText = cancelSelectedDescriptionText();
            }
        }
    }
    else
    {
        if(info.isAnyCancellable)
        {
            info.actionText = cancelSingleActionText();
        }
        else
        {
            info.actionText = clearSingleActionText();
        }
    }


    return info;
}

void MegaTransferView::onPauseResumeVisibleRows(bool pauseState)
{
    QModelIndexList indexes = getTransfers(true);

    auto sourceModel = MegaSyncApp->getTransfersModel();
    sourceModel->pauseTransfers(indexes, pauseState);

    //Use to repaint and update the transfers state
    update();
}

void MegaTransferView::onPauseResumeSelection(bool pauseState)
{
    QModelIndexList indexes = getSelectedTransfers();
    auto sourceModel = MegaSyncApp->getTransfersModel();

    sourceModel->pauseTransfers(indexes, pauseState);

    //Use to repaint and update the transfers state
    update();
}

void MegaTransferView::onCancelVisibleTransfers()
{
    auto info = getVisibleCancelOrClearInfo();

    if(!info.areAllSync)
    {
        MessageDialogInfo msgInfo;
        msgInfo.titleText = info.titleText;
        msgInfo.descriptionText = info.actionText;
        msgInfo.parent = Utilities::getTopParent<QDialog>(this);
        msgInfo.buttons = QMessageBox::Yes | QMessageBox::No;
        msgInfo.defaultButton = QMessageBox::No;
        msgInfo.buttonsText = info.buttonsText;

        msgInfo.finishFunc = [this](QPointer<MessageDialogResult> msg)
        {
            if(msg->result() == QMessageBox::Yes)
            {
                auto indexes = getTransfers(true);

                auto sourceModel = MegaSyncApp->getTransfersModel();
                sourceModel->cancelAndClearTransfers(indexes, this);
            }
        };

        MessageDialogOpener::warning(msgInfo);
    }
}

void MegaTransferView::onCancelSelectedTransfers()
{
    auto info = getSelectedCancelOrClearInfo();

    MessageDialogInfo msgInfo;
    msgInfo.titleText = info.titleText;
    msgInfo.descriptionText = info.actionText;
    msgInfo.parent = Utilities::getTopParent<QDialog>(this);
    msgInfo.buttons = QMessageBox::Yes | QMessageBox::No;
    msgInfo.defaultButton = QMessageBox::No;
    msgInfo.buttonsText = info.buttonsText;

    msgInfo.finishFunc = [this](QPointer<MessageDialogResult> msg)
    {
        if(msg->result() == QMessageBox::Yes)
        {
            QModelIndexList indexes = getSelectedTransfers();
            selectionModel()->clear();
            verticalScrollBar()->setValue(0);

            auto sourceModel = MegaSyncApp->getTransfersModel();
            sourceModel->cancelAndClearTransfers(indexes, this);
        }
    };

    MessageDialogOpener::warning(msgInfo);
}

QString MegaTransferView::cancelTransfersMultiSelectionTitleText()
{
    return tr("Cancel transfers?");
}

QString MegaTransferView::clearTransfersMultiSelectionTitleText()
{
    return tr("Clear transfers?");
}

QString MegaTransferView::cancelAllDescriptionText()
{
    return tr("All your transfers will be cancelled.");
}

QString MegaTransferView::cancelAndClearDescriptionText()
{
    return tr("All your transfers in this category will be cancelled and cleared.");
}

QString MegaTransferView::cancelCategoryTransfersDescriptionText()
{
    return tr("All your transfers in this category will be cancelled.");
}

QString MegaTransferView::cancelTransfersWithSyncDescriptionText()
{
    return tr("Your incomplete sync transfers won't be cancelled.");
}

QString MegaTransferView::cancelAndClearTransfersWithSyncDescriptionText()
{
    return tr("Your incomplete sync transfers won't be cancelled\n"
              "All the other transfers will be cancelled and cleared.");
}

QString MegaTransferView::clearAllCompletedDescriptionText()
{
    return tr("All your completed transfers will be cleared.");
}

QString MegaTransferView::clearCategoryTransfersDescriptionText()
{
    return tr("All your completed transfers in this category will be cleared.");
}

QString MegaTransferView::cancelSelectedDescriptionText()
{
    return tr("All your selected transfers will be cancelled.");
}

QString MegaTransferView::cancelAndClearSelectedDescriptionText()
{
    return tr("All your selected transfers will be cancelled and cleared.");
}

QString MegaTransferView::cancelSelectedWithSyncsDescriptionText()
{
    return tr("Your selected incomplete sync transfers won't be cancelled.");
}

QString MegaTransferView::cancelAndClearSelectedWithSyncDescriptionText()
{
    return tr("Your selected incomplete sync transfers won't be cancelled\n"
              "All the other selected transfers will be cancelled and cleared.");
}

QString MegaTransferView::clearSelectedCompletedTransfersDescriptionText()
{
    return tr("All the selected completed transfers in this category will be cleared.");
}

void MegaTransferView::onCancelAllTransfers()
{
    auto proxy (qobject_cast<TransfersManagerSortFilterProxyModel*>(model()));

    if (proxy)
    {
        MessageDialogInfo msgInfo;
        msgInfo.titleText = cancelTransfersMultiSelectionTitleText();
        msgInfo.descriptionText = proxy->isAnySync() ? cancelTransfersWithSyncDescriptionText() :
                                                       cancelAllDescriptionText();
        msgInfo.parent = Utilities::getTopParent<QDialog>(this);
        msgInfo.buttons = QMessageBox::Yes | QMessageBox::No;
        msgInfo.defaultButton = QMessageBox::No;
        msgInfo.buttonsText = getCancelDialogButtons();

        msgInfo.finishFunc = [this](QPointer<MessageDialogResult> msg)
        {
            if(msg->result() == QMessageBox::Yes)
            {
                cancelAllTransfers();
                emit allCancelled();
            }
        };

        MessageDialogOpener::warning(msgInfo);
    }
}

void MegaTransferView::onClearAllTransfers()
{
    MessageDialogInfo msgInfo;
    msgInfo.titleText = clearTransfersMultiSelectionTitleText();
    msgInfo.descriptionText = clearAllCompletedDescriptionText();
    msgInfo.parent = Utilities::getTopParent<QDialog>(this);
    msgInfo.buttons = QMessageBox::Yes | QMessageBox::No;
    msgInfo.defaultButton = QMessageBox::No;
    msgInfo.buttonsText = getClearDialogButtons();

    msgInfo.finishFunc = [this](QPointer<MessageDialogResult> msg)
    {
        if(msg->result() == QMessageBox::Yes)
        {
            clearAllTransfers();
        }
    };

    MessageDialogOpener::warning(msgInfo);
}

void MegaTransferView::onCancelAndClearVisibleTransfers()
{
    auto info = getVisibleCancelOrClearInfo();

    MessageDialogInfo msgInfo;
    msgInfo.titleText = info.titleText;
    msgInfo.descriptionText = info.actionText;
    msgInfo.parent = Utilities::getTopParent<QDialog>(this);
    msgInfo.buttons = QMessageBox::Yes | QMessageBox::No;
    msgInfo.defaultButton = QMessageBox::No;
    msgInfo.buttonsText = info.buttonsText;

    msgInfo.finishFunc = [this](QPointer<MessageDialogResult> msg)
    {
        if(msg->result() == QMessageBox::Yes)
        {
            auto sourceModel = MegaSyncApp->getTransfersModel();

            auto indexes = getTransfers(true, TransferData::FINISHED_STATES_MASK);
            sourceModel->clearTransfers(indexes);

            //Cancel transfers
            auto cancelIndexes = getTransfers(true);
            sourceModel->cancelAndClearTransfers(cancelIndexes, this);
        }
    };

    MessageDialogOpener::warning(msgInfo);
}

void MegaTransferView::onClearVisibleTransfers()
{
    MessageDialogInfo msgInfo;
    msgInfo.titleText = clearTransfersMultiSelectionTitleText();
    msgInfo.descriptionText = clearCategoryTransfersDescriptionText();
    msgInfo.parent = Utilities::getTopParent<QDialog>(this);
    msgInfo.buttons = QMessageBox::Yes | QMessageBox::No;
    msgInfo.defaultButton = QMessageBox::No;
    msgInfo.buttonsText = getClearDialogButtons();

    msgInfo.finishFunc = [this](QPointer<MessageDialogResult> msg)
    {
        if(msg->result() == QMessageBox::Yes)
        {
            auto sourceModel = MegaSyncApp->getTransfersModel();

            auto indexes = getTransfers(true, TransferData::FINISHED_STATES_MASK);
            sourceModel->clearTransfers(indexes);
        }
    };

    MessageDialogOpener::warning(msgInfo);
}

void MegaTransferView::clearAllTransfers()
{    
    auto sourceModel = MegaSyncApp->getTransfersModel();

    sourceModel->pauseModelProcessing(true);
    sourceModel->clearAllTransfers();
    sourceModel->pauseModelProcessing(false);
}

void MegaTransferView::cancelAllTransfers()
{
    auto sourceModel = MegaSyncApp->getTransfersModel();

    sourceModel->pauseModelProcessing(true);
    sourceModel->cancelAllTransfers(this);
    sourceModel->pauseModelProcessing(false);
}

int MegaTransferView::getVerticalScrollBarWidth() const
{
    return verticalScrollBar()->width();
}

void MegaTransferView::onRetryVisibleTransfers()
{
    TransferMetaDataContainer::retryAllPressed();

    QModelIndexList indexes = getTransfers(true, TransferData::TRANSFER_FAILED);

    auto sourceModel = MegaSyncApp->getTransfersModel();
    sourceModel->retryTransfers(indexes);
}

void MegaTransferView::onCancelClearSelection(bool isClear)
{
    QModelIndexList indexes = getSelectedTransfers();

    auto sourceModel = MegaSyncApp->getTransfersModel();
    isClear ? sourceModel->clearTransfers(indexes) : sourceModel->cancelAndClearTransfers(indexes, this);
}

void MegaTransferView::enableContextMenu()
{
    setContextMenuPolicy(Qt::CustomContextMenu);
    connect(this, &MegaTransferView::customContextMenuRequested,
            this, &MegaTransferView::onCustomContextMenu);
}

void MegaTransferView::onCustomContextMenu(const QPoint& point)
{
    auto contextMenu = createContextMenu();

    if(!contextMenu->actions().isEmpty())
    {
        contextMenu->exec(mapToGlobal(point));
    }
}

QMenu* MegaTransferView::createContextMenu()
{
    auto contextMenu = new QMenu(this);
    contextMenu->setProperty("class", QLatin1String("MegaMenu"));
    contextMenu->setProperty("icon-token", QLatin1String("icon-primary"));
    contextMenu->setAttribute(Qt::WA_DeleteOnClose);

    QModelIndexList indexes = selectedIndexes();
    auto modelSize = model()->rowCount();

    bool isTopIndex = false;
    bool isBottomIndex = false;

    TransferData::TransferStates overallState;
    TransferData::TransferTypes overallType;
    bool containsIncomingShares(false);
    long long int movableTransfers(0);
    bool containsInvalidNodes(false);

    //TODO use these containers to open links, open folder...etc
    QList<MegaHandle> handlesToOpenByContextMenu;
    QList<QDir> localFoldersToOpenByContextMenu;
    QList<QFileInfo> localFilesToOpenByContextMenu;

    auto proxy(qobject_cast<TransfersManagerSortFilterProxyModel*>(model()));

    for (auto index: std::as_const(indexes))
    {
        if(index.row() == 0)
        {
            isTopIndex = proxy->getSortCriterion() == static_cast<int>(SortCriterion::PRIORITY);
        }

        if(index.row() == (modelSize -1))
        {
            isBottomIndex = proxy->getSortCriterion() == static_cast<int>(SortCriterion::PRIORITY);
        }

        auto d (qvariant_cast<TransferItem>(index.data()).getTransferData());

        if(!containsInvalidNodes && (d->isCompleted() || d->mType & TransferData::TRANSFER_DOWNLOAD))
        {
            std::unique_ptr<mega::MegaNode> node(MegaSyncApp->getMegaApi()->getNodeByHandle(d->mNodeHandle));
            if (node == nullptr || MegaSyncApp->getMegaApi()->isInRubbish(node.get()))
            {
                containsInvalidNodes = true;
            }
            if (!containsInvalidNodes)
            {
                if (!containsIncomingShares && Utilities::isIncommingShare(node.get()))
                {
                    containsIncomingShares = true;
                }
                //Handles to open
                if (handlesToOpenByContextMenu.size() <= MAX_ITEMS_FOR_CONTEXT_MENU)
                {

                    auto parentNode = mParentTransferWidget->getModel()->getParentNodeToOpenByRow(index.row());
                    if (parentNode && !handlesToOpenByContextMenu.contains(parentNode->getHandle()))
                    {
                        handlesToOpenByContextMenu.append(parentNode->getHandle());
                    }
                }
            }
        }

        if(d->isCompleted() || d->mType & TransferData::TRANSFER_UPLOAD)
        {
            if(localFoldersToOpenByContextMenu.size() <= MAX_ITEMS_FOR_CONTEXT_MENU || localFilesToOpenByContextMenu.size() <= MAX_ITEMS_FOR_CONTEXT_MENU)
            {
                QFileInfo fileInfo = mParentTransferWidget->getModel()->getFileInfoByIndex(index);
                if(localFilesToOpenByContextMenu.size() <= MAX_ITEMS_FOR_CONTEXT_MENU && !localFilesToOpenByContextMenu.contains(fileInfo))
                {
                    localFilesToOpenByContextMenu.append(fileInfo);
                }

                if(localFoldersToOpenByContextMenu.size() <= MAX_ITEMS_FOR_CONTEXT_MENU)
                {
                    QDir parentFolder(fileInfo.dir());
                    if(!localFoldersToOpenByContextMenu.contains(parentFolder))
                    {
                        localFoldersToOpenByContextMenu.append(parentFolder);
                    }
                }
            }
        }

        auto isMovableRow = [d, modelSize, &movableTransfers]()
        {
            if(modelSize > 1)
            {
                if(d->mType & TransferData::TRANSFER_UPLOAD
                        || d->mType & TransferData::TRANSFER_DOWNLOAD)
                {
                    movableTransfers++;
                }
            }
        };

        switch (d->getState())
        {
            case TransferData::TRANSFER_ACTIVE:
            case TransferData::TRANSFER_QUEUED:
            case TransferData::TRANSFER_RETRYING:
            {
                overallState |= TransferData::TRANSFER_ACTIVE;
                isMovableRow();
                break;
            }
            case TransferData::TRANSFER_PAUSED:
                isMovableRow();
                [[fallthrough]];
            default:
                overallState |= d->getState();
        }

        overallType |= d->mType;
    }

    enum EnableAction
    {
        NONE = 0,
        PAUSE = 0x1,
        RESUME = 0x2,
        CANCEL = 0x4,
        CLEAR = 0x8,
        MOVE = 0x10,
        LINK = 0x20,
        OPEN = 0x40
    };
    Q_DECLARE_FLAGS(EnableActions, EnableAction);

    EnableActions actionFlag(EnableAction::NONE);

    auto checkUnfinishedActionByType = [overallType, &actionFlag]()
    {
        if((overallType & TransferData::TRANSFER_UPLOAD) && !(overallType & (TransferData::TRANSFER_DOWNLOAD | TransferData::TRANSFER_LTCPDOWNLOAD)))
        {
            actionFlag |= EnableAction::OPEN;
        }
        else if((overallType & TransferData::TRANSFER_DOWNLOAD) && !(overallType & TransferData::TRANSFER_UPLOAD))
        {
            actionFlag |= EnableAction::LINK;
        }
    };

    //Are all completed
    if(overallState == TransferData::TRANSFER_COMPLETED)
    {
        actionFlag |= EnableAction::CLEAR;
        actionFlag |= EnableAction::LINK;
        actionFlag |= EnableAction::OPEN;
    }
    else if(overallState == TransferData::TRANSFER_FAILED)
    {
        actionFlag |= EnableAction::CLEAR;
        checkUnfinishedActionByType();
    }
    else if(overallState & TransferData::TRANSFER_PAUSED || overallState & TransferData::TRANSFER_ACTIVE)
    {
        if(overallState & TransferData::TRANSFER_COMPLETED)
        {
            actionFlag |= EnableAction::CLEAR;
        }
        else
        {
            //only if all selected indexes can be moved, the move action is enabled
            if(movableTransfers == indexes.size())
            {
                actionFlag |= EnableAction::MOVE;
            }

            if(overallState & TransferData::TRANSFER_ACTIVE)
            {
                actionFlag |= EnableAction::PAUSE;
            }
            else if(overallState & TransferData::TRANSFER_PAUSED)
            {
                actionFlag |= EnableAction::RESUME;
            }
        }

        if(!(overallType & TransferData::TRANSFER_SYNC))
        {
            actionFlag |= EnableAction::CANCEL;
        }

        checkUnfinishedActionByType();
    }

    bool addSeparator(false);

    if (actionFlag & EnableAction::PAUSE)
    {
        auto pauseAction =
            new MegaMenuItemAction(pauseActionText(indexes.size()),
                                   Utilities::getPixmapName(QLatin1String("pause"),
                                                            Utilities::AttributeType::SMALL |
                                                                Utilities::AttributeType::THIN |
                                                                Utilities::AttributeType::OUTLINE,
                                                            false),
                                   0,
                                   contextMenu);
        connect(pauseAction, &QAction::triggered, this, &MegaTransferView::pauseSelectedClicked);

        contextMenu->addAction(pauseAction);
        addSeparator = true;
    }

    if(actionFlag & EnableAction::RESUME)
    {
        auto resumeAction =
            new MegaMenuItemAction(resumeActionText(indexes.size()),
                                   Utilities::getPixmapName(QLatin1String("play"),
                                                            Utilities::AttributeType::SMALL |
                                                                Utilities::AttributeType::THIN |
                                                                Utilities::AttributeType::OUTLINE,
                                                            false),
                                   0,
                                   contextMenu);
        connect(resumeAction, &QAction::triggered,
                this, &MegaTransferView::resumeSelectedClicked);

        contextMenu->addAction(resumeAction);

        addSeparator = true;
    }

    addSeparatorToContextMenu(addSeparator, contextMenu);

    if(actionFlag & EnableAction::OPEN)
    {
        if(localFilesToOpenByContextMenu.size() <= MAX_ITEMS_FOR_CONTEXT_MENU)
        {
            auto openItemAction = new MegaMenuItemAction(
                tr("Open"),
                Utilities::getPixmapName(QLatin1String("external_link"),
                                         Utilities::AttributeType::SMALL |
                                             Utilities::AttributeType::THIN |
                                             Utilities::AttributeType::OUTLINE,
                                         false),
                0,
                contextMenu);
            connect(openItemAction, &QAction::triggered, this, &MegaTransferView::openItemClicked);

            contextMenu->addAction(openItemAction);
        }

        if(localFoldersToOpenByContextMenu.size() <= MAX_ITEMS_FOR_CONTEXT_MENU)
        {
            //Ico not included in transfer manager folder as it is also used by settingsDialog
            auto showInFolderAction = new MegaMenuItemAction(
                tr("Show in folder"),
                Utilities::getPixmapName(QLatin1String("folder-open"),
                                         Utilities::AttributeType::SMALL |
                                             Utilities::AttributeType::THIN |
                                             Utilities::AttributeType::OUTLINE,
                                         false),
                0,
                contextMenu);
            connect(showInFolderAction, &QAction::triggered, this, &MegaTransferView::showInFolderClicked);

            contextMenu->addAction(showInFolderAction);
            addSeparator = true;
        }
    }

    addSeparatorToContextMenu(addSeparator, contextMenu);

    if(actionFlag & EnableAction::LINK)
    {
        if (!containsInvalidNodes)
        {
            if (handlesToOpenByContextMenu.size() <= MAX_ITEMS_FOR_CONTEXT_MENU)
            {
                //Ico not included in transfer manager folder as it is also used by settingsDialog
                auto openInMEGAAction = new MegaMenuItemAction(
                    tr("Open in MEGA"),
                    Utilities::getPixmapName(QLatin1String("MEGA"),
                                             Utilities::AttributeType::SMALL |
                                                 Utilities::AttributeType::THIN |
                                                 Utilities::AttributeType::OUTLINE,
                                             false),
                    0,
                    contextMenu);
                connect(openInMEGAAction, &QAction::triggered, this, &MegaTransferView::openInMEGAClicked);

                contextMenu->addAction(openInMEGAAction);
            }
            if (!containsIncomingShares)
            {
                auto getLinkAction = new MegaMenuItemAction(
                    tr("Get link"),
                    Utilities::getPixmapName(QLatin1String("link-01"),
                                             Utilities::AttributeType::SMALL |
                                                 Utilities::AttributeType::THIN |
                                                 Utilities::AttributeType::OUTLINE,
                                             false),
                    0,
                    contextMenu);
                connect(getLinkAction, &QAction::triggered, this, &MegaTransferView::getLinkClicked);

                contextMenu->addAction(getLinkAction);
            }
        }

        addSeparator = true;
    }

    addSeparatorToContextMenu(addSeparator, contextMenu);

    if (actionFlag & EnableAction::MOVE)
    {
        if (!isTopIndex)
        {
            auto moveToTopAction = new MegaMenuItemAction(
                tr("Move to top"),
                Utilities::getPixmapName(QLatin1String("move-top"),
                                         Utilities::AttributeType::SMALL |
                                             Utilities::AttributeType::THIN |
                                             Utilities::AttributeType::OUTLINE,
                                         false),
                0,
                contextMenu);
            connect(moveToTopAction,
                    &QAction::triggered,
                    this,
                    &MegaTransferView::moveToTopClicked);

            auto moveUpAction = new MegaMenuItemAction(
                tr("Move up"),
                Utilities::getPixmapName(QLatin1String("move-up"),
                                         Utilities::AttributeType::SMALL |
                                             Utilities::AttributeType::THIN |
                                             Utilities::AttributeType::OUTLINE,
                                         false),
                0,
                contextMenu);
            connect(moveUpAction, &QAction::triggered, this, &MegaTransferView::moveUpClicked);

            contextMenu->addAction(moveToTopAction);
            contextMenu->addAction(moveUpAction);

            addSeparator = true;
        }

        if (!isBottomIndex)
        {
            auto moveDownAction = new MegaMenuItemAction(
                tr("Move down"),
                Utilities::getPixmapName(QLatin1String("move-down"),
                                         Utilities::AttributeType::SMALL |
                                             Utilities::AttributeType::THIN |
                                             Utilities::AttributeType::OUTLINE,
                                         false),
                0,
                contextMenu);
            connect(moveDownAction, &QAction::triggered, this, &MegaTransferView::moveDownClicked);

            auto moveToBottomAction = new MegaMenuItemAction(
                tr("Move to bottom"),
                Utilities::getPixmapName(QLatin1String("move-bottom"),
                                         Utilities::AttributeType::SMALL |
                                             Utilities::AttributeType::THIN |
                                             Utilities::AttributeType::OUTLINE,
                                         false),
                0,
                contextMenu);
            connect(moveToBottomAction,
                    &QAction::triggered,
                    this,
                    &MegaTransferView::moveToBottomClicked);

            contextMenu->addAction(moveDownAction);
            contextMenu->addAction(moveToBottomAction);

            addSeparator = true;
        }

        addSeparatorToContextMenu(addSeparator, contextMenu);
    }

    if(actionFlag & EnableAction::CANCEL)
    {
        auto cancelAction = new MegaMenuItemAction(
            actionFlag & EnableAction::CLEAR ? cancelAndClearActionText(indexes.size()) :
                                               cancelActionText(indexes.size()),
            Utilities::getPixmapName(QLatin1String("x"),
                                     Utilities::AttributeType::SMALL |
                                         Utilities::AttributeType::THIN |
                                         Utilities::AttributeType::OUTLINE,
                                     false),
            0,
            contextMenu);
        connect(cancelAction, &QAction::triggered,
                this, &MegaTransferView::cancelSelectedClicked);

        contextMenu->addAction(cancelAction);

        // Set default action to have it painted red
        contextMenu->setDefaultAction(cancelAction);
    }
    else if(actionFlag & EnableAction::CLEAR)
    {
        auto clearAction =
            new MegaMenuItemAction(tr("Clear"),
                                   Utilities::getPixmapName(QLatin1String("eraser"),
                                                            Utilities::AttributeType::SMALL |
                                                                Utilities::AttributeType::THIN |
                                                                Utilities::AttributeType::OUTLINE,
                                                            false),
                                   0,
                                   contextMenu);
        connect(clearAction, &QAction::triggered,
                this, &MegaTransferView::clearSelectedClicked);

        contextMenu->addAction(clearAction);
    }

    return contextMenu;
}


void MegaTransferView::addSeparatorToContextMenu(bool& addSeparator, QMenu* contextMenu)
{
    if(addSeparator)
    {
        contextMenu->addSeparator();
        addSeparator = false;
    }
}

void MegaTransferView::mouseReleaseEvent(QMouseEvent* event)
{
    auto pressedIndex = indexAt(event->pos());
    if(!pressedIndex.isValid())
    {
        clearSelection();
    }

    LoadingSceneView::mouseReleaseEvent(event);
}

void MegaTransferView::mouseMoveEvent(QMouseEvent *event)
{
    if (event->button() == Qt::RightButton)
    {
        return;
    }

    LoadingSceneView::mouseMoveEvent(event);
}

bool MegaTransferView::event(QEvent* event)
{
    if (event->type() == QEvent::LanguageChange)
    {
        viewport()->update();
    }

    return LoadingSceneView::event(event);
}

void MegaTransferView::dropEvent(QDropEvent* event)
{
    QAbstractItemView::dropEvent(event);
    event->acceptProposedAction();
    clearSelection();
}

void MegaTransferView::keyPressEvent(QKeyEvent *event)
{
    if(event->key() == Qt::Key_Delete)
    {
        onCancelSelectedTransfers();
    }
    else if(event->key() == Qt::Key_Down || event->key() == Qt::Key_Up)
    {
        mKeyNavigation = true;
    }

    LoadingSceneView::keyPressEvent(event);

    if(mKeyNavigation)
    {
        mKeyNavigation = false;
    }
}

void MegaTransferView::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
    if(mKeyNavigation)
    {
        auto selectedIndexes = selected.indexes();
        auto deselectedIndexes = deselected.indexes();

        if(!selectedIndexes.isEmpty())
        {
            scrollTo(selectedIndexes.last(), QAbstractItemView::PositionAtCenter);
        }
        else if(!deselectedIndexes.isEmpty())
        {
            scrollTo(deselectedIndexes.last(), QAbstractItemView::PositionAtCenter);
        }
    }

    LoadingSceneView::selectionChanged(selected, deselected);
}

bool MegaTransferView::eventFilter(QObject *object, QEvent *event)
{
    if(object == verticalScrollBar())
    {
        if(event->type() == QEvent::Show)
        {
            emit verticalScrollBarVisibilityChanged(true);
        }
        else if(event->type() == QEvent::Hide)
        {
            emit verticalScrollBarVisibilityChanged(false);
        }
    }

    return LoadingSceneView::eventFilter(object, event);
}

void MegaTransferView::paintEvent(QPaintEvent *event)
{
    //This is done to keep the dragging state even if the model has removed/inserted items
    //as Qt changes the view state when these actions are done.
    //If the dragging state is changed, the drag and drop line is not painted anymore, so we need to restore it before painting it
    auto proxy(qobject_cast<TransfersManagerSortFilterProxyModel*>(model()));
    if(proxy)
    {
        if(proxy->isDragging())
        {
            setState(DraggingState);
        }
    }

    LoadingSceneView::paintEvent(event);
}

void MegaTransferView::moveToTopClicked()
{
    auto proxy(qobject_cast<TransfersManagerSortFilterProxyModel*>(model()));
    if(proxy)
    {
        if(!selectionModel())
        {
            return;
        }

        auto indexes = selectionModel()->selectedRows();
        if(!indexes.isEmpty())
        {
            auto sourceModel = MegaSyncApp->getTransfersModel();

            sourceModel->moveTransferPriorityToTop(proxy->mapToSourceList(indexes));
        }
    }

    clearSelection();
}

void MegaTransferView::moveUpClicked()
{
    auto proxy(qobject_cast<TransfersManagerSortFilterProxyModel*>(model()));
    if (proxy && selectionModel())
    {
        auto indexes = selectionModel()->selectedRows();
        if (!indexes.isEmpty())
        {
            auto sourceModel = MegaSyncApp->getTransfersModel();

            sourceModel->moveTransferPriorityUp(proxy->mapToSourceList(indexes));
        }
    }

    clearSelection();
}

void MegaTransferView::moveDownClicked()
{
    auto proxy(qobject_cast<TransfersManagerSortFilterProxyModel*>(model()));
    if (proxy && selectionModel())
    {
        auto indexes = selectionModel()->selectedRows();
        if (!indexes.isEmpty())
        {
            auto sourceModel = MegaSyncApp->getTransfersModel();

            sourceModel->moveTransferPriorityDown(proxy->mapToSourceList(indexes));
        }
    }

    clearSelection();
}

void MegaTransferView::moveToBottomClicked()
{
    auto proxy(qobject_cast<TransfersManagerSortFilterProxyModel*>(model()));
    if (proxy && selectionModel())
    {
        auto indexes = selectionModel()->selectedRows();
        if (!indexes.isEmpty())
        {
            auto sourceModel = MegaSyncApp->getTransfersModel();

            sourceModel->moveTransferPriorityToBottom(proxy->mapToSourceList(indexes));
        }
    }

    clearSelection();
}

void MegaTransferView::getLinkClicked()
{
    if (mDisableLink)
    {
        return;
    }

    QList<int> rows;
    auto proxy(qobject_cast<QSortFilterProxyModel*>(model()));

    QModelIndexList indexes;
    if(selectionModel())
    {
        if(proxy)
        {
            indexes = proxy->mapSelectionToSource(selectionModel()->selection()).indexes();
        }
        else
        {
            indexes = selectionModel()->selection().indexes();
        }
    }

    for (auto index: std::as_const(indexes))
    {
        rows.push_back(index.row());
    }

    if (!rows.isEmpty())
    {
        mParentTransferWidget->getModel()->getLinks(rows);
    }

    clearSelection();
}

void MegaTransferView::openInMEGAClicked()
{
    if (mDisableLink)
    {
        return;
    }

    QList<int> rows;
    auto proxy(qobject_cast<QSortFilterProxyModel*>(model()));

    QModelIndexList indexes;
    if(selectionModel())
    {
        if(proxy)
        {
            indexes = proxy->mapSelectionToSource(selectionModel()->selection()).indexes();
        }
        else
        {
            indexes = selectionModel()->selection().indexes();
        }
    }

    for (auto index: std::as_const(indexes))
    {
        rows.push_back(index.row());
    }

    if (!rows.isEmpty())
    {
        mParentTransferWidget->getModel()->openInMEGA(rows);
    }

    clearSelection();
}

void MegaTransferView::openItemClicked()
{
    const QModelIndexList selection (selectedIndexes());
    for (auto index : selection)
    {
        if (index.isValid())
        {
            const auto transferItem (
                        qvariant_cast<TransferItem>(index.data(Qt::DisplayRole)));
            auto d (transferItem.getTransferData());
            auto path = d->path();
            if (!path.isEmpty())
            {
                QFileInfo info(path);
                if(info.exists())
                {
                    auto openUrlTask = Utilities::openUrl(QUrl::fromLocalFile(path));
                    mOpenUrlWatcher.setFuture(openUrlTask);
                }
                else
                {
                    showOpeningFileError();
                }
            }
        }
    }
    clearSelection();
}

void MegaTransferView::showInFolderClicked()
{
    const QModelIndexList selection (selectedIndexes());
    mParentTransferWidget->getModel()->openFoldersByIndexes(selection);
    clearSelection();
}

void MegaTransferView::showInMegaClicked()
{
    const QModelIndexList selection (selectedIndexes());
    for (auto index : selection)
    {
        if (index.isValid())
        {
            const auto transferItem (
                        qvariant_cast<TransferItem>(index.data(Qt::DisplayRole)));
            auto d (transferItem.getTransferData());

            if (d->mParentHandle != mega::INVALID_HANDLE)
            {
                MegaSyncApp->shellViewOnMegaByHandle(d->mParentHandle, false);
            }
        }
    }
    clearSelection();
}

void MegaTransferView::cancelSelectedClicked()
{
    onCancelSelectedTransfers();
}

void MegaTransferView::clearSelectedClicked()
{
    onCancelSelectedTransfers();
}

void MegaTransferView::pauseSelectedClicked()
{
    emit pauseResumeTransfersByContextMenu(true);
}

void MegaTransferView::resumeSelectedClicked()
{
    emit pauseResumeTransfersByContextMenu(false);
}

void MegaTransferView::onInternalMoveStarted()
{
     setAutoScroll(true);
}

void MegaTransferView::onInternalMoveFinished()
{
    setAutoScroll(false);
}

void MegaTransferView::onOpenUrlFinished()
{
    auto result = mOpenUrlWatcher.result();
    if(!result)
    {
        showOpeningFileError();
    }
}

void MegaTransferView::showOpeningFileError()
{
    MessageDialogInfo msgInfo;
    msgInfo.parent = Utilities::getTopParent<QDialog>(this);
    msgInfo.descriptionText = errorOpeningFileText();
    MessageDialogOpener::warning(msgInfo);
}
