/***************************************************************************
 *   Copyright (C) 2006-2007 by Paulo Moura Guedes                              *
 *   moura@kdewebdev.org                                                   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.             *
 ***************************************************************************/

#ifndef __TIDYX_H__
#define __TIDYX_H__

/* tidyx.h -- C++ Wrapper for HTML Tidy Lib

  Pure syntax sugar!

  The C functions always pass a this-equivalent
  as 1st arg so, where possible, we just play along.
  For the doc proper, you can't mix C++ new/delete 
  with C malloc/free (or Tidy's over-ridden memory 
  functions).  So we just use containment there.

  For Sources and Sinks, we actually have a concrete
  struct definition to work with, so there inheritance
  is very helpful.

  Because the opaque types are pointer types, for 
  Options, Nodes and Attribute Values, the C++ 
  constructors are never actually called, instead
  we just cast the returns from the lib to C++
  pointers.  Essentially, we are copying the opaque
  data into *this;

  Copyright (c) 2002 Charles Reitzel, Arlington, MA  USA
  All Rights Reserved.

  Created 2002-07-11 by Charles Reitzel
*/

#include <tidy.h>
#include <buffio.h>

#include <config-tidy.h>
    
#ifdef __cplusplus

namespace Tidy
{
class Document;
class AttrVal;

/* Enums */
typedef TidyConfigCategory ConfigCategory;
typedef TidyOptionId       OptionId;
typedef TidyOptionType     OptionType;
typedef TidyTriState       TriState;
typedef TidyDoctypeModes   DoctypeModes;
typedef TidyDupAttrModes   DupAttrModes;
typedef TidyReportLevel    ReportLevel;
typedef TidyNodeType       NodeType;
typedef TidyTagId          TagId;
typedef TidyAttrId         AttrId;

/* Iterator */
typedef TidyIterator       Iterator;


/* Tidy public interface
**
** Most functions return an integer:
**
** 0    -> SUCCESS
** >0   -> WARNING
** <0   -> ERROR
** 
*/
/* I/O and Message handling interface
**
** Convert callbacks to virtual functions.
** Derive from either Source or Sink and
** provide implementations for the abstract
** I/O methods.
*/

/*****************
   Input Source
*****************/

class Source : public TidyInputSource
{
public:
  Source()
  {
    getByte    = (TidyGetByteFunc) get;
    ungetByte  = (TidyUngetByteFunc) unget;
    eof        = (TidyEOFFunc) end;
#ifdef HAVE_TIDY_ULONG_VERSION
    sourceData = (ulong) this;
#else
    sourceData = this;
#endif
  }
  virtual ~Source() {}

  virtual int  GetByte() = 0;
  virtual void UngetByte( byte bv ) = 0;
  virtual Bool IsEOF() = 0;

protected:
#ifdef HAVE_TIDY_ULONG_VERSION
  static int get( ulong data )
#else
  static int get( void* data )
#endif
  {
    Source* source = (Source*) data;
    return ( source ? source->GetByte() : EOF );
  }
#ifdef HAVE_TIDY_ULONG_VERSION
  static void unget( ulong data, byte bv )
#else
  static void unget( void* data, byte bv )
#endif
  {
    Source* source = (Source*) data;
    if ( source )
      source->UngetByte( bv );
  }
#ifdef HAVE_TIDY_ULONG_VERSION
  static Bool end( ulong data )
#else
  static Bool end( void* data )
#endif
  {
    Source* source = (Source*) data;
    return ( source ? source->IsEOF() : yes );
  }
};


/****************
   Output Sink
****************/

class Sink : public TidyOutputSink
{
public:
  Sink()
  {
    putByte  = (TidyPutByteFunc) put;
#ifdef HAVE_TIDY_ULONG_VERSION
    sinkData = (ulong) this;
#else
    sinkData = this;
#endif
  }
  virtual ~Sink() {}
  virtual void PutByte( byte bv ) = 0;

protected:
#ifdef HAVE_TIDY_ULONG_VERSION
  static void put( ulong data, byte bv )
#else
  static void put( void* data, byte bv )
#endif
  {
    Sink* sink = (Sink*) data;
    if ( sink )
      sink->PutByte( bv );
  }
};


class Buffer : public TidyBuffer
{
public:
  Buffer()                            { Init(); }
  ~Buffer()                           { Free(); }

#ifndef SWIG
  operator ctmbstr () const { return (ctmbstr)Data(); } // May not be null
  operator tmbstr ()        { return (tmbstr)Data(); }  // terminated!
#endif

