/*
 * Copyright 2009- ECMWF.
 *
 * This software is licensed under the terms of the Apache Licence version 2.0
 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
 * In applying this licence, ECMWF does not waive the privileges and immunities
 * granted to it by virtue of its status as an intergovernmental organisation
 * nor does it submit to any jurisdiction.
 */

#include "TriggerGraphModel.hpp"

#include <QDebug>

#include "IconProvider.hpp"
#include "ServerHandler.hpp"
#include "TriggerGraphView.hpp"
#include "VAttribute.hpp"
#include "VAttributeType.hpp"
#include "VIcon.hpp"
#include "VNode.hpp"

TriggerGraphModel::TriggerGraphModel(Mode mode, QObject* parent) : QAbstractItemModel(parent), mode_(mode) {
}

TriggerGraphModel::~TriggerGraphModel() = default;

void TriggerGraphModel::clearData() {
    beginResetModel();
    items_.clear();
    endResetModel();
}

void TriggerGraphModel::setItems(const std::vector<TriggerGraphNodeItem*>& items) {
    beginResetModel();
    items_.clear();
    for (auto it : items) {
        items_.push_back(it->item());
    }
    endResetModel();
}

void TriggerGraphModel::appendItems(const std::vector<VItem*>& items) {
    beginResetModel();
    for (auto it : items) {
        items_.push_back(it);
    }
    endResetModel();
}

void TriggerGraphModel::beginUpdate() {
    beginResetModel();
}

void TriggerGraphModel::endUpdate() {
    endResetModel();
}

bool TriggerGraphModel::hasData() const {
    return (!items_.empty());
}

int TriggerGraphModel::columnCount(const QModelIndex& /*parent */) const {
    return 1;
}

int TriggerGraphModel::rowCount(const QModelIndex& parent) const {
    if (!hasData())
        return 0;

    // Parent is the root:
    if (!parent.isValid()) {
        return static_cast<int>(items_.size());
    }

    return 0;
}

Qt::ItemFlags TriggerGraphModel::flags(const QModelIndex& /*index*/) const {
    return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}

QVariant TriggerGraphModel::data(const QModelIndex& index, int role) const {
    if (!index.isValid() || !hasData() ||
        (role < Qt::UserRole && role != Qt::DisplayRole && role != Qt::BackgroundRole &&
         role != Qt::TextAlignmentRole && role != Qt::ToolTipRole && role != Qt::ForegroundRole)) {
        return {};
    }

    VItem* t = items_[index.row()];
    Q_ASSERT(t);

    if (index.column() == 0) {
        if (role == ServerRole) {
            return -1;
        }

        if (VAttribute* a = t->isAttribute()) {
            if (role == Qt::DisplayRole) {
                QStringList d = a->data();
                if (VNode* pn = a->parent())
                    d.append(QString::fromStdString(pn->absNodePath()));
                return d;
            }
            else if (role == Qt::ToolTipRole) {
                return a->toolTip();
            }
        }
        else if (VNode* vnode = t->isNode()) {
            if (role == Qt::DisplayRole) {
                return QString::fromStdString(vnode->absNodePath());
            }
            else if (role == Qt::BackgroundRole) {
                if (vnode->isSuspended()) {
                    QVariantList lst;
                    lst << vnode->stateColour() << vnode->realStateColour();
                    return lst;
                }
                else
                    return vnode->stateColour();
            }
            else if (role == Qt::ForegroundRole)
                return vnode->stateFontColour();

            else if (role == Qt::ToolTipRole) {
                QString txt = vnode->toolTip();
                // txt+=VIcon::toolTip(vnode,icons_);
                return txt;
            }
            else if (role == IconRole) {
                return VIcon::pixmapList(vnode, nullptr);
            }
            else if (role == NodeTypeRole) {
                if (vnode->isTask())
                    return 2;
                else if (vnode->isSuite())
                    return 0;
                else if (vnode->isFamily())
                    return 1;
                else if (vnode->isAlias())
                    return 3;
                return 0;
            }
            else if (role == NodeTypeForegroundRole) {
                return vnode->typeFontColour();
            }
            else if (role == NodePointerRole) {
                return QVariant::fromValue((void*)vnode);
            }

            else if (role == Qt::TextAlignmentRole) {
                return (mode_ == NodeMode) ? Qt::AlignCenter : Qt::AlignLeft;
            }
        }
    }

    // We express the table cell background colour through the UserRole. The
    // BackgroundRole is already used for the node rendering
    //    if(role == Qt::UserRole && mode_ != NodeMode)
    //    {
    //        const std::set<TriggerCollector::Mode>&  modes=items[row]->modes();
    //        if(modes.find(TriggerCollector::Normal) != modes.end())
    //            return QVariant();
    //        else
    //            return QColor(233,242,247);
    //    }

    return {};
}

