////////////////////////////////////////////////////////////////////
///
///   MorkParser.h - Mozilla Mork Format Parser/Reader
///
///   Copyright (C) 2007 ScalingWeb.com
///   All rights reserved.
///
///   Authors: Yuriy Soroka <ysoroka@scalingweb.com>
///               Anton Fedoruk <afedoruk@scalingweb.com>
///
///
///////////////////////////////////////////////////////////////////

#ifndef MorkParser_h
#define MorkParser_h

#include <QMap>
#include <QByteArray>
#include <iostream>
class QString;
// Types

typedef QMap< int, QString > MorkDict;
typedef QMap< int, int > MorkCells;                                        // ColumnId : ValueId
typedef QMap< int, MorkCells > MorkRowMap;                        // Row id
typedef QMap< int, MorkRowMap > RowScopeMap;                // Row scope
typedef QMap< int, RowScopeMap > MorkTableMap;                // Table id
typedef QMap< int, MorkTableMap > TableScopeMap;        // Table Scope

// Mork header of supported format version
const char MorkMagicHeader[] = "// <!-- <mdb:mork:z v=\"1.4\"/> -->";

const char MorkDictColumnMeta[] = "<(a=c)>";

// Error codes
enum MorkErrors {
    NoError = 0,
    FailedToOpen,
    UnsupportedVersion,
    DefectedFormat
};

// Mork term types
enum MorkTerm {
    NoneTerm = 0,
    DictTerm,
    GroupTerm,
    TableTerm,
    RowTerm,
    CellTerm,
    CommentTerm,
    LiteralTerm
};

/// Class MorkParser

class MorkParser
{
public:

    explicit MorkParser(int defaultScope = 0x80);

    ///
    /// Open and parse mork file

    bool open(const QString &path);

    ///
    /// Return error status

    MorkErrors error() const;

    ///
    /// Returns all tables of specified scope

    MorkTableMap *getTables(int tableScope);

    ///
    /// Rerturns all rows under specified scope

    MorkRowMap *getRows(int rowScope, RowScopeMap *table);

    ///
    /// Return value of specified value oid

    QString getValue(int oid);

    ///
    /// Return value of specified column oid

    QString getColumn(int oid);

protected: // Members

    void initVars();

    bool isWhiteSpace(char c) const;
    char nextChar();

    void parseScopeId(const QString &TextId, int &Id, int &Scope) const;
    void setCurrentRow(int TableScope, int TableId, int RowScope, int RowId);

    // Parse methods
    bool parse();
    bool parseDict();
    bool parseComment();
    bool parseCell();
    bool parseTable();
    bool parseMeta(char c);
    bool parseRow(int TableId, int TableScope);
    bool parseGroup();

protected: // Data

    // Columns in mork means value names
    MorkDict mColumns;
    MorkDict mValues;

    // All mork file data
    TableScopeMap mMork;
    MorkCells *mCurrentCells = nullptr;

    // Error status of last operation
    MorkErrors mError;

    // All Mork data
    QByteArray mMorkData;

    int mMorkPos;
    int mNextAddValueId;
    int mDefaultScope;

    // Indicates intity is being parsed
    enum {
        NPColumns, NPValues, NPRows
    } nowParsing_;
};

#endif // MorkParser_h