  const byte* Data() const            { return bp + next; }
  byte* Data()                        { return bp + next; }

  uint Size() const                   { return size; }
  uint Allocated() const              { return allocated; }
  Bool HasData() const                { return (Bool)( size > 0 ); }
  Bool IsEmpty() const                { return (Bool)( size == 0 ); }

  void Init()                         { tidyBufInit(this); }
  void Free()                         { tidyBufFree(this); }
  void Alloc( uint buflen )           { tidyBufAlloc(this, buflen); }
  void CheckAlloc( uint buflen, uint chunkSize = 0 )
  { tidyBufCheckAlloc(this, buflen, chunkSize);
  }

  void Attach( void* vp, uint size )  { tidyBufAttach(this, (byte*) vp, size); }
  void Detach()                       { tidyBufClear(this); }

  void Clear()                        { tidyBufClear(this); }
  void Append( void* vp, uint size )  { tidyBufAppend(this, vp, size); }

  void PutByte( byte bv )             { tidyBufPutByte(this, bv); }
  int  PopByte()                      { return tidyBufPopByte(this); }

  int  GetByte()                      { return tidyBufGetByte(this); }
  Bool EndOfInput()                   { return tidyBufEndOfInput(this); }
  void UngetByte( byte bv )           { tidyBufUngetByte(this, bv); }

protected:
  TidyBuffer _buf;
};


class BufferSink : public Sink, public Buffer
{
public:
  BufferSink()                    {}
  virtual ~BufferSink()           {}

  virtual void PutByte( byte bv ) { Buffer::PutByte( bv ); }

  // Need to expose buffer methods for scripting languages
  // that do not support multiple inheritance. E.g. Java
  TidyBuffer& buf()               { return *(Buffer*)this; }
  const Buffer& buf() const       { return *(Buffer*)this; }
};

class BufferSource : public Source, public Buffer
{
public:
  BufferSource()                    {}
  virtual ~BufferSource()           {}

  virtual int  GetByte()            { return Buffer::GetByte(); }
  virtual void UngetByte( byte bv ) { Buffer::UngetByte(bv); }
  virtual Bool IsEOF()              { return Buffer::EndOfInput(); }

  // Need to expose buffer methods for scripting languages
  // that do not support multiple inheritance. E.g. Java
  Buffer& buf()                     { return *(Buffer*)this; }
  const Buffer& buf() const         { return *(Buffer*)this; }
};



class Option
{
public:
    OptionId           Id()          { return tidyOptGetId( topt() ); }
    ctmbstr            Name()        { return tidyOptGetName( topt() ); }
    OptionType         Type()        { return tidyOptGetType( topt() ); }
    Bool               IsReadOnly()  { return tidyOptIsReadOnly( topt() ); }
    ConfigCategory     Category()    { return tidyOptGetCategory( topt() ); }

    ctmbstr            Default()     { return tidyOptGetDefault( topt() ); }
    ulong              DefaultInt()  { return tidyOptGetDefaultInt( topt() ); }
    Bool               DefaultBool() { return tidyOptGetDefaultBool( topt() ); }

    Iterator           PickList()    { return tidyOptGetPickList( topt() ); }
    ctmbstr            NextPick( Iterator& pos )
    {   return tidyOptGetNextPick( topt(), &pos );
    }
protected:
    TidyOption topt()
    {  return (TidyOption) this;
    }
}; // End Option


class Node
{
public:
    /* parent / child */
    Node*   Parent()     { return (Node*) tidyGetParent( tnod() ); }
    Node*   Child()      { return (Node*) tidyGetChild( tnod() ); }

    /* siblings */
    Node*   Next()       { return (Node*) tidyGetNext( tnod() ); }
    Node*   Prev()       { return (Node*) tidyGetPrev( tnod() ); }

    /* Node info */
    NodeType Type()      { return tidyNodeGetType( tnod() ); }
    ctmbstr Name()       { return tidyNodeGetName( tnod() ); }

    /* Null for non-element nodes and all pure HTML
    ctmbstr NsLocal()    { return tidyNodeNsLocal( tnod() ); }
    ctmbstr NsPrefix()   { return tidyNodeNsPrefix( tnod() ); }
    ctmbstr NsUri()      { return tidyNodeNsUri( tnod() ); }
    */

    /* Iterate over attribute values */
    AttrVal* FirstAttr() { return (AttrVal*) tidyAttrFirst( tnod() ); }


