/*
 * Copyright (C) 2007 Esmertec AG.
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef WBXML_PARSER_H
#define WBXML_PARSER_H

#include <setjmp.h>
#include <stdint.h>
#include "wbxml_const.h"
#include "wbxml_stl.h"
#include "wbxml_tabledef.h"

struct Attribute
{
    string name;
    string value;
};

class WbxmlContentHandler
{
public:
    virtual ~WbxmlContentHandler() {}
    virtual void handlePublicId(uint32_t id) = 0;
    virtual void startElement(const char * name, const vector<Attribute> & attribs) = 0;
    virtual void endElement(const char * name) = 0;
    virtual void characters(const char * data, int len) = 0;
    virtual void opaque(const char * data, int len) = 0;
};

class DefaultWbxmlContentHandler: public WbxmlContentHandler
{
public:
    DefaultWbxmlContentHandler()
    {
        mPublicId = -1;
    }

    void handlePublicId(uint32_t id)
    {
        mPublicId = id;
    }

    // @return public ID or -1 if no public ID seen
    int getPublicId(void) const
    {
        return mPublicId;
    }

    void startElement(const char * name, const vector<Attribute> & attribs)
    {
    }

    void endElement(const char * name)
    {
    }

    void characters(const char * data, int len)
    {
    }

    void opaque(const char * data, int len)
    {
    }

private:
    int mPublicId;
};

class WbxmlParser
{
public:
    WbxmlParser(uint32_t transportEncoding);
    ~WbxmlParser();

    void setContentHandler(WbxmlContentHandler * handler);

    //void setTokenMappings(uint32_t publicId, TagTable tagTable, AttrTable attrTable);
    int parse(const char * data, uint32_t len, bool end);

    void reset(void);

    int getError(void) const
    {
        return mLastError;
    }

private:
    enum ParserState {
        EXPECT_HEADER,
        EXPECT_STRING_TABLE,
        EXPECT_BODY_START,
        EXPECT_ELEMENT_START,
        EXPECT_ELEMENT_END,
        ELEMENT_END,
        EXPECT_CONTENT,
        EXPECT_BODY_END,
    };
    enum ParserError {
        ERROR_NO_ERROR = 0,
        ERROR_INVALID_DATA = 1,
        ERROR_NEED_MORE_DATA,
        ERROR_UNSUPPORTED_PUBID,
        ERROR_UNSUPPORTED_CHARSET,
        ERROR_INVALID_STRING_TABLE,
        ERROR_INVALID_STRING_TABLE_REFERENCE,
        ERROR_INVALID_EXT_TOKEN,
        ERROR_INVALID_MBUINT,
        ERROR_INVALID_ENTITY,
        ERROR_UNRECOGNIZED_TAG,
        ERROR_UNRECOGNIZED_ATTR,
        ERROR_MISSING_ATTR,
        ERROR_MISSING_TOKEN_END,
        ERROR_NOT_SUPPORTED_YET   = 999,
    };

    int readByte();
    int peekByte();
    uint32_t readMbuint32();
    void readString(string & str);
    const char * resolveStrTableRef(void);

    const char * lookupTagName(int tag) const;
    const char * lookupAttrName(int tag, const char **valuePrefix) const;
    void readAttribute(Attribute * attrib);

    jmp_buf mJmpbuf;

    string mLastChunk;
    const char * mExternalChunk;
    uint32_t mExternalChunkLen;
    uint32_t mDataOffset;
    bool mIsDataEnd;

    int getReadPos(void) const
    {
        return mDataOffset;
    }
    void setReadPos(int pos)
    {
        mDataOffset = pos;
    }
    void appendData(const char * data, uint32_t len, bool end);
    void saveRemainingData();
    uint32_t availDataSize(void) const
    {
        return mLastChunk.size() + mExternalChunkLen - mDataOffset;
    }

    bool selectTokenMapping(int publicId);

    const TagCodePage * mTagPages;
    uint32_t mNumTagPages;
    const AttrCodePage * mAttrPages;
    uint32_t mNumAttrPages;

    uint32_t mTransportEncoding;
    WbxmlContentHandler * mContentHandler;

    vector<string> mStartElemStack;
    string mStringTable;
    uint32_t mCurrTagPage;
    uint32_t mCurrAttrPage;

    ParserState mState;
    ParserError mLastError;

    int mDocVersion;
    uint32_t mPublicId;
    uint32_t mCharset;
};

#endif