#include "flatproxymodel.h"
#include "vbconnect.h"

Model::FlatProxyModel::FlatProxyModel(QObject* parent)
    : QAbstractItemModel(parent), mModel(0)
{
}

Model::FlatProxyModel::FlatProxyModel(QAbstractItemModel* model, QObject* parent)
    : QAbstractItemModel(parent), mModel(0)
{
    setModel(model);
}

Model::FlatProxyModel::FlatProxyModel(const QPair<QList<int>, QString>& format,
                                      QAbstractItemModel* model, QObject* parent)
    : QAbstractItemModel(parent), mModel(0), mFormat(format)
{
    setModel(model);
}

Model::FlatProxyModel::~FlatProxyModel() {
}

int Model::FlatProxyModel::columnCount(const QModelIndex&) const {
    return 1;
}

QVariant Model::FlatProxyModel::data(const QModelIndex& index, int role) const {
    if (mModel == 0)
        return QVariant();
    if (role != Qt::DisplayRole && role != Qt::EditRole)
        return QVariant();

    const QModelIndex mIndex = modelIndex(index);
    const int row = mIndex.row();
    const QModelIndex parent = mIndex.parent();

    QString d;
    const int modelCC = mModel->columnCount();
    if (mFormat.second.isEmpty()) {
        // Space separate all columns
        for (int i=0; i<modelCC; ++i) {
            const QString columnString =
                mModel->data(mModel->index(row, i, parent)).toString();
            if (!columnString.isEmpty()) {
                if (!d.isEmpty())
                    // Insert separator
                    d += ' ';
                d += columnString;
            }
        }
    } else {
        // Use column arguments from the format list
        d = mFormat.second;
        foreach(int i, mFormat.first)
            d = d.arg(mModel->data(mModel->index(row, i, parent))
                       .toString());
    }

    return d;
}

Qt::ItemFlags Model::FlatProxyModel::flags(const QModelIndex& index) const {
    if (mModel == 0)
        return 0;

    Qt::ItemFlags f = mModel->flags(modelIndex(index));
    // Strip all writable flags and make sure we can select it
    return (f & ~(Qt::ItemIsEditable | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable)) | Qt::ItemIsSelectable | Qt::ItemIsEnabled;
}

bool Model::FlatProxyModel::hasChildren(const QModelIndex&) const {
    return false;
}

QModelIndex Model::FlatProxyModel::index(int row, int column,
                                   const QModelIndex& parent) const
{
    if (hasIndex(row, column, parent))
        return createIndex(row, column);
    return QModelIndex();
}

QModelIndex Model::FlatProxyModel::parent(const QModelIndex&) const {
    // Never valid
    return QModelIndex();
}

int Model::FlatProxyModel::rowCount(const QModelIndex&) const {
    return mModelIndexMap.count();
}

void Model::FlatProxyModel::setModel(QAbstractItemModel* model) {
    if (model == mModel)
        // Don't do anything
        return;

    if (mModel != 0)
        // Remove old connects
        mModel->disconnect(this);

    // Clear out old settings
    mModelIndexMap.clear();

    mModel = model;

    remap();
}

QModelIndex Model::FlatProxyModel::modelIndex(const QModelIndex& proxyIndex) const {
    if (proxyIndex.isValid()) {
        int row = proxyIndex.row();
        if (mModelIndexMap.contains(row))
            return mModelIndexMap[row];
    }

    return QModelIndex();
}

QModelIndex Model::FlatProxyModel::modelIndex(int row) const {
    return modelIndex(index(row, 0));
}

void Model::FlatProxyModel::setFormat(const QPair<QList<int>, QString>& format) {
    mFormat = format;
    emit layoutChanged();
}

void Model::FlatProxyModel::slotDataChanged(QModelIndex, QModelIndex) {
    // TODO: Optimize the case where it's just the data of a row
    // that is changing
    remap();
}

void Model::FlatProxyModel::slotLayoutChanged() {
    remap();
}

void Model::FlatProxyModel::remap() {
    if (mModel != 0) {
        // Build the model map
        int position = 0;
        mapModel(position, QModelIndex());

        // Listen to model changes
        vbConnect(mModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)),
                  this, SLOT(slotDataChanged(QModelIndex, QModelIndex)));
        vbConnect(mModel, SIGNAL(layoutChanged()), this, SLOT(slotLayoutChanged()));
    }

    emit modelChanged();
    emit layoutChanged();
}

void Model::FlatProxyModel::mapModel(int& pos, const QModelIndex& parent) const {
    int childCount = mModel->rowCount(parent);
    for (int i=0; i<childCount; ++i) {
        // First, map this one
        QModelIndex index = mModel->index(i, 0, parent);
        mModelIndexMap[pos++] = index;

        // qDebug("%d = %s", pos, mModel->data(index).toString().toAscii().constData());
        // Map it's children
        mapModel(pos, index);
    }
}