    Bool IsText()        { return tidyNodeIsText( tnod() ); }
    Bool IsHeader()      { return tidyNodeIsHeader( tnod() ); } /* h1, h2, ... */

    TagId Id()           { return tidyNodeGetId( tnod() ); }

    Bool IsHTML()        { return tidyNodeIsHTML( tnod() ); }
    Bool IsHEAD()        { return tidyNodeIsHEAD( tnod() ); }
    Bool IsTITLE()       { return tidyNodeIsTITLE( tnod() ); }
    Bool IsBASE()        { return tidyNodeIsBASE( tnod() ); }
    Bool IsMETA()        { return tidyNodeIsMETA( tnod() ); }
    Bool IsBODY()        { return tidyNodeIsBODY( tnod() ); }
    Bool IsFRAMESET()    { return tidyNodeIsFRAMESET( tnod() ); }
    Bool IsFRAME()       { return tidyNodeIsFRAME( tnod() ); }
    Bool IsIFRAME()      { return tidyNodeIsIFRAME( tnod() ); }
    Bool IsNOFRAMES()    { return tidyNodeIsNOFRAMES( tnod() ); }
    Bool IsHR()          { return tidyNodeIsHR( tnod() ); }
    Bool IsH1()          { return tidyNodeIsH1( tnod() ); }
    Bool IsH2()          { return tidyNodeIsH2( tnod() ); }
    Bool IsPRE()         { return tidyNodeIsPRE( tnod() ); }
    Bool IsLISTING()     { return tidyNodeIsLISTING( tnod() ); }
    Bool IsP()           { return tidyNodeIsP( tnod() ); }
    Bool IsUL()          { return tidyNodeIsUL( tnod() ); }
    Bool IsOL()          { return tidyNodeIsOL( tnod() ); }
    Bool IsDL()          { return tidyNodeIsDL( tnod() ); }
    Bool IsDIR()         { return tidyNodeIsDIR( tnod() ); }
    Bool IsLI()          { return tidyNodeIsLI( tnod() ); }
    Bool IsDT()          { return tidyNodeIsDT( tnod() ); }
    Bool IsDD()          { return tidyNodeIsDD( tnod() ); }
    Bool IsTABLE()       { return tidyNodeIsTABLE( tnod() ); }
    Bool IsCAPTION()     { return tidyNodeIsCAPTION( tnod() ); }
    Bool IsTD()          { return tidyNodeIsTD( tnod() ); }
    Bool IsTH()          { return tidyNodeIsTH( tnod() ); }
    Bool IsTR()          { return tidyNodeIsTR( tnod() ); }
    Bool IsCOL()         { return tidyNodeIsCOL( tnod() ); }
    Bool IsCOLGROUP()    { return tidyNodeIsCOLGROUP( tnod() ); }
    Bool IsBR()          { return tidyNodeIsBR( tnod() ); }
    Bool IsA()           { return tidyNodeIsA( tnod() ); }
    Bool IsLINK()        { return tidyNodeIsLINK( tnod() ); }
    Bool IsB()           { return tidyNodeIsB( tnod() ); }
    Bool IsI()           { return tidyNodeIsI( tnod() ); }
    Bool IsSTRONG()      { return tidyNodeIsSTRONG( tnod() ); }
    Bool IsEM()          { return tidyNodeIsEM( tnod() ); }
    Bool IsBIG()         { return tidyNodeIsBIG( tnod() ); }
    Bool IsSMALL()       { return tidyNodeIsSMALL( tnod() ); }
    Bool IsPARAM()       { return tidyNodeIsPARAM( tnod() ); }
    Bool IsOPTION()      { return tidyNodeIsOPTION( tnod() ); }
    Bool IsOPTGROUP()    { return tidyNodeIsOPTGROUP( tnod() ); }
    Bool IsIMG()         { return tidyNodeIsIMG( tnod() ); }
    Bool IsMAP()         { return tidyNodeIsMAP( tnod() ); }
    Bool IsAREA()        { return tidyNodeIsAREA( tnod() ); }
    Bool IsNOBR()        { return tidyNodeIsNOBR( tnod() ); }
    Bool IsWBR()         { return tidyNodeIsWBR( tnod() ); }
    Bool IsFONT()        { return tidyNodeIsFONT( tnod() ); }
    Bool IsLAYER()       { return tidyNodeIsLAYER( tnod() ); }
    Bool IsSPACER()      { return tidyNodeIsSPACER( tnod() ); }
    Bool IsCENTER()      { return tidyNodeIsCENTER( tnod() ); }
    Bool IsSTYLE()       { return tidyNodeIsSTYLE( tnod() ); }
    Bool IsSCRIPT()      { return tidyNodeIsSCRIPT( tnod() ); }
    Bool IsNOSCRIPT()    { return tidyNodeIsNOSCRIPT( tnod() ); }
    Bool IsFORM()        { return tidyNodeIsFORM( tnod() ); }
    Bool IsTEXTAREA()    { return tidyNodeIsTEXTAREA( tnod() ); }
    Bool IsBLOCKQUOTE()  { return tidyNodeIsBLOCKQUOTE( tnod() ); }
    Bool IsAPPLET()      { return tidyNodeIsAPPLET( tnod() ); }
    Bool IsOBJECT()      { return tidyNodeIsOBJECT( tnod() ); }
    Bool IsDIV()         { return tidyNodeIsDIV( tnod() ); }
    Bool IsSPAN()        { return tidyNodeIsSPAN( tnod() ); }
    Bool IsINPUT()       { return tidyNodeIsINPUT( tnod() ); }
    Bool IsQ()           { return tidyNodeIsQ( tnod() ); }
    Bool IsLABEL()       { return tidyNodeIsLABEL( tnod() ); }
    Bool IsH3()          { return tidyNodeIsH3( tnod() ); }
    Bool IsH4()          { return tidyNodeIsH4( tnod() ); }
    Bool IsH5()          { return tidyNodeIsH5( tnod() ); }
    Bool IsH6()          { return tidyNodeIsH6( tnod() ); }
    Bool IsADDRESS()     { return tidyNodeIsADDRESS( tnod() ); }
    Bool IsXMP()         { return tidyNodeIsXMP( tnod() ); }
    Bool IsSELECT()      { return tidyNodeIsSELECT( tnod() ); }
    Bool IsBLINK()       { return tidyNodeIsBLINK( tnod() ); }
    Bool IsMARQUEE()     { return tidyNodeIsMARQUEE( tnod() ); }
    Bool IsEMBED()       { return tidyNodeIsEMBED( tnod() ); }
    Bool IsBASEFONT()    { return tidyNodeIsBASEFONT( tnod() ); }
    Bool IsISINDEX()     { return tidyNodeIsISINDEX( tnod() ); }
    Bool IsS()           { return tidyNodeIsS( tnod() ); }
    Bool IsSTRIKE()      { return tidyNodeIsSTRIKE( tnod() ); }
    Bool IsU()           { return tidyNodeIsU( tnod() ); }
    Bool IsMENU()        { return tidyNodeIsMENU( tnod() ); }

