#include "canvastreemodel.h"

#include <QDebug>

#include "localprop.h"

CanvasTreeModel::CanvasTreeModel(FGCanvasGroup* root) :
    _root(root)
{
    connect(_root, &FGCanvasGroup::childAdded, this, &CanvasTreeModel::onGroupChildAdded);
}

FGCanvasElement* CanvasTreeModel::elementFromIndex(const QModelIndex &index) const
{
    if (!index.isValid()) {
        return nullptr;
    }

    FGCanvasElement* e = static_cast<FGCanvasElement*>(index.internalPointer());
    return e;
}

int CanvasTreeModel::rowCount(const QModelIndex &parent) const
{
    FGCanvasElement* e = static_cast<FGCanvasElement*>(parent.internalPointer());
    if (!e) {
        return _root->childCount();
    }

    FGCanvasGroup* group = qobject_cast<FGCanvasGroup*>(e);
    if (group) {
        return group->childCount();
    }

    return 0;
}

int CanvasTreeModel::columnCount(const QModelIndex &parent) const
{
    return 1;
}

QVariant CanvasTreeModel::data(const QModelIndex &index, int role) const
{
    FGCanvasElement* e = static_cast<FGCanvasElement*>(index.internalPointer());
    if (!e) {
        return QVariant();
    }

    switch (role) {
    case Qt::DisplayRole:
        return e->property()->value("id", QVariant("<noid>"));

    case Qt::CheckStateRole:
        return e->property()->value("visible", true).toBool() ? Qt::Checked : Qt::Unchecked;

    default:
        break;
    }

    return QVariant();
}

bool CanvasTreeModel::hasChildren(const QModelIndex &parent) const
{
    FGCanvasElement* e;
    if (parent.isValid()) {
        e = static_cast<FGCanvasElement*>(parent.internalPointer());
    } else {
        e = _root;
    }

    FGCanvasGroup* group = qobject_cast<FGCanvasGroup*>(e);
    if (group) {
        return group->hasChilden();
    }

    return false;
}

QModelIndex CanvasTreeModel::index(int row, int column, const QModelIndex &parent) const
{
    FGCanvasGroup* group;
    if (parent.isValid()) {
        group = qobject_cast<FGCanvasGroup*>(static_cast<FGCanvasElement*>(parent.internalPointer()));
    } else {
        group = _root;
    }

    if (!group) {
        return QModelIndex(); // invalid
    }

    if ((row < 0) || (row >= (int) group->childCount())) {
        return QModelIndex(); // invalid
    }

    return createIndex(row, column, group->childAt(row));
}

QModelIndex CanvasTreeModel::parent(const QModelIndex &child) const
{
    FGCanvasElement* e = static_cast<FGCanvasElement*>(child.internalPointer());
    if (!child.isValid() || !e) {
        return QModelIndex();
    }

    return indexForGroup(const_cast<FGCanvasGroup*>(e->parentGroup()));
}

Qt::ItemFlags CanvasTreeModel::flags(const QModelIndex &index) const
{
    return QAbstractItemModel::flags(index) | Qt::ItemIsUserCheckable | Qt::ItemIsEditable;
}

bool CanvasTreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    FGCanvasElement* e = static_cast<FGCanvasElement*>(index.internalPointer());
    if (!e) {
        return false;
    }

    qDebug() << Q_FUNC_INFO;
    if (role == Qt::CheckStateRole) {
        e->property()->changeValue("visible", (value.toInt() == Qt::Checked));
        emit dataChanged(index, index, QVector<int>() << Qt::CheckStateRole);
        return true;
    }

    return false;
}

QModelIndex CanvasTreeModel::indexForGroup(FGCanvasGroup* group) const
{
    if (!group) {
        return QModelIndex();
    }

    if (group->parentGroup()) {
        int prIndex = group->parentGroup()->indexOfChild(group);
        return createIndex(prIndex, 0, group);
    } else {
        return createIndex(0, 0, group);
    }
}

void CanvasTreeModel::onGroupChildAdded()
{
    FGCanvasGroup* group = qobject_cast<FGCanvasGroup*>(sender());
    int newChild = group->childCount() - 1;

    FGCanvasGroup* childGroup = qobject_cast<FGCanvasGroup*>(group->childAt(newChild));
    if (childGroup) {
        connect(childGroup, &FGCanvasGroup::childAdded, this, &CanvasTreeModel::onGroupChildAdded);
    }

    beginInsertRows(indexForGroup(group),
                    newChild, newChild);
    endInsertRows();
}

void CanvasTreeModel::onGroupChildRemoved(int index)
{
    FGCanvasGroup* group = qobject_cast<FGCanvasGroup*>(sender());
    beginRemoveRows(indexForGroup(group), index, index);
}