QVariant TriggerGraphModel::headerData(const int section, const Qt::Orientation orient, const int role) const {
    if (orient != Qt::Horizontal)
        return QAbstractItemModel::headerData(section, orient, role);

    return {};
}

QModelIndex TriggerGraphModel::index(int row, int column, const QModelIndex& parent) const {
    if (!hasData() || row < 0 || column < 0) {
        return {};
    }

    // When parent is the root this index refers to a node or server
    if (!parent.isValid()) {
        return createIndex(row, column);
    }

    return {};
}

QModelIndex TriggerGraphModel::parent(const QModelIndex& /*child*/) const {
    return {};
}

VInfo_ptr TriggerGraphModel::nodeInfo(const QModelIndex& index) {
    if (VItem* t = indexToItem(index)) {
        return VInfo::createFromItem(t);
    }

    VInfo_ptr res;
    return res;
}

QModelIndex TriggerGraphModel::nodeToIndex(const VNode* node) const {
    if (!hasData() || !node)
        return {};

    for (size_t i = 0; i < items_.size(); i++) {
        if (items_[i] == node)
            return index(i, 0);
    }

    return {};
}

QModelIndex TriggerGraphModel::itemToIndex(VItem* /*item*/) {
    //    if(item)
    //    {
    //         for(std::size_t i=0; i < tc_->items().size(); i++)
    //             if(tc_->items()[i] == item)
    //                 return index(i,0);
    //    }

    return {};
}

VItem* TriggerGraphModel::indexToItem(const QModelIndex& index) const {
    if (!hasData() || !index.isValid())
        return nullptr;

    int row = index.row();
    if (row < 0 || row >= static_cast<int>(items_.size()))
        return nullptr;

    return items_[row];
}

void TriggerGraphModel::nodeChanged(const VNode* /*node*/, const std::vector<ecf::Aspect::Type>&) {
    if (!hasData())
        return;

    //    int num=tc_->items().size();
    //    for(int i=0; i < num; i++)
    //    {
    //        if(VItem* item=tc_->items()[i]->item())
    //        {
    //            if(VNode* n=item->isNode())
    //            {
    //                if(n == node)
    //                {
    //                    QModelIndex idx=index(i,0);
    //                    Q_EMIT dataChanged(idx,idx);
    //                }
    //            }

    //            else if(VAttribute* a=item->isAttribute())
    //            {
    //                if(a->parent() == node)
    //                {
    //                    QModelIndex idx=index(i,0);
    //                    Q_EMIT dataChanged(idx,idx);
    //                }
    //            }
    //        }
    //    }
}

// TriggerGraphModel::TriggerGraphModel(Mode mode,QObject *parent) :
//           QAbstractItemModel(parent),
//           mode_(mode)
//{
// }

// TriggerGraphModel::~TriggerGraphModel()
//= default;

// void TriggerGraphModel::clearData()
//{
//     beginResetModel();
//     if (node_) {
//         delete node_;
//         node_=nullptr;
//     }
//     triggerTc_=nullptr;
//     triggeredTc_ = nullptr;
//     endResetModel();
// }

// void TriggerGraphModel::setNode(VInfo_ptr info)
//{
//     beginResetModel();
//     if (node_) {
//         delete node_;
//     }
//     node_= new TriggerTableItem(info->item());
//     triggerTc_=nullptr;
//     triggeredTc_ = nullptr;
//     endResetModel();
// }

// void TriggerGraphModel::beginUpdate()
//{
//     beginResetModel();
// }