    /* Attribute retrieval
    */
    AttrVal* GetHREF()        { return attr(tidyAttrGetHREF( tnod() )); }
    AttrVal* GetSRC()         { return attr(tidyAttrGetSRC( tnod() )); }
    AttrVal* GetID()          { return attr(tidyAttrGetID( tnod() )); }
    AttrVal* GetNAME()        { return attr(tidyAttrGetNAME( tnod() )); }
    AttrVal* GetSUMMARY()     { return attr(tidyAttrGetSUMMARY( tnod() )); }
    AttrVal* GetALT()         { return attr(tidyAttrGetALT( tnod() )); }
    AttrVal* GetLONGDESC()    { return attr(tidyAttrGetLONGDESC( tnod() )); }
    AttrVal* GetUSEMAP()      { return attr(tidyAttrGetUSEMAP( tnod() )); }
    AttrVal* GetISMAP()       { return attr(tidyAttrGetISMAP( tnod() )); }
    AttrVal* GetLANGUAGE()    { return attr(tidyAttrGetLANGUAGE( tnod() )); }
    AttrVal* GetTYPE()        { return attr(tidyAttrGetTYPE( tnod() )); }
    AttrVal* GetVALUE()       { return attr(tidyAttrGetVALUE( tnod() )); }
    AttrVal* GetCONTENT()     { return attr(tidyAttrGetCONTENT( tnod() )); }
    AttrVal* GetTITLE()       { return attr(tidyAttrGetTITLE( tnod() )); }
    AttrVal* GetXMLNS()       { return attr(tidyAttrGetXMLNS( tnod() )); }
    AttrVal* GetDATAFLD()     { return attr(tidyAttrGetDATAFLD( tnod() )); }
    AttrVal* GetWIDTH()       { return attr(tidyAttrGetWIDTH( tnod() )); }
    AttrVal* GetHEIGHT()      { return attr(tidyAttrGetHEIGHT( tnod() )); }
    AttrVal* GetFOR()         { return attr(tidyAttrGetFOR( tnod() )); }
    AttrVal* GetSELECTED()    { return attr(tidyAttrGetSELECTED( tnod() )); }
    AttrVal* GetCHECKED()     { return attr(tidyAttrGetCHECKED( tnod() )); }
    AttrVal* GetLANG()        { return attr(tidyAttrGetLANG( tnod() )); }
    AttrVal* GetTARGET()      { return attr(tidyAttrGetTARGET( tnod() )); }
    AttrVal* GetHTTP_EQUIV()  { return attr(tidyAttrGetHTTP_EQUIV(tnod())); }
    AttrVal* GetREL()         { return attr(tidyAttrGetREL( tnod() )); }
    AttrVal* GetOnMOUSEMOVE() { return attr(tidyAttrGetOnMOUSEMOVE(tnod())); }
    AttrVal* GetOnMOUSEDOWN() { return attr(tidyAttrGetOnMOUSEDOWN(tnod())); }
    AttrVal* GetOnMOUSEUP()   { return attr(tidyAttrGetOnMOUSEUP( tnod() )); }
    AttrVal* GetOnCLICK()     { return attr(tidyAttrGetOnCLICK( tnod() )); }
    AttrVal* GetOnMOUSEOVER() { return attr(tidyAttrGetOnMOUSEOVER(tnod())); }
    AttrVal* GetOnMOUSEOUT()  { return attr(tidyAttrGetOnMOUSEOUT(tnod())); }
    AttrVal* GetOnKEYDOWN()   { return attr(tidyAttrGetOnKEYDOWN( tnod() )); }
    AttrVal* GetOnKEYUP()     { return attr(tidyAttrGetOnKEYUP( tnod() )); }
    AttrVal* GetOnKEYPRESS()  { return attr(tidyAttrGetOnKEYPRESS(tnod())); }
    AttrVal* GetOnFOCUS()     { return attr(tidyAttrGetOnFOCUS( tnod() )); }
    AttrVal* GetOnBLUR()      { return attr(tidyAttrGetOnBLUR( tnod() )); }
    AttrVal* GetBGCOLOR()     { return attr(tidyAttrGetBGCOLOR( tnod() )); }
    AttrVal* GetLINK()        { return attr(tidyAttrGetLINK( tnod() )); }
    AttrVal* GetALINK()       { return attr(tidyAttrGetALINK( tnod() )); }
    AttrVal* GetVLINK()       { return attr(tidyAttrGetVLINK( tnod() )); }
    AttrVal* GetTEXT()        { return attr(tidyAttrGetTEXT( tnod() )); }
    AttrVal* GetSTYLE()       { return attr(tidyAttrGetSTYLE( tnod() )); }
    AttrVal* GetABBR()        { return attr(tidyAttrGetABBR( tnod() )); }
    AttrVal* GetCOLSPAN()     { return attr(tidyAttrGetCOLSPAN( tnod() )); }
    AttrVal* GetROWSPAN()     { return attr(tidyAttrGetROWSPAN( tnod() )); }

protected:
    AttrVal* attr( TidyAttr tattr )
    {   return (AttrVal*) tattr;
    }
    Node* node( TidyNode tnod )
    {   return (Node*) tnod;
    }
    TidyNode tnod()
    {   return (TidyNode) this;
    }
}; // End Node

/* Attribute interrogation
*/

class AttrVal
{
public:
    AttrVal* Next()        { return (AttrVal*) tidyAttrNext( tattr() ); }

