// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)

#include "mapmodel.h"

#include <QtCore/QDebug>
#include <QtXml/QXmlSimpleReader>
#include <QtXml/QXmlInputSource>
#include <QtXml/QXmlDefaultHandler>

MapModel::MapModel(QObject *parent) :
    QAbstractTableModel(parent)
{
    _columns = 100;
    _data.fill(2, 100*30);

    QHash<int, QByteArray> roleNames;
    roleNames.insert(Qt::DisplayRole, "type");
    setRoleNames(roleNames);
}

int MapModel::rowCount(const QModelIndex &parent) const
{
    if (parent.isValid())
        return 0;
    return _data.size() / _columns;
}

int MapModel::columnCount(const QModelIndex &parent) const
{
    if (parent.isValid())
        return 0;
    return _columns;
}


QVariant MapModel::data(const QModelIndex &index, int) const
{
    if (!index.isValid() || index.row() >= rowCount() || index.column() >= columnCount())
        return QVariant();

    return _data[index.row() * _columns + index.column()];
}

bool MapModel::setData(const QModelIndex &index, const QVariant &value, int)
{
    if (!index.isValid() || index.row() >= rowCount() || index.column() >= columnCount())
        return false;

    bool ok;
    const int v = value.toInt(&ok);
    if (!ok || v < 0)
        return false;

    _data[index.row() * _columns + index.column()] = v;
    emit dataChanged(index, index);
    return true;
}

Qt::ItemFlags MapModel::flags(const QModelIndex &index) const
{
    return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
}

QString MapModel::source() const
{
    return _source;
}

void MapModel::setSource(const QString &s)
{
    if (_source != s) {
        _source = s;
        if (!_source.isEmpty())
            read();
        emit sourceChanged();
    }
}

int MapModel::type(QPoint i) const
{
    return data(index(i.y(), i.x())).toInt();
}

void MapModel::setType(QPoint i, int type)
{
    setData(index(i.y(), i.x()), type);
}

void MapModel::newMap(int columns, int rows)
{
    beginResetModel();
    _data.fill(2, columns*rows);
    _columns = columns;
    endResetModel();
}

void MapModel::extendUp()
{
    beginResetModel();
    for (int i = 0; i < _columns; ++i)
        _data.prepend(2);
    endResetModel();
}

void MapModel::extendDown()
{
    beginResetModel();
    for (int i = 0; i < _columns; ++i)
        _data.append(2);
    endResetModel();
}

void MapModel::extendLeft()
{
    beginResetModel();
    for (int i = _data.size() - _columns; i >= 0; i -= _columns)
        _data.insert(i, 2);
    ++_columns;
    endResetModel();
}

void MapModel::extendRight()
{
    beginResetModel();
    for (int i = _data.size(); i > 0; i -= _columns)
        _data.insert(i, 2);
    ++_columns;
    endResetModel();
}

namespace {
    class MapXmlHandler : public QXmlDefaultHandler
    {
    public:
        MapXmlHandler()
            : cols(0), firstrow(true)
        {}

        virtual bool endElement(const QString &, const QString &localName, const QString &) {
            if (localName == "tilerow")
                firstrow = false;
            else if (localName == "tilecol") {
                data.append(type);
                if (firstrow)
                    ++cols;
            }
            return true;
        }

        virtual bool characters(const QString &ch) {
            type = ch.toInt();
            return true;
        }

        int type;
        int cols;
        bool firstrow;
        QVector<int> data;
    };
} // anonymous namespace

void MapModel::read()
{
    beginResetModel();

    QFile file(_source);
    if (!file.exists())
        return;

    file.open(QFile::ReadOnly);
    QXmlInputSource input(&file);

    QXmlSimpleReader xmlReader;
    MapXmlHandler handler;
    xmlReader.setContentHandler(&handler);

    xmlReader.parse(&input);

    _columns = handler.cols;
    _data = handler.data;

    endResetModel();
}

void MapModel::save(const QString &filename) const
{
    QFile file(filename);
    file.open(QFile::WriteOnly);

    file.write("<map>\r\n");
    QVectorIterator<int> it(_data);
    int colIndex = 0;
    while (it.hasNext()) {
        int ty = it.next();
        if (colIndex == 0)
            file.write("<tilerow>\r\n");
        file.write(QString("<tilecol>%1</tilecol>").arg(ty).toLatin1());
        ++colIndex;
        if (colIndex == _columns) {
            file.write("\r\n</tilerow>\r\n");
            colIndex = 0;
        }
    }
    file.write("</map>\r\n\r\n");
}
