#define __ENABLE_WSTRING 1
#include <cstdio>   // FILE
#include <string>   // string,wstring
#include <iconv.h>  // iconv_t
#include <vector>   // vector

#include "autoptr"

using namespace std;

//#define wstring ucs4string
typedef wchar_t ucs4;
//typedef unsigned int ucs4;
//typedef basic_string<ucs4> wstring;

// Note: address of ilseq must be available
// Thus don't make this #define
static const ucs4 ilseq = 0xFFFD;
static const ucs4 ucsig = 0xFEFF;

#if 1
/* libstdc++ 2 way */
static const wstring emptywstring;
#define CLEARSTR(x) x=emptywstring
#else
/* libstdc++ 3 way */
#define CLEARSTR(x) x.clear()
#endif

class Page
{
    class Dumper
    {
        mutable iconv_t converter;
        mutable iconv_t tester;
        
        bool OpenConv(iconv_t &conv, const char *set1, const char *set2);
    public:
        string charset;
        
        Dumper();
        ~Dumper();
        void SetSet(const char *setname);
        
        void putc(ucs4 p) const;
        void puts(const wstring &s) const;
        
        bool isok(ucs4 p) const;
    } Dumper;
    
    bool CanDump(ucs4 p) const
    {
        return Dumper.isok(p);
    }
    
    mutable char underquote;

    wstring htmlencode(const wstring &s) const;
    wstring htmldecode(const wstring &s) const;
    
    void Putc(ucs4 p) const
    {
        Dumper.putc(p);
    }
    void Dump(const wstring &s) const
    {
        Dumper.puts(s);
    }
    void DumpHTML(const wstring &s) const
    {
        Dump(htmlencode(s));
    }
    void DumpHTML(const wstring &s, char quotetype) const
    {
        underquote = quotetype;
        DumpHTML(s);
        underquote = 0;
    }
    
    struct Tag;
    struct PI;
    
    void DumpTag(const Tag &) const;
    void DumpPI(const PI &) const;
    void DumpRaw(const wstring &) const;
    
    class Element : public ptrable
    {
    public:
        Element() {}
        virtual ~Element() {}
    };
    
    class ElemBody;
    class ElemTag;
    class ElemRaw;
    class ElemPI;

    vector<autoptr<Element> > Structure;

    void push_back(Element *e) { Structure.push_back(e); }

public:
    void Dump() const;
    
    void SetOut(const char *midset);

    void FilterText(wstring (*proc)(const wstring &));
    void ParseUCS4(FILE *fp);
    void Parse(FILE *fp, const char *charset = "iso-8859-1");
    
    Page(): underquote(0) {}
};