    ctmbstr Name()         { return tidyAttrName( tattr() ); }
    ctmbstr Value()        { return tidyAttrValue( tattr() ); }

    /* Null for pure HTML
    ctmbstr NsLocal()      { return tidyAttrNsLocal( tattr() ); }
    ctmbstr NsPrefix()     { return tidyAttrNsPrefix( tattr() ); }
    ctmbstr NsUri()        { return tidyAttrNsUri( tattr() ); }
    */

    AttrId Id()            { return tidyAttrGetId( tattr() ); }
    Bool IsEvent()         { return tidyAttrIsEvent( tattr() ); }
    Bool IsProp()          { return tidyAttrIsProp( tattr() ); }

    Bool IsHREF()          { return tidyAttrIsHREF( tattr() ); }
    Bool IsSRC()           { return tidyAttrIsSRC( tattr() ); }
    Bool IsID()            { return tidyAttrIsID( tattr() ); }
    Bool IsNAME()          { return tidyAttrIsNAME( tattr() ); }
    Bool IsSUMMARY()       { return tidyAttrIsSUMMARY( tattr() ); }
    Bool IsALT()           { return tidyAttrIsALT( tattr() ); }
    Bool IsLONGDESC()      { return tidyAttrIsLONGDESC( tattr() ); }
    Bool IsUSEMAP()        { return tidyAttrIsUSEMAP( tattr() ); }
    Bool IsISMAP()         { return tidyAttrIsISMAP( tattr() ); }
    Bool IsLANGUAGE()      { return tidyAttrIsLANGUAGE( tattr() ); }
    Bool IsTYPE()          { return tidyAttrIsTYPE( tattr() ); }
    Bool IsVALUE()         { return tidyAttrIsVALUE( tattr() ); }
    Bool IsCONTENT()       { return tidyAttrIsCONTENT( tattr() ); }
    Bool IsTITLE()         { return tidyAttrIsTITLE( tattr() ); }
    Bool IsXMLNS()         { return tidyAttrIsXMLNS( tattr() ); }
    Bool IsDATAFLD()       { return tidyAttrIsDATAFLD( tattr() ); }
    Bool IsWIDTH()         { return tidyAttrIsWIDTH( tattr() ); }
    Bool IsHEIGHT()        { return tidyAttrIsHEIGHT( tattr() ); }
    Bool IsFOR()           { return tidyAttrIsFOR( tattr() ); }
    Bool IsSELECTED()      { return tidyAttrIsSELECTED( tattr() ); }
    Bool IsCHECKED()       { return tidyAttrIsCHECKED( tattr() ); }
    Bool IsLANG()          { return tidyAttrIsLANG( tattr() ); }
    Bool IsTARGET()        { return tidyAttrIsTARGET( tattr() ); }
    Bool IsHTTP_EQUIV()    { return tidyAttrIsHTTP_EQUIV( tattr() ); }
    Bool IsREL()           { return tidyAttrIsREL( tattr() ); }
    Bool IsOnMouseMove()   { return tidyAttrIsOnMOUSEMOVE( tattr() ); }
    Bool IsOnMouseDown()   { return tidyAttrIsOnMOUSEDOWN( tattr() ); }
    Bool IsOnMouseUp()     { return tidyAttrIsOnMOUSEUP( tattr() ); }
    Bool IsOnClick()       { return tidyAttrIsOnCLICK( tattr() ); }
    Bool IsOnMouseOver()   { return tidyAttrIsOnMOUSEOVER( tattr() ); }
    Bool IsOnMouseOut()    { return tidyAttrIsOnMOUSEOUT( tattr() ); }
    Bool IsOnKeyDown()     { return tidyAttrIsOnKEYDOWN( tattr() ); }
    Bool IsOnKeyUp()       { return tidyAttrIsOnKEYUP( tattr() ); }
    Bool IsOnKeyPress()    { return tidyAttrIsOnKEYPRESS( tattr() ); }
    Bool IsOnFOCUS()       { return tidyAttrIsOnFOCUS( tattr() ); }
    Bool IsOnBLUR()        { return tidyAttrIsOnBLUR( tattr() ); }
    Bool IsBGCOLOR()       { return tidyAttrIsBGCOLOR( tattr() ); }
    Bool IsLINK()          { return tidyAttrIsLINK( tattr() ); }
    Bool IsALINK()         { return tidyAttrIsALINK( tattr() ); }
    Bool IsVLINK()         { return tidyAttrIsVLINK( tattr() ); }
    Bool IsTEXT()          { return tidyAttrIsTEXT( tattr() ); }
    Bool IsSTYLE()         { return tidyAttrIsSTYLE( tattr() ); }
    Bool IsABBR()          { return tidyAttrIsABBR( tattr() ); }
    Bool IsCOLSPAN()       { return tidyAttrIsCOLSPAN( tattr() ); }
    Bool IsROWSPAN()       { return tidyAttrIsROWSPAN( tattr() ); }

protected:
    TidyAttr tattr()
    {   return (TidyAttr) this;
    }
}; // End AttrVal



class Document
{
public:
    Document() : _tdoc(NULL) {}
    virtual ~Document() { Release(); }

