/*
 * Copyright 2006 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */


#ifndef SkXMLParser_DEFINED
#define SkXMLParser_DEFINED

#include "SkString.h"

class SkStream;

class SkDOM;
struct SkDOMNode;

class SkXMLParserError {
public:
    enum ErrorCode {
        kNoError,
        kEmptyFile,
        kUnknownElement,
        kUnknownAttributeName,
        kErrorInAttributeValue,
        kDuplicateIDs,
        kUnknownError
    };

    SkXMLParserError();
    virtual ~SkXMLParserError();
    ErrorCode getErrorCode() const { return fCode; }
    virtual void getErrorString(SkString* str) const;
    int getLineNumber() const { return fLineNumber; }
    int getNativeCode() const { return fNativeCode; }
    bool hasError() const { return fCode != kNoError || fNativeCode != -1; }
    bool hasNoun() const { return fNoun.size() > 0; }
    void reset();
    void setCode(ErrorCode code) { fCode = code; }
    void setNoun(const SkString& str) { fNoun.set(str); }
    void setNoun(const char* ch)  { fNoun.set(ch); }
    void setNoun(const char* ch, size_t len) { fNoun.set(ch, len); }
protected:
    ErrorCode fCode;
private:
    int fLineNumber;
    int fNativeCode;
    SkString fNoun;
    friend class SkXMLParser;
};

class SkXMLParser {
public:
            SkXMLParser(SkXMLParserError* parserError = NULL);
    virtual ~SkXMLParser();

    /** Returns true for success
    */
    bool parse(const char doc[], size_t len);
    bool parse(SkStream& docStream);
    bool parse(const SkDOM&, const SkDOMNode*);

    static void GetNativeErrorString(int nativeErrorCode, SkString* str);

protected:
    // override in subclasses; return true to stop parsing
    virtual bool onStartElement(const char elem[]);
    virtual bool onAddAttribute(const char name[], const char value[]);
    virtual bool onEndElement(const char elem[]);
    virtual bool onText(const char text[], int len);

public:
    // public for ported implementation, not meant for clients to call
    virtual bool startElement(const char elem[]);
    virtual bool addAttribute(const char name[], const char value[]);
    virtual bool endElement(const char elem[]);
    virtual bool text(const char text[], int len); 
    void* fParser;
protected:
    SkXMLParserError* fError;
private:
    void reportError(void* parser);
};

#if 0
class SkXMLPullParser {
public:
            SkXMLPullParser();
    explicit SkXMLPullParser(SkStream*);
    virtual ~SkXMLPullParser();

    SkStream*   getStream() const { return fStream; }
    SkStream*   setStream(SkStream* stream);

    enum EventType {
        ERROR = -1,
        START_DOCUMENT,
        END_DOCUMENT,
        START_TAG,
        END_TAG,
        TEXT,
        CDSECT,
        ENTITY_REF,
        IGNORABLE_WHITESPACE,
        PROCESSING_INSTRUCTION,
        COMMENT,
        DOCDECL
    };

    EventType   nextToken();
    EventType   getEventType() const { return fCurr.fEventType; }

    struct AttrInfo {
        const char* fName;
        const char* fValue;
    };
    
    int         getDepth() const { return fDepth; }
    const char* getName();
    int         getAttributeCount();
    void        getAttributeInfo(int, AttrInfo*);
    const char* getText();
    bool        isWhitespace();
    
protected:
    virtual bool onEntityReplacement(const char name[],
                                     SkString* replacement);

public:
    struct Curr {
        EventType   fEventType;
        const char* fName;
        AttrInfo*   fAttrInfos;
        int         fAttrInfoCount;
        bool        fIsWhitespace;
    };

private:
    // implemented in the porting layer
    bool        onInit();   // return false on failure
    EventType   onNextToken();
    void        onExit();
    
    SkStream*   fStream;
    Curr        fCurr;
    int         fDepth;
    
    struct Impl;
    Impl*   fImpl;
};
#endif

#endif