// void TriggerGraphModel::endUpdate()
//{
//     endResetModel();
// }

////must be protected by beginUpdate()/endUpdate()
// void TriggerGraphModel::setTriggerCollectors(TriggerTableCollector *triggerTc, TriggerTableCollector *triggeredTc)
//{
//     triggerTc_ = triggerTc;
//     triggeredTc_ = triggeredTc;
//     Q_ASSERT(triggerTc_);
//     Q_ASSERT(triggeredTc_);
// }

// bool TriggerGraphModel::hasData() const
//{
//     return (node_ != nullptr);
////        return false;

////    if(triggerTc_) {
////        Q_ASSERT(triggeredTc_);
////        return (triggerTc_->size() > 0 || triggeredTc_->size() > 0);
////    }
////    return false;
//}

// bool TriggerGraphModel::hasTrigger() const
//{
//     if (triggerTc_) {
//         Q_ASSERT(node_);
//         Q_ASSERT(triggeredTc_);
//         return true;
//     }
//     return false;
// }

// int TriggerGraphModel::columnCount( const QModelIndex& /*parent */) const
//{
//      return 1;
// }

// int TriggerGraphModel::rowCount( const QModelIndex& parent) const
//{
//     if(!hasData())
//         return 0;

//    //Parent is the root:
//    if(!parent.isValid() )
//    {
//        int num = 0;
//        if (node_) {
//            num +=1;
//            if (hasTrigger()) {
//                num += triggerTc_->size() + triggeredTc_->size();
//            }
//        }
//        return num;
//    }

//    return 0;
//}

// Qt::ItemFlags TriggerGraphModel::flags ( const QModelIndex & index) const
//{
//     return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
// }

// QVariant TriggerGraphModel::data( const QModelIndex& index, int role ) const
//{
//     if(!index.isValid() || !hasData() || (role < Qt::UserRole &&
//         role != Qt::DisplayRole && role != Qt::BackgroundRole && role != Qt::TextAlignmentRole &&
//         role != Qt::ToolTipRole && role != Qt::ForegroundRole))
//     {
//         return QVariant();
//     }

//    TriggerTableItem *item = indexToItem(index);
//    if (!item) {
//        return QVariant();
//    }
//    VItem *t = item->item();
//    Q_ASSERT(t);

//    if(index.column() == 0)
//    {
//        if (role == ServerRole) {
//            return -1;
//        }

//        if(VAttribute* a=t->isAttribute())
//        {
//            if(role == Qt::DisplayRole)
//            {
//                QStringList d=a->data();
//                if(VNode* pn=a->parent())
//                    d.append(QString::fromStdString(pn->absNodePath()));
//                return d;
//            }
//            else if(role ==  Qt::ToolTipRole)
//            {
//                return a->toolTip();
//            }

//        }
//        else if(VNode* vnode=t->isNode())
//        {
//            if(role == Qt::DisplayRole)
//            {
//                return QString::fromStdString(vnode->absNodePath());
//            }
//            else if(role == Qt::BackgroundRole)
//            {
//                if(vnode->isSuspended())
//                {
//                    QVariantList lst;
//                    lst << vnode->stateColour() << vnode->realStateColour();
//                    return lst;
//                }
//                else
//                    return vnode->stateColour() ;
//            }
//            else if(role == Qt::ForegroundRole)
//                return vnode->stateFontColour();

//            else if(role == Qt::ToolTipRole)
//            {
//                QString txt=vnode->toolTip();
//                //txt+=VIcon::toolTip(vnode,icons_);
//                return txt;
//            }
//            else if(role == IconRole)
//            {
//                return VIcon::pixmapList(vnode,nullptr);
//            }
//            else if(role  == NodeTypeRole)
//            {
//                 if(vnode->isTask()) return 2;
//                 else if(vnode->isSuite()) return 0;
//                 else if(vnode->isFamily()) return 1;
//                 else if(vnode->isAlias()) return 3;
//                 return 0;
//            }
//            else if(role  == NodeTypeForegroundRole)
//            {
//                return vnode->typeFontColour();
//            }
//            else if(role  == NodePointerRole)
//            {
//                 return qVariantFromValue((void *) vnode);
//            }

//            else if(role  == Qt::TextAlignmentRole)
//            {
//                return( mode_==NodeMode)?Qt::AlignCenter:Qt::AlignLeft;
//            }

//        }
//    }

//    //We express the table cell background colour through the UserRole. The
//    //BackgroundRole is already used for the node rendering
////    if(role == Qt::UserRole && mode_ != NodeMode)
////    {
////        const std::set<TriggerCollector::Mode>&  modes=items[row]->modes();
////        if(modes.find(TriggerCollector::Normal) != modes.end())
////            return QVariant();
////        else
////            return QColor(233,242,247);
////    }

//    return QVariant();
//}

// QVariant TriggerGraphModel::headerData( const int section, const Qt::Orientation orient , const int role ) const
//{
//     if ( orient != Qt::Horizontal)
//             return QAbstractItemModel::headerData( section, orient, role );

//    return QVariant();
//}

// QModelIndex TriggerGraphModel::index( int row, int column, const QModelIndex & parent ) const
//{
//     if(!hasData() || row < 0 || column < 0)
//     {
//         return {};
//     }

//    //When parent is the root this index refers to a node or server
//    if(!parent.isValid())
//    {
//        return createIndex(row,column);
//    }

//    return {};

//}

// QModelIndex TriggerGraphModel::parent(const QModelIndex &child) const
//{
//     return {};
// }

// VInfo_ptr TriggerGraphModel::nodeInfo(const QModelIndex& index)
//{
//     if(TriggerTableItem* t = indexToItem(index)) {
//         return VInfo::createFromItem(t->item());
//     }

//    VInfo_ptr res;
//    return res;
//}

// QModelIndex TriggerGraphModel::nodeToIndex(const VNode *node) const
//{
//     if (!hasData() || !node)
//         return {};

//    if (node_->item() == node)
//        return index(0, 0);

//    if (hasTrigger()) {
//        for (size_t i=0; i < triggerTc_->items().size(); i++) {
//            if (triggerTc_->items()[i]->item() == node)
//                return index(1+i, 0);
//        }
//        for (size_t i=0; i < triggeredTc_->items().size(); i++) {
//            if (triggeredTc_->items()[i]->item() == node)
//                return index(1 + triggerTc_->size() + i, 0);
//        }
//    }

//    return {};
//}

// QModelIndex TriggerGraphModel::itemToIndex(TriggerTableItem *item)
//{
////    if(item)
////    {
////         for(std::size_t i=0; i < tc_->items().size(); i++)
////             if(tc_->items()[i] == item)
////                 return index(i,0);
////    }

//    return {};
//}

// TriggerTableItem* TriggerGraphModel::indexToItem(const QModelIndex& index) const
//{
//     if(!hasData() || !index.isValid())
//         return nullptr;

//    int row=index.row();
//    if (row == 0) {
//        return node_;
//    } else if (hasTrigger()){
//        row -= 1;
//        if(row < 0 || row >= static_cast<int>(triggerTc_->size() + triggeredTc_->size()))
//            return nullptr;
//        else if(row < static_cast<int>(triggerTc_->size())) {
//            const std::vector<TriggerTableItem*>& items=triggerTc_->items();
//            return items[row];
//        } else {
//            const std::vector<TriggerTableItem*>& items=triggeredTc_->items();
//            return items[row - triggerTc_->size()];
//        }
//    }
//    return nullptr;
//}

// void TriggerGraphModel::nodeChanged(const VNode* node, const std::vector<ecf::Aspect::Type>&)
//{
//     if(!hasData())
//         return;

////    int num=tc_->items().size();
////    for(int i=0; i < num; i++)
////    {
////        if(VItem* item=tc_->items()[i]->item())
////        {
////            if(VNode* n=item->isNode())
////            {
////                if(n == node)
////                {
////                    QModelIndex idx=index(i,0);
////                    Q_EMIT dataChanged(idx,idx);
////                }
////            }

////            else if(VAttribute* a=item->isAttribute())
////            {
////                if(a->parent() == node)
////                {
////                    QModelIndex idx=index(i,0);
////                    Q_EMIT dataChanged(idx,idx);
////                }
////            }
////        }
////    }
//}