    int  Create()
    {
        Release();
        if ( (_tdoc = tidyCreate()) )
        {
#ifdef HAVE_TIDY_ULONG_VERSION
            tidySetAppData( _tdoc, (ulong) this );
#else
            tidySetAppData( _tdoc, this );
#endif
            tidySetReportFilter( _tdoc, (TidyReportFilter) ReportFilter );
            return 0;
        }
        return -1;
    }
    void Release()
    {
        tidyRelease( _tdoc );
        _tdoc = NULL;
    }

    /* Let application store a chunk of data w/ each Tidy instance.
    ** Useful for callbacks.
    */
#ifdef HAVE_TIDY_ULONG_VERSION
    void  SetAppData( ulong data ) { tidySetAppData( _tdoc, data ); }
    ulong GetAppData()             { return tidyGetAppData( _tdoc ); }
#else
    void  SetAppData( void* data ) { tidySetAppData( _tdoc, data ); }
    void* GetAppData()             { return tidyGetAppData( _tdoc ); }
#endif

    static ctmbstr ReleaseDate()  { return tidyReleaseDate(); }

    /* Diagnostics and Repair */
    int   Status()                { return tidyStatus( _tdoc ); }
    int   DetectedHtmlVersion()   { return tidyDetectedHtmlVersion( _tdoc ); }
    Bool  DetectedXhtml()         { return tidyDetectedXhtml( _tdoc ); }
    Bool  DetectedGenericXml()    { return tidyDetectedGenericXml( _tdoc ); }

