/** Subclass of QAbstractTableModel, deals with reading and writing variables data from files
  The first item in the file is how many rows of data, then the data comes in pairs: variables,
  value. **/

#ifndef VARIABLESTABLEMODEL_H
#define VARIABLESTABLEMODEL_H

#include <QtGui>

#include "consoleoutmodel.h" // for ConsoleOut namespace

#define _CONSOLE_ERROR( x ) emit sendConsoleOut(QString() + x , ConsoleOut::Error);
#define _CONSOLE_INFO( x ) emit sendConsoleOut(QString() + x , ConsoleOut::Information);
#define _CONSOLE_VERBOSE( x ) emit sendConsoleOut(QString() + x , ConsoleOut::Verbose);
#define _CONSOLE_FATAL( x ) emit sendConsoleOut(QString() + x , ConsoleOut::Fatal);

class VariablesTableModel : public QAbstractTableModel{
    Q_OBJECT
public:
    VariablesTableModel(QWidget *parent = 0) : QAbstractTableModel(parent){
    }

    ~VariablesTableModel(){}

     int rowCount(const QModelIndex &parent) const{
        return variables.size();
    }
    int columnCount(const QModelIndex &parent) const{return 2;}

    QVariant data(const QModelIndex &index, int role) const{
        if (!index.isValid())
            return QVariant();

        if (index.row() >= variables.size() || index.column() >= 2)
            return QVariant();

        if (role == Qt::DisplayRole ){
            if(index.column()==0)
                return variables.at(index.row());
            if(index.column()==1)
                return values.at(index.row());
        }
        return QVariant();
    }
    QVariant headerData(int section, Qt::Orientation orientation,
                        int role = Qt::DisplayRole) const{
        if (role != Qt::DisplayRole)
            return QVariant();

        if (orientation == Qt::Horizontal){
            if(section == 0)
                return QString("Variable");
            else
                return QString("Value");
        }
        else
            return QVariant();
    }

    Qt::ItemFlags flags(const QModelIndex &index) const{
        if (!index.isValid())
            return Qt::ItemIsEnabled;

        return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
    }

    bool setData(const QModelIndex &index, const QVariant &value,
                 int role = Qt::EditRole){

        if (index.isValid() && role == Qt::EditRole) {
            if(index.column()==0){
                variables.replace(index.row(), value.toString());
            }
            if(index.column()==1){
                values.replace(index.row(), value.toString());
            }
            emit dataChanged(index, index);
            emit loadedVariables(variables, values);
            return true;
        }
        return false;
    }

    bool insertRows(int position, int rows, const QModelIndex &parent)
    {
        beginInsertRows(QModelIndex(), position, position+rows-1);
        for (int row = 0; row < rows; ++row) {
            variables.insert(position, "<Variable>");
            values.insert(position, "<Value>");
        }
        endInsertRows();
        emit loadedVariables(variables, values);
        return true;
    }
    bool removeRows(int position, int rows, const QModelIndex &parent)
    {
        if(position < 0 || position + rows-1 >= variables.size()){return false;}
        beginRemoveRows(QModelIndex(), position, position+rows-1);
        for (int row = 0; row < rows; ++row) {
            variables.removeAt(position);
            values.removeAt(position);
        }
        endRemoveRows();
        emit loadedVariables(variables, values);
        return true;
    }

    //helper functions for me - not required
    QString getText(int row, int column){
        if(row >=0 && row < variables.size()){
            if(column == 0)
                return variables.at(row);
            if(column == 1)
                return values.at(row);
        }
        return QString();
    }
    bool setText(int row, int column, QString text){
        if(row >=0 && row < variables.size()){
           if(column == 0){
               variables.replace(row, text);
               QModelIndex i = this->createIndex(row, column);
               emit dataChanged(i, i);
               emit loadedVariables(variables, values);
               return true;
           }
           if(column == 1){
               values.replace(row, text);
               QModelIndex i = this->createIndex(row, column);
               emit dataChanged(i, i);
               emit loadedVariables(variables, values);
               return true;
           }
        }
        return false;
    }

private:
    QStringList variables, values;

signals:
    void sendConsoleOut(QString text, ConsoleOut::OutputType);
    void loadedVariables(QStringList variables, QStringList values);

public slots:
    void importFromFile(QString path){
        QFile file(path);
        if(file.exists()){
            if(!file.open(QIODevice::ReadOnly)){  // meed QIODevice::Text ??
                _CONSOLE_ERROR("Failed to open already existing variables file for "
                              + file.fileName());
                return;
            }
            QDataStream in(&file);
            in.setVersion(QDataStream::Qt_4_6);

            int numberOfRows;
            in >> numberOfRows;
            if(numberOfRows >= 1){
                this->beginInsertRows(QModelIndex(), variables.size(), variables.size()+numberOfRows-1);

                QString a, b;
                while(!in.atEnd()){
                    in >> a >> b;
                    variables << a;
                    values << b;
                }
                this->endInsertRows();

            }
        }
        file.close();
        emit loadedVariables(variables, values);
    }


    void populateFromFile(QString path){
        if(variables.size() > 0){
            this->beginRemoveRows(QModelIndex(), 0, variables.size()-1);
            variables.clear();
            values.clear();
            this->endRemoveRows();
        }
        importFromFile(path);
    }

    void writeToFile(QString path){
        QFile file(path);
        if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)){
            _CONSOLE_ERROR("Failed to open variables file for writing: "
                           + file.fileName());
            return;
        }
        QDataStream out(&file);
        out.setVersion(QDataStream::Qt_4_6);
        out << variables.size();
        for (int i = 0 ; i < variables.size(); ++i){
            out << variables.at(i) << values.at(i);
        }
    }
};

#endif // VARIABLESTABLEMODEL_H