    uint  ErrorCount()            { return tidyErrorCount( _tdoc ); }
    uint  WarningCount()          { return tidyWarningCount( _tdoc ); }
    uint  AccessWarningCount()    { return tidyAccessWarningCount( _tdoc ); }
    uint  ConfigErrorCount()      { return tidyConfigErrorCount( _tdoc ); }

    /* Get/Set configuration options
    */
    int   LoadConfig( ctmbstr configFile )
    {   return tidyLoadConfig( _tdoc, configFile );
    }
    int   LoadConfigEnc( ctmbstr configFile, ctmbstr charenc )
    {   return tidyLoadConfigEnc( _tdoc, configFile, charenc );
    }

    int   SetCharEncoding( ctmbstr encnam )
    {   return tidySetCharEncoding( _tdoc, encnam );
    }


    static OptionId  OptGetIdForName( ctmbstr optnam )
    {   return tidyOptGetIdForName( optnam );
    }

    Iterator  GetOptionList()
    {   return tidyGetOptionList( _tdoc );
    }
    Option*   GetNextOption( Iterator& pos )
    {   return (Option*) tidyGetNextOption( _tdoc, &pos );
    }

    Option*   GetOption( OptionId optId )
    {   return (Option*) tidyGetOption( _tdoc, optId );
    }
    Option*   GetOptionByName( ctmbstr optnam )
    {   return (Option*) tidyGetOptionByName( _tdoc, optnam );
    }


    ctmbstr       OptGetValue( OptionId optId )
    {   return tidyOptGetValue( _tdoc, optId );
    }
    Bool          OptSetValue( OptionId optId, ctmbstr val )
    {   return tidyOptSetValue( _tdoc, optId, val );
    }
    Bool          OptParseValue( ctmbstr optnam, ctmbstr val )
    {   return tidyOptParseValue( _tdoc, optnam, val );
    }
    uint          OptGetInt( OptionId optId )
    {   return tidyOptGetInt( _tdoc, optId );
    }
    Bool          OptSetInt( OptionId optId, uint val )
    {   return tidyOptSetInt( _tdoc, optId, val );
    }
    Bool          OptGetBool( OptionId optId )
    {   return tidyOptGetBool( _tdoc, optId );
    }
    Bool          OptSetBool( OptionId optId, Bool val )
    {   return tidyOptSetBool( _tdoc, optId, val );
    }


    Bool          OptResetToDefault( OptionId opt )
    {   return tidyOptResetToDefault( _tdoc, opt );
    }
    Bool          OptResetAllToDefault()
    {   return tidyOptResetAllToDefault( _tdoc );
    }
    /* reset to config (after document processing) */
    Bool          OptSnapshot()
    {   return tidyOptSnapshot( _tdoc );
    }
    Bool          OptDiffThanSnapshot()
    {   return tidyOptDiffThanSnapshot( _tdoc );
    }
    Bool          OptDiffThanDefault()
    {   return tidyOptDiffThanDefault( _tdoc );
    }
    Bool          OptResetToSnapshot()
    {   return tidyOptResetToSnapshot( _tdoc );
    }
    Bool          OptCopyConfig( Document& from )
    {   return tidyOptCopyConfig( _tdoc, from._tdoc );
    }
    ctmbstr       OptGetEncName( OptionId optId )
    {   return tidyOptGetEncName( _tdoc, optId );
    }
    ctmbstr       OptGetCurrPick( OptionId optId )
    {   return tidyOptGetCurrPick( _tdoc, optId );
    }
    Iterator      OptGetDeclTagList()
    {   return tidyOptGetDeclTagList( _tdoc );
    }
    ctmbstr       OptGetNextDeclTag( OptionId optId, Iterator* iter )
    {   return tidyOptGetNextDeclTag( _tdoc, optId, iter );
    }


    FILE*         SetErrorFile( ctmbstr errfilnam )
    {   return tidySetErrorFile( _tdoc, errfilnam );
    }
    int           SetErrorSink( Sink& sink )
    {   return tidySetErrorSink( _tdoc, &sink );
    }

    // Override this virtual function to filter out
    // or redirect error messages.  Return yes (true),
    // for Tidy to proceed with error output. To 
    // suppress the message, return no (false).

    virtual Bool OnMessage( ReportLevel /*lvl*/, uint /*line*/, uint /*col*/, ctmbstr /*msg */)
    {
        return yes;
    }


    /* Parse/load Functions
    **
    ** HTML/XHTML version determined from input.
    */
    int         ParseFile( ctmbstr filename )
    {   return tidyParseFile( _tdoc, filename );
    }
    int         ParseStdin()
    {   return tidyParseStdin( _tdoc );
    }
    int         ParseString( ctmbstr content )
    {   return tidyParseString( _tdoc, content );
    }
    int         ParseBuffer( Buffer& inbuf )
    {   return tidyParseBuffer( _tdoc, &inbuf );
    }
    int         ParseSource( Source& source )
    {   return tidyParseSource( _tdoc, &source );
    }


    /* Diagnostics and Repair
    */
    int         CleanAndRepair()
    {   return tidyCleanAndRepair( _tdoc );
    }
    int         RunDiagnostics()
    {   return tidyRunDiagnostics( _tdoc );
    }


    /* Document save Functions
    **
    ** If buffer is not big enough, ENOMEM will be returned and
    ** the necessary buffer size will be placed in *buflen.
    */
    int         SaveFile( ctmbstr filename )
    {   return tidySaveFile( _tdoc, filename );
    }
    int         SaveStdout()
    {   return tidySaveStdout( _tdoc );
    }
    int         SaveString( tmbstr buffer, uint* buflen )
    {   return tidySaveString( _tdoc, buffer, buflen );
    }
    int         SaveBuffer( Buffer& outbuf )
    {   return tidySaveBuffer( _tdoc, &outbuf );
    }
    int         SaveSink( Sink& sink )
    {   return tidySaveSink( _tdoc, &sink );
    }

    int         OptSaveFile( ctmbstr cfgfil )
    {   return tidyOptSaveFile( _tdoc, cfgfil );
    }
    int         OptSaveSink( Sink& sink )
    {   return tidyOptSaveSink( _tdoc, &sink );
    }

    /* Error reporting functions 
    */
    void        ErrorSummary()
    {   tidyErrorSummary( _tdoc );
    }
    void        GeneralInfo()
    {   tidyGeneralInfo( _tdoc );
    }

    /* Document tree traversal functions
    */

    Node*  GetRoot()
    {   return (Node*) tidyGetRoot( _tdoc );
    }
    Node*  GetHtml()
    {   return (Node*) tidyGetHtml( _tdoc );
    }
    Node*  GetHead()
    {   return (Node*) tidyGetHead( _tdoc );
    }
    Node*  GetBody()
    {   return (Node*) tidyGetBody( _tdoc );
    }

    Bool IsPropietary( Node* node )
    {   return tidyNodeIsProp( _tdoc, (TidyNode)node );
    }
    Bool HasText( Node* node )
    { return tidyNodeHasText( _tdoc, (TidyNode)node );
    }
    Bool GetNodeText( Node* node, Buffer& outbuf )
    { return tidyNodeGetText( _tdoc, (TidyNode)node, &outbuf );
    }


protected:
    TidyDoc _tdoc;


    /* Convert report filter callback to a virtual function.
    */
    static Bool ReportFilter( TidyDoc tdoc,
                              TidyReportLevel lvl, uint line, uint col, ctmbstr msg )
    {
        Document* doc = (Document*) tidyGetAppData( tdoc );
        if ( doc )
            return doc->OnMessage( lvl, line, col, msg );
        return no;
    }
};  // End Tidy Doc


} // End Namespace
#endif /* __cplusplus */
#endif /* __TIDYX_H__ */
