/**
 * License Agreement.
 *
 * Rich Faces - Natural Ajax for Java Server Faces (JSF)
 *
 * Copyright (C) 2007 Exadel, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 */

/*
 *  Java HTML Tidy - JTidy
 *  HTML parser and pretty printer
 *
 *  Copyright (c) 1998-2000 World Wide Web Consortium (Massachusetts
 *  Institute of Technology, Institut National de Recherche en
 *  Informatique et en Automatique, Keio University). All Rights
 *  Reserved.
 *
 *  Contributing Author(s):
 *
 *     Dave Raggett <dsr@w3.org>
 *     Andy Quick <ac.quick@sympatico.ca> (translation to Java)
 *     Gary L Peskin <garyp@firstech.com> (Java development)
 *     Sami Lempinen <sami@lempinen.net> (release management)
 *     Fabrizio Giustina <fgiust at users.sourceforge.net>
 *
 *  The contributing author(s) would like to thank all those who
 *  helped with testing, bug fixes, and patience.  This wouldn't
 *  have been possible without all of you.
 *
 *  COPYRIGHT NOTICE:
 * 
 *  This software and documentation is provided "as is," and
 *  the copyright holders and contributing author(s) make no
 *  representations or warranties, express or implied, including
 *  but not limited to, warranties of merchantability or fitness
 *  for any particular purpose or that the use of the software or
 *  documentation will not infringe any third party patents,
 *  copyrights, trademarks or other rights. 
 *
 *  The copyright holders and contributing author(s) will not be
 *  liable for any direct, indirect, special or consequential damages
 *  arising out of any use of the software or documentation, even if
 *  advised of the possibility of such damage.
 *
 *  Permission is hereby granted to use, copy, modify, and distribute
 *  this source code, or portions hereof, documentation and executables,
 *  for any purpose, without fee, subject to the following restrictions:
 *
 *  1. The origin of this source code must not be misrepresented.
 *  2. Altered versions must be plainly marked as such and must
 *     not be misrepresented as being the original source.
 *  3. This Copyright notice may not be removed or altered from any
 *     source or altered source distribution.
 * 
 *  The copyright holders and contributing author(s) specifically
 *  permit, without fee, and encourage the use of this source code
 *  as a component for supporting the Hypertext Markup Language in
 *  commercial products. If you use this source code in a product,
 *  acknowledgment is not required but would be appreciated.
 *
 */
package org.ajax4jsf.org.w3c.tidy;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Serializable;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.ajax4jsf.io.FastBufferOutputStream;
import org.ajax4jsf.io.FastBufferWriter;


/**
 * HTML parser and pretty printer.
 * @author Dave Raggett <a href="mailto:dsr@w3.org">dsr@w3.org </a>
 * @author Andy Quick <a href="mailto:ac.quick@sympatico.ca">ac.quick@sympatico.ca </a> (translation to Java)
 * @author Fabrizio Giustina
 * @version $Revision: 1.1.2.1 $ ($Author: alexsmirnov $)
 */
public class Tidy implements Serializable
{

    /**
     * Serial Version UID to avoid problems during serialization.
     */
    static final long serialVersionUID = -2794371560623987718L;

    /**
     * Alias for configuration options accepted in command line.
     */
    private static final Map CMDLINE_ALIAS = new HashMap();

    static
    {
        CMDLINE_ALIAS.put("xml", "input-xml");
        CMDLINE_ALIAS.put("xml", "output-xhtml");
        CMDLINE_ALIAS.put("asxml", "output-xhtml");
        CMDLINE_ALIAS.put("ashtml", "output-html");
        CMDLINE_ALIAS.put("omit", "hide-endtags");
        CMDLINE_ALIAS.put("upper", "uppercase-tags");
        CMDLINE_ALIAS.put("raw", "output-raw");
        CMDLINE_ALIAS.put("numeric", "numeric-entities");
        CMDLINE_ALIAS.put("change", "write-back");
        CMDLINE_ALIAS.put("update", "write-back");
        CMDLINE_ALIAS.put("modify", "write-back");
        CMDLINE_ALIAS.put("errors", "only-errors");
        CMDLINE_ALIAS.put("slides", "split");
        CMDLINE_ALIAS.put("lang", "language");
        CMDLINE_ALIAS.put("w", "wrap");
        CMDLINE_ALIAS.put("file", "error-file");
        CMDLINE_ALIAS.put("f", "error-file");
    }

    /**
     * Error output stream.
     */
    private PrintWriter errout;

    private PrintWriter stderr;

    private Configuration configuration;

    private String inputStreamName = "InputStream";

    private int parseErrors;

    private int parseWarnings;

    private Report report;

    /**
     * Instantiates a new Tidy instance. It's reccomended that a new instance is used at each parsing.
     */
    public Tidy()
    {
        this.report = new Report();
        configuration = new Configuration(this.report);
        if (configuration == null)
        {
            return;
        }

        AttributeTable at = AttributeTable.getDefaultAttributeTable();
        if (at == null)
        {
            return;
        }
        TagTable tt = new TagTable();
        if (tt == null)
        {
            return;
        }
        tt.setConfiguration(configuration);
        configuration.tt = tt;
        EntityTable et = EntityTable.getDefaultEntityTable();
        if (et == null)
        {
            return;
        }

        configuration.errfile = null;
        stderr = new PrintWriter(System.err, true);
        errout = stderr;
    }

    /**
     * Returns the actual configuration
     * @return tidy configuration
     */
    public Configuration getConfiguration()
    {
        return configuration;
    }

    public PrintWriter getStderr()
    {
        return stderr;
    }

    /**
     * ParseErrors - the number of errors that occurred in the most recent parse operation.
     * @return number of errors that occurred in the most recent parse operation.
     */
    public int getParseErrors()
    {
        return parseErrors;
    }

    /**
     * ParseWarnings - the number of warnings that occurred in the most recent parse operation.
     * @return number of warnings that occurred in the most recent parse operation.
     */
    public int getParseWarnings()
    {
        return parseWarnings;
    }

    /**
     * InputStreamName - the name of the input stream (printed in the header information).
     * @param name input stream name
     */
    public void setInputStreamName(String name)
    {
        if (name != null)
        {
            inputStreamName = name;
        }
    }

    public String getInputStreamName()
    {
        return inputStreamName;
    }

    /**
     * Errout - the error output stream.
     * @return error output stream.
     */
    public PrintWriter getErrout()
    {
        return errout;
    }

    public void setErrout(PrintWriter out)
    {
        this.errout = out;
    }

    /**
     * Sets the configuration from a configuration file.
     * @param filename configuration file name/path.
     */
    public void setConfigurationFromFile(String filename)
    {
        configuration.parseFile(filename);
    }

    /**
     * Sets the configuration from a properties object.
     * @param props Properties object
     */
    public void setConfigurationFromProps(Properties props)
    {
        configuration.addProps(props);
    }

    /**
     * Parses InputStream in and returns the root Node. If out is non-null, pretty prints to OutputStream out.
     * @param in input content Possible {@link InputStream} , {@link Reader} or {@link String}.
     * @param out optional output stream
     * @return parsed org.w3c.tidy.Node
     */
    public Node parse(Object in, OutputStream out)
    {
        Node document = null;

        try
        {
            document = parse(in, null, out);
        }
        catch (FileNotFoundException fnfe)
        {
            // ignore
        }
        catch (IOException e)
        {
            // ignore
        }

        return document;
    }

    /**
     * Internal routine that actually does the parsing. The caller can pass either an InputStream or file name. If both
     * are passed, the file name is preferred.
     * @param in input content (used only if <code>file</code> is null) Possible {@link InputStream} , {@link Reader} or {@link String}.
     * @param file file name
     * @param out output stream
     * @return parsed org.w3c.tidy.Node
     * @throws FileNotFoundException if <code>file</code> is not null but it can't be found
     * @throws IOException for errors in reading input stream or file
     */
    private Node parse(Object in, String file, OutputStream out) throws FileNotFoundException, IOException
    {
        Lexer lexer;
        Node document = null;
        Node doctype;
        PPrint pprint;

        if (errout == null)
        {
            return null;
        }

        parseErrors = 0;
        parseWarnings = 0;

        // ensure config is self-consistent
        configuration.adjust();

        if (file != null)
        {
            in = new FileInputStream(file);
            inputStreamName = file;
        }
        else if (in == null)
        {
            in = System.in;
            inputStreamName = "stdin";
        }

        if (in != null)
        {

            StreamIn streamIn = StreamInFactory.getStreamIn(configuration, in);

            lexer = new Lexer(streamIn, configuration, this.report);
            lexer.errout = errout;

            // store pointer to lexer in input stream to allow character encoding errors to be reported
            streamIn.setLexer(lexer);

            this.report.setFilename(inputStreamName); // #431895 - fix by Dave Bryan 04 Jan 01

            if (!configuration.quiet)
            {
                this.report.helloMessage(errout);
            }

            // skip byte order mark

            //            if (lexer.configuration.getInCharEncoding() == Configuration.UTF8
            //                || lexer.configuration.getInCharEncoding() == Configuration.UTF16LE
            //                || lexer.configuration.getInCharEncoding() == Configuration.UTF16BE
            //                || lexer.configuration.getInCharEncoding() == Configuration.UTF16)
            //            {
            //                int c = lexer.in.readChar();
            //                if (c != EncodingUtils.UNICODE_BOM)
            //                {
            //                    lexer.in.ungetChar(c);
            //                }
            //            }

            // Tidy doesn't alter the doctype for generic XML docs
            if (configuration.xmlTags)
            {
                document = ParserImpl.parseXMLDocument(lexer);
                if (!document.checkNodeIntegrity())
                {
                    if (!configuration.quiet)
                    {
                        report.badTree(errout);
                    }
                    return null;
                }
            }
            else
            {
                lexer.warnings = 0;

                document = ParserImpl.parseDocument(lexer);

                if (!document.checkNodeIntegrity())
                {
                    if (!configuration.quiet)
                    {
                        this.report.badTree(errout);
                    }
                    return null;
                }

                Clean cleaner = new Clean(configuration.tt);

                // simplifies <b><b> ... </b> ... </b> etc.
                cleaner.nestedEmphasis(document);

                // cleans up <dir> indented text </dir> etc.
                cleaner.list2BQ(document);
                cleaner.bQ2Div(document);

                // replaces i by em and b by strong
                if (configuration.logicalEmphasis)
                {
                    cleaner.emFromI(document);
                }

                if (configuration.word2000 && cleaner.isWord2000(document))
                {
                    // prune Word2000's <![if ...]> ... <![endif]>
                    cleaner.dropSections(lexer, document);

                    // drop style & class attributes and empty p, span elements
                    cleaner.cleanWord2000(lexer, document);
                }

                // replaces presentational markup by style rules
                if (configuration.makeClean || configuration.dropFontTags)
                {
                    cleaner.cleanTree(lexer, document);
                }

                if (!document.checkNodeIntegrity())
                {
                    this.report.badTree(errout);
                    return null;
                }

                doctype = document.findDocType();

                // remember given doctype
                if (doctype != null)
                {
                    doctype = (Node) doctype.clone();
                }

                if (document.content != null)
                {
                    if (configuration.xHTML)
                    {
                        lexer.setXHTMLDocType(document);
                    }
                    else
                    {
                        lexer.fixDocType(document);
                    }

                    if (configuration.tidyMark)
                    {
                        lexer.addGenerator(document);
                    }
                }

                // ensure presence of initial <?XML version="1.0"?>
                if (configuration.xmlOut && configuration.xmlPi)
                {
                    lexer.fixXmlDecl(document);
                }

                if (!configuration.quiet && document.content != null)
                {
                    this.report.reportVersion(errout, lexer, inputStreamName, doctype);
                }
            }

            // Try to close the InputStream but only if if we created it.
            if ((file != null) && (in != System.in))
            {
                try
                {
                    ((FileInputStream) in).close();
                }
                catch (IOException e)
                {
                    // ignore
                }
            }

            if (!configuration.quiet)
            {
                parseWarnings = lexer.warnings;
                parseErrors = lexer.errors;
                this.report.reportNumWarnings(errout, lexer);
            }

            if (!configuration.quiet && lexer.errors > 0 && !configuration.forceOutput)
            {
                this.report.needsAuthorIntervention(errout);
            }

            if (!configuration.onlyErrors && (lexer.errors == 0 || configuration.forceOutput))
            {
                if (configuration.burstSlides)
                {
                    Node body;

                    body = null;
                    // remove doctype to avoid potential clash with markup introduced when bursting into slides

                    // discard the document type
                    doctype = document.findDocType();

                    if (doctype != null)
                    {
                        Node.discardElement(doctype);
                    }

                    /* slides use transitional features */
                    lexer.versions |= Dict.VERS_HTML40_LOOSE;

                    // and patch up doctype to match
                    if (configuration.xHTML)
                    {
                        lexer.setXHTMLDocType(document);
                    }
                    else
                    {
                        lexer.fixDocType(document);
                    }

                    // find the body element which may be implicit
                    body = document.findBody(configuration.tt);

                    if (body != null)
                    {
                        pprint = new PPrint(configuration);
                        if (!configuration.quiet)
                        {
                            this.report.reportNumberOfSlides(errout, pprint.countSlides(body));
                        }
                        pprint.createSlides(lexer, document);
                    }
                    else if (!configuration.quiet)
                    {
                        this.report.missingBody(errout);
                    }
                }
                else if (configuration.writeback && (file != null))
                {
                    try
                    {
                        pprint = new PPrint(configuration);
                        FileOutputStream fis = new FileOutputStream(file);

                        Out o = OutFactory.getOut(this.configuration, fis);

                        if (document.findDocType() == null)
                        {
                            // only use numeric character references if no doctype could be determined (e.g., because
                            // the document contains proprietary features) to ensure well-formedness.
                            configuration.numEntities = true;
                        }
                        if (configuration.bodyOnly)
                        {
                            // Feature request #434940 - fix by Dave Raggett/Ignacio Vazquez-Abrams 21 Jun 01
                            pprint.printBody(o, lexer, document, configuration.xmlOut);
                        }
                        else if (configuration.xmlOut && !configuration.xHTML)
                        {
                            pprint.printXMLTree(o, (short) 0, 0, lexer, document);
                        }
                        else
                        {
                            pprint.printTree(o, (short) 0, 0, lexer, document);
                        }

                        pprint.flushLine(o, 0);
                        o.close();
                    }
                    catch (IOException e)
                    {
                        errout.println(file + e.toString());
                    }
                }
                else if (out != null)
                {
                    pprint = new PPrint(configuration);

                    Out o = OutFactory.getOut(this.configuration, out); // normal output stream

                    if (document.findDocType() == null)
                    {
                        // only use numeric character references if no doctype could be determined (e.g., because
                        // the document contains proprietary features) to ensure well-formedness.
                        configuration.numEntities = true;
                    }
                    if (configuration.bodyOnly)
                    {
                        // Feature request #434940 - fix by Dave Raggett/Ignacio Vazquez-Abrams 21 Jun 01
                        pprint.printBody(o, lexer, document, configuration.xmlOut);
                    }
                    else if (configuration.xmlOut && !configuration.xHTML)
                    {
                        pprint.printXMLTree(o, (short) 0, 0, lexer, document);
                    }
                    else
                    {
                        pprint.printTree(o, (short) 0, 0, lexer, document);
                    }

                    pprint.flushLine(o, 0);
                    o.close();
                }

            }

            if (!configuration.quiet)
            {
                this.report.errorSummary(lexer);
            }
        }
        return document;
    }

    /**
     * Parses InputStream in and returns a DOM Document node. If out is non-null, pretty prints to OutputStream out.
     * @param in input stream. Possible {@link InputStream} , {@link Reader} or {@link String}.
     * @param out optional output stream
     * @return parsed org.w3c.dom.Document
     */
    public org.w3c.dom.Document parseDOM(Object in, OutputStream out)
    {
        Node document = parse(in, out);
        if (document != null)
        {
            return (org.w3c.dom.Document) document.getAdapter();
        }
        return null;
    }

    /**
     * Creates an empty DOM Document.
     * @return a new org.w3c.dom.Document
     */
    public static org.w3c.dom.Document createEmptyDocument()
    {
        Node document = new Node(Node.ROOT_NODE, new byte[0], 0, 0);
        Node node = new Node(Node.START_TAG, new byte[0], 0, 0, "html", new TagTable());
        if (document != null && node != null)
        {
            document.insertNodeAtStart(node);
            return (org.w3c.dom.Document) document.getAdapter();
        }

        return null;
    }

    /**
     * Pretty-prints a DOM Document. Must be an instance of org.w3c.tidy.DOMDocumentImpl.
     * @param doc org.w3c.dom.Document
     * @param out output stream
     * @throws IOException 
     */
    public void pprint(org.w3c.dom.Document doc, OutputStream out) throws IOException
    {
        if (!(doc instanceof DOMDocumentImpl))
        {
            // @todo should we inform users that tidy can't print a generic Document or change the method signature?
            return;
        }

        if (null != out) {
			pprint(((DOMDocumentImpl) doc).adaptee, OutFactory.getOut(
					this.configuration, out));
		}
    }

    /**
     * Pretty-prints a DOM Document. Must be an instance of org.w3c.tidy.DOMDocumentImpl.
     * @param doc org.w3c.dom.Document
     * @param out output stream
     * @throws IOException 
     */
    public void pprint(org.w3c.dom.Document doc, Writer out) throws IOException
    {
        if (!(doc instanceof DOMDocumentImpl))
        {
            // @todo should we inform users that tidy can't print a generic Document or change the method signature?
            return;
        }

        if (null != out) {
        	if(!(out instanceof FastBufferWriter)) {
        		FastBufferWriter bout = new FastBufferWriter();
    			pprint(((DOMDocumentImpl) doc).adaptee, OutFactory.getOut(
    					this.configuration, bout));
    			bout.writeTo(out);
        	} else {
    			pprint(((DOMDocumentImpl) doc).adaptee, OutFactory.getOut(
    					this.configuration, out));
        	}
		}
    }

    /**
     * Pretty-prints a DOM Node.
     * @param node org.w3c.dom.Node. Must be an instance of org.w3c.tidy.DOMNodeImpl.
     * @param out output stream
     * @throws IOException 
     */
    public void pprint(org.w3c.dom.Node node, OutputStream out) throws IOException
    {
        if (!(node instanceof DOMNodeImpl))
        {
            // @todo should we inform users than tidy can't print a generic Node or change the method signature?
            return;
        }
        if (null != out) {
        	if(!(out instanceof FastBufferOutputStream)) {
        		FastBufferOutputStream bout = new FastBufferOutputStream();
    			pprint(((DOMNodeImpl) node).adaptee, OutFactory.getOut(
    					this.configuration, bout));
    			bout.writeTo(out);
        	} else {
    			pprint(((DOMNodeImpl) node).adaptee, OutFactory.getOut(
    					this.configuration, out));
        	}
		}
    }

    /**
     * Pretty-prints a tidy Node.
     * @param node org.w3c.tidy.Node
     * @param out output stream
     * @throws IOException 
     */
    private void pprint(Node node, Out o) throws IOException
    {

        Lexer lexer = new Lexer(null, this.configuration, this.report);

		PPrint pprint = new PPrint(configuration);

		if (configuration.xmlTags)
		{
		    pprint.printXMLTree(o, (short) 0, 0, lexer, node);
		}
		else
		{
		    pprint.printTree(o, (short) 0, 0, lexer, node);
		}

		pprint.flushLine(o, 0);
		o.close();
    }

    /**
     * Command line interface to parser and pretty printer.
     * @param argv command line parameters
     */
    public static void main(String[] argv)
    {
        Tidy tidy = new Tidy();
        int returnCode = tidy.mainExec(argv);
        System.exit(returnCode);
    }

    /**
     * Main method, but returns the return code as an int instead of calling System.exit(code). Needed for testing main
     * method without shutting down tests.
     * @param argv command line parameters
     * @return return code
     */
    protected int mainExec(String[] argv)
    {
        String file;
        int argCount = argv.length;
        int argIndex = 0;

        // read command line
        Properties properties = new Properties();

        while (argCount > 0)
        {
            if (argv[argIndex].startsWith("-"))
            {
                // support -foo and --foo
                String argName = argv[argIndex].toLowerCase();
                while (argName.length() > 0 && argName.charAt(0) == '-')
                {
                    argName = argName.substring(1);
                }

                // "exclusive" options
                if (argName.equals("help") || argName.equals("h") || argName.equals("?"))
                {
                    this.report.helpText(new PrintWriter(System.out, true));
                    return 0;
                }
                else if (argName.equals("help-config"))
                {
                    configuration.printConfigOptions(new PrintWriter(System.out, true), false);
                    return 0;
                }
                else if (argName.equals("show-config"))
                {
                    configuration.adjust(); // ensure config is self-consistent
                    configuration.printConfigOptions(errout, true);
                    return 0;
                }
                else if (argName.equals("version") || argName.equals("v"))
                {
                    this.report.showVersion(errout);
                    return 0;
                }

                // optional value for non boolean options
                String argValue = null;
                if (argCount > 2 && !argv[argIndex + 1].startsWith("-"))
                {
                    argValue = argv[argIndex + 1];
                    --argCount;
                    ++argIndex;
                }

                // handle "special" aliases
                String alias = (String) CMDLINE_ALIAS.get(argName);
                if (alias != null)
                {
                    argName = alias;
                }

                if (Configuration.isKnownOption(argName)) // handle any standard config option
                {
                    properties.setProperty(argName, (argValue == null ? "" : argName));
                }
                else if (argName.equals("config")) // parse a property file
                {
                    if (argValue != null)
                    {
                        configuration.parseFile(argValue);
                    }
                }
                else if (TidyUtils.isCharEncodingSupported(argName)) // handle any encoding name
                {
                    properties.setProperty("char-encoding", argName);
                }
                else
                {

                    for (int i = 0; i < argName.length(); i++)
                    {
                        switch (argName.charAt(i))
                        {
                            case 'i' :
                                configuration.indentContent = true;
                                configuration.smartIndent = true;
                                break;

                            case 'o' :
                                configuration.hideEndTags = true;
                                break;

                            case 'u' :
                                configuration.upperCaseTags = true;
                                break;

                            case 'c' :
                                configuration.makeClean = true;
                                break;

                            case 'b' :
                                configuration.makeBare = true;
                                break;

                            case 'n' :
                                configuration.numEntities = true;
                                break;

                            case 'm' :
                                configuration.writeback = true;
                                break;

                            case 'e' :
                                configuration.onlyErrors = true;
                                break;

                            case 'q' :
                                configuration.quiet = true;
                                break;

                            default :
                                this.report.unknownOption(this.errout, argName.charAt(i));
                                break;
                        }
                    }
                }

                --argCount;
                ++argIndex;
                continue;
            }

            configuration.addProps(properties);

            // ensure config is self-consistent
            configuration.adjust();

            // user specified error file
            if (configuration.errfile != null)
            {

                String errorfile = "stderr";

                // is it same as the currently opened file?
                if (!configuration.errfile.equals(errorfile))
                {
                    // no so close previous error file

                    if (this.errout != this.stderr)
                    {
                        this.errout.close();
                    }

                    // and try to open the new error file
                    try
                    {
                        this.setErrout(new PrintWriter(new FileWriter(configuration.errfile), true));
                        errorfile = configuration.errfile;
                    }
                    catch (IOException e)
                    {
                        // can't be opened so fall back to stderr
                        errorfile = "stderr";
                        this.setErrout(stderr);
                    }
                }
            }

            if (argCount > 0)
            {
                file = argv[argIndex];
            }
            else
            {
                file = "stdin";
            }

            try
            {
                parse(null, file, System.out);
            }
            catch (FileNotFoundException fnfe)
            {
                this.report.unknownFile(this.errout, file);
            }
            catch (IOException ioe)
            {
                this.report.unknownFile(this.errout, file);
            }

            --argCount;
            ++argIndex;

            if (argCount <= 0)
            {
                break;
            }
        }

        if (this.parseErrors + this.parseWarnings > 0 && !configuration.quiet)
        {
            this.report.generalInfo(this.errout);
        }

        if (this.errout != this.stderr)
        {
            this.errout.close();
        }

        // return status can be used by scripts
        if (this.parseErrors > 0)
        {
            return 2;
        }

        if (this.parseWarnings > 0)
        {
            return 1;
        }

        // 0 means all is ok
        return 0;
    }

    /**
     * Attach a TidyMessageListener which will be notified for messages and errors.
     * @param listener TidyMessageListener implementation
     */
    public void setMessageListener(TidyMessageListener listener)
    {
        this.report.addMessageListener(listener);
    }

    /**
     * <code>indent-spaces</code>- default indentation.
     * @param spaces number of spaces used for indentation
     * @see Configuration#spaces
     */
    public void setSpaces(int spaces)
    {
        configuration.spaces = spaces;
    }

    /**
     * <code>indent-spaces</code>- default indentation.
     * @return number of spaces used for indentation
     * @see Configuration#spaces
     */
    public int getSpaces()
    {
        return configuration.spaces;
    }

    /**
     * <code>wrap</code>- default wrap margin.
     * @param wraplen default wrap margin
     * @see Configuration#wraplen
     */
    public void setWraplen(int wraplen)
    {
        configuration.wraplen = wraplen;
    }

    /**
     * <code>wrap</code>- default wrap margin.
     * @return default wrap margin
     * @see Configuration#wraplen
     */
    public int getWraplen()
    {
        return configuration.wraplen;
    }

    /**
     * <code>tab-size</code>- tab size in chars.
     * @param tabsize tab size in chars
     * @see Configuration#tabsize
     */
    public void setTabsize(int tabsize)
    {
        configuration.tabsize = tabsize;
    }

    /**
     * <code>tab-size</code>- tab size in chars.
     * @return tab size in chars
     * @see Configuration#tabsize
     */
    public int getTabsize()
    {
        return configuration.tabsize;
    }

    /**
     * Errfile - file name to write errors to.
     * @param errfile file name to write errors to
     * @see Configuration#errfile
     */
    public void setErrfile(String errfile)
    {
        configuration.errfile = errfile;
    }

    /**
     * Errfile - file name to write errors to.
     * @return error file name
     * @see Configuration#errfile
     */
    public String getErrfile()
    {
        return configuration.errfile;
    }

    /**
     * writeback - if true then output tidied markup. NOTE: this property is ignored when parsing from an InputStream.
     * @param writeback <code>true</code>= output tidied markup
     * @see Configuration#writeback
     */
    public void setWriteback(boolean writeback)
    {
        configuration.writeback = writeback;
    }

    /**
     * writeback - if true then output tidied markup. NOTE: this property is ignored when parsing from an InputStream.
     * @return <code>true</code> if tidy will output tidied markup in input file
     * @see Configuration#writeback
     */
    public boolean getWriteback()
    {
        return configuration.writeback;
    }

    /**
     * only-errors - if true normal output is suppressed.
     * @param onlyErrors if <code>true</code> normal output is suppressed.
     * @see Configuration#onlyErrors
     */
    public void setOnlyErrors(boolean onlyErrors)
    {
        configuration.onlyErrors = onlyErrors;
    }

    /**
     * only-errors - if true normal output is suppressed.
     * @return <code>true</code> if normal output is suppressed.
     * @see Configuration#onlyErrors
     */
    public boolean getOnlyErrors()
    {
        return configuration.onlyErrors;
    }

    /**
     * show-warnings - show warnings? (errors are always shown).
     * @param showWarnings if <code>false</code> warnings are not shown
     * @see Configuration#showWarnings
     */
    public void setShowWarnings(boolean showWarnings)
    {
        configuration.showWarnings = showWarnings;
    }

    /**
     * show-warnings - show warnings? (errors are always shown).
     * @return <code>false</code> if warnings are not shown
     * @see Configuration#showWarnings
     */
    public boolean getShowWarnings()
    {
        return configuration.showWarnings;
    }

    /**
     * quiet - no 'Parsing X', guessed DTD or summary.
     * @param quiet <code>true</code>= don't output summary, warnings or errors
     * @see Configuration#quiet
     */
    public void setQuiet(boolean quiet)
    {
        configuration.quiet = quiet;
    }

    /**
     * quiet - no 'Parsing X', guessed DTD or summary.
     * @return <code>true</code> if tidy will not output summary, warnings or errors
     * @see Configuration#quiet
     */
    public boolean getQuiet()
    {
        return configuration.quiet;
    }

    /**
     * indent - indent content of appropriate tags.
     * @param indentContent indent content of appropriate tags
     * @see Configuration#indentContent
     */
    public void setIndentContent(boolean indentContent)
    {
        configuration.indentContent = indentContent;
    }

    /**
     * indent - indent content of appropriate tags.
     * @return <code>true</code> if tidy will indent content of appropriate tags
     * @see Configuration#indentContent
     */
    public boolean getIndentContent()
    {
        return configuration.indentContent;
    }

    /**
     * SmartIndent - does text/block level content effect indentation.
     * @param smartIndent <code>true</code> if text/block level content should effect indentation
     * @see Configuration#smartIndent
     */
    public void setSmartIndent(boolean smartIndent)
    {
        configuration.smartIndent = smartIndent;
    }

    /**
     * SmartIndent - does text/block level content effect indentation.
     * @return <code>true</code> if text/block level content should effect indentation
     * @see Configuration#smartIndent
     */
    public boolean getSmartIndent()
    {
        return configuration.smartIndent;
    }

    /**
     * hide-endtags - suppress optional end tags.
     * @param hideEndTags <code>true</code>= suppress optional end tags
     * @see Configuration#hideEndTags
     */
    public void setHideEndTags(boolean hideEndTags)
    {
        configuration.hideEndTags = hideEndTags;
    }

    /**
     * hide-endtags - suppress optional end tags.
     * @return <code>true</code> if tidy will suppress optional end tags
     * @see Configuration#hideEndTags
     */
    public boolean getHideEndTags()
    {
        return configuration.hideEndTags;
    }

    /**
     * input-xml - treat input as XML.
     * @param xmlTags <code>true</code> if tidy should treat input as XML
     * @see Configuration#xmlTags
     */
    public void setXmlTags(boolean xmlTags)
    {
        configuration.xmlTags = xmlTags;
    }

    /**
     * input-xml - treat input as XML.
     * @return <code>true</code> if tidy will treat input as XML
     * @see Configuration#xmlTags
     */
    public boolean getXmlTags()
    {
        return configuration.xmlTags;
    }

    /**
     * output-xml - create output as XML.
     * @param xmlOut <code>true</code> if tidy should create output as xml
     * @see Configuration#xmlOut
     */
    public void setXmlOut(boolean xmlOut)
    {
        configuration.xmlOut = xmlOut;
    }

    /**
     * output-xml - create output as XML.
     * @return <code>true</code> if tidy will create output as xml
     * @see Configuration#xmlOut
     */
    public boolean getXmlOut()
    {
        return configuration.xmlOut;
    }

    /**
     * output-xhtml - output extensible HTML.
     * @param xhtml <code>true</code> if tidy should output XHTML
     * @see Configuration#xHTML
     */
    public void setXHTML(boolean xhtml)
    {
        configuration.xHTML = xhtml;
    }

    /**
     * output-xhtml - output extensible HTML.
     * @return <code>true</code> if tidy will output XHTML
     * @see Configuration#xHTML
     */
    public boolean getXHTML()
    {
        return configuration.xHTML;
    }

    /**
     * uppercase-tags - output tags in upper case.
     * @param upperCaseTags <code>true</code> if tidy should output tags in upper case (default is lowercase)
     * @see Configuration#upperCaseTags
     */
    public void setUpperCaseTags(boolean upperCaseTags)
    {
        configuration.upperCaseTags = upperCaseTags;
    }

    /**
     * uppercase-tags - output tags in upper case.
     * @return <code>true</code> if tidy should will tags in upper case
     * @see Configuration#upperCaseTags
     */
    public boolean getUpperCaseTags()
    {
        return configuration.upperCaseTags;
    }

    /**
     * uppercase-attributes - output attributes in upper case.
     * @param upperCaseAttrs <code>true</code> if tidy should output attributes in upper case (default is lowercase)
     * @see Configuration#upperCaseAttrs
     */
    public void setUpperCaseAttrs(boolean upperCaseAttrs)
    {
        configuration.upperCaseAttrs = upperCaseAttrs;
    }

    /**
     * uppercase-attributes - output attributes in upper case.
     * @return <code>true</code> if tidy should will attributes in upper case
     * @see Configuration#upperCaseAttrs
     */
    public boolean getUpperCaseAttrs()
    {
        return configuration.upperCaseAttrs;
    }

    /**
     * make-clean - remove presentational clutter.
     * @param makeClean true to remove presentational clutter
     * @see Configuration#makeClean
     */
    public void setMakeClean(boolean makeClean)
    {
        configuration.makeClean = makeClean;
    }

    /**
     * make-clean - remove presentational clutter.
     * @return true if tidy will remove presentational clutter
     * @see Configuration#makeClean
     */
    public boolean getMakeClean()
    {
        return configuration.makeClean;
    }

    /**
     * make-bare - remove Microsoft cruft.
     * @param makeBare true to remove Microsoft cruft
     * @see Configuration#makeBare
     */
    public void setMakeBare(boolean makeBare)
    {
        configuration.makeBare = makeBare;
    }

    /**
     * make-clean - remove Microsoft cruft.
     * @return true if tidy will remove Microsoft cruft
     * @see Configuration#makeBare
     */
    public boolean getMakeBare()
    {
        return configuration.makeBare;
    }

    /**
     * break-before-br - output newline before &lt;br&gt;.
     * @param breakBeforeBR <code>true</code> if tidy should output a newline before &lt;br&gt;
     * @see Configuration#breakBeforeBR
     */
    public void setBreakBeforeBR(boolean breakBeforeBR)
    {
        configuration.breakBeforeBR = breakBeforeBR;
    }

    /**
     * break-before-br - output newline before &lt;br&gt;.
     * @return <code>true</code> if tidy will output a newline before &lt;br&gt;
     * @see Configuration#breakBeforeBR
     */
    public boolean getBreakBeforeBR()
    {
        return configuration.breakBeforeBR;
    }

    /**
     * <code>split</code>- create slides on each h2 element.
     * @param burstSlides <code>true</code> if tidy should create slides on each h2 element
     * @see Configuration#burstSlides
     */
    public void setBurstSlides(boolean burstSlides)
    {
        configuration.burstSlides = burstSlides;
    }

    /**
     * <code>split</code>- create slides on each h2 element.
     * @return <code>true</code> if tidy will create slides on each h2 element
     * @see Configuration#burstSlides
     */
    public boolean getBurstSlides()
    {
        return configuration.burstSlides;
    }

    /**
     * <code>numeric-entities</code>- output entities other than the built-in HTML entities in the numeric rather
     * than the named entity form.
     * @param numEntities <code>true</code> if tidy should output entities in the numeric form.
     * @see Configuration#numEntities
     */
    public void setNumEntities(boolean numEntities)
    {
        configuration.numEntities = numEntities;
    }

    /**
     * <code>numeric-entities</code>- output entities other than the built-in HTML entities in the numeric rather
     * than the named entity form.
     * @return <code>true</code> if tidy will output entities in the numeric form.
     * @see Configuration#numEntities
     */
    public boolean getNumEntities()
    {
        return configuration.numEntities;
    }

    /**
     * <code>quote-marks</code>- output " marks as &amp;quot;.
     * @param quoteMarks <code>true</code> if tidy should output " marks as &amp;quot;
     * @see Configuration#quoteMarks
     */
    public void setQuoteMarks(boolean quoteMarks)
    {
        configuration.quoteMarks = quoteMarks;
    }

    /**
     * <code>quote-marks</code>- output " marks as &amp;quot;.
     * @return <code>true</code> if tidy will output " marks as &amp;quot;
     * @see Configuration#quoteMarks
     */
    public boolean getQuoteMarks()
    {
        return configuration.quoteMarks;
    }

    /**
     * <code>quote-nbsp</code>- output non-breaking space as entity.
     * @param quoteNbsp <code>true</code> if tidy should output non-breaking space as entity
     * @see Configuration#quoteNbsp
     */
    public void setQuoteNbsp(boolean quoteNbsp)
    {
        configuration.quoteNbsp = quoteNbsp;
    }

    /**
     * <code>quote-nbsp</code>- output non-breaking space as entity.
     * @return <code>true</code> if tidy will output non-breaking space as entity
     * @see Configuration#quoteNbsp
     */
    public boolean getQuoteNbsp()
    {
        return configuration.quoteNbsp;
    }

    /**
     * <code>quote-ampersand</code>- output naked ampersand as &amp;.
     * @param quoteAmpersand <code>true</code> if tidy should output naked ampersand as &amp;
     * @see Configuration#quoteAmpersand
     */
    public void setQuoteAmpersand(boolean quoteAmpersand)
    {
        configuration.quoteAmpersand = quoteAmpersand;
    }

    /**
     * <code>quote-ampersand</code>- output naked ampersand as &amp;.
     * @return <code>true</code> if tidy will output naked ampersand as &amp;
     * @see Configuration#quoteAmpersand
     */
    public boolean getQuoteAmpersand()
    {
        return configuration.quoteAmpersand;
    }

    /**
     * <code>wrap-attributes</code>- wrap within attribute values.
     * @param wrapAttVals <code>true</code> if tidy should wrap within attribute values
     * @see Configuration#wrapAttVals
     */
    public void setWrapAttVals(boolean wrapAttVals)
    {
        configuration.wrapAttVals = wrapAttVals;
    }

    /**
     * <code>wrap-attributes</code>- wrap within attribute values.
     * @return <code>true</code> if tidy will wrap within attribute values
     * @see Configuration#wrapAttVals
     */
    public boolean getWrapAttVals()
    {
        return configuration.wrapAttVals;
    }

    /**
     * <code>wrap-script-literals</code>- wrap within JavaScript string literals.
     * @param wrapScriptlets <code>true</code> if tidy should wrap within JavaScript string literals
     * @see Configuration#wrapScriptlets
     */
    public void setWrapScriptlets(boolean wrapScriptlets)
    {
        configuration.wrapScriptlets = wrapScriptlets;
    }

    /**
     * <code>wrap-script-literals</code>- wrap within JavaScript string literals.
     * @return <code>true</code> if tidy will wrap within JavaScript string literals
     * @see Configuration#wrapScriptlets
     */
    public boolean getWrapScriptlets()
    {
        return configuration.wrapScriptlets;
    }

    /**
     * <code>wrap-sections</code>- wrap within &lt;![ ... ]&gt; section tags
     * @param wrapSection <code>true</code> if tidy should wrap within &lt;![ ... ]&gt; section tags
     * @see Configuration#wrapSection
     */
    public void setWrapSection(boolean wrapSection)
    {
        configuration.wrapSection = wrapSection;
    }

    /**
     * <code>wrap-sections</code>- wrap within &lt;![ ... ]&gt; section tags
     * @return <code>true</code> if tidy will wrap within &lt;![ ... ]&gt; section tags
     * @see Configuration#wrapSection
     */
    public boolean getWrapSection()
    {
        return configuration.wrapSection;
    }

    /**
     * <code>alt-text</code>- default text for alt attribute.
     * @param altText default text for alt attribute
     * @see Configuration#altText
     */
    public void setAltText(String altText)
    {
        configuration.altText = altText;
    }

    /**
     * <code>alt-text</code>- default text for alt attribute.
     * @return default text for alt attribute
     * @see Configuration#altText
     */
    public String getAltText()
    {
        return configuration.altText;
    }

    /**
     * <code>add-xml-pi</code>- add &lt;?xml?&gt; for XML docs.
     * @param xmlPi <code>true</code> if tidy should add &lt;?xml?&gt; for XML docs
     * @see Configuration#xmlPi
     */
    public void setXmlPi(boolean xmlPi)
    {
        configuration.xmlPi = xmlPi;
    }

    /**
     * <code>add-xml-pi</code>- add &lt;?xml?&gt; for XML docs.
     * @return <code>true</code> if tidy will add &lt;?xml?&gt; for XML docs
     * @see Configuration#xmlPi
     */
    public boolean getXmlPi()
    {
        return configuration.xmlPi;
    }

    /**
     * <code>drop-font-tags</code>- discard presentation tags.
     * @param dropFontTags <code>true</code> if tidy should discard presentation tags
     * @see Configuration#dropFontTags
     */
    public void setDropFontTags(boolean dropFontTags)
    {
        configuration.dropFontTags = dropFontTags;
    }

    /**
     * <code>drop-font-tags</code>- discard presentation tags.
     * @return <code>true</code> if tidy will discard presentation tags
     * @see Configuration#dropFontTags
     */
    public boolean getDropFontTags()
    {
        return configuration.dropFontTags;
    }

    /**
     * <code>drop-proprietary-attributes</code>- discard proprietary attributes.
     * @param dropProprietaryAttributes <code>true</code> if tidy should discard proprietary attributes
     * @see Configuration#dropProprietaryAttributes
     */
    public void setDropProprietaryAttributes(boolean dropProprietaryAttributes)
    {
        configuration.dropProprietaryAttributes = dropProprietaryAttributes;
    }

    /**
     * <code>drop-proprietary-attributes</code>- discard proprietary attributes.
     * @return <code>true</code> if tidy will discard proprietary attributes
     * @see Configuration#dropProprietaryAttributes
     */
    public boolean getDropProprietaryAttributes()
    {
        return configuration.dropProprietaryAttributes;
    }

    /**
     * <code>drop-empty-paras</code>- discard empty p elements.
     * @param dropEmptyParas <code>true</code> if tidy should discard empty p elements
     * @see Configuration#dropEmptyParas
     */
    public void setDropEmptyParas(boolean dropEmptyParas)
    {
        configuration.dropEmptyParas = dropEmptyParas;
    }

    /**
     * <code>drop-empty-paras</code>- discard empty p elements.
     * @return <code>true</code> if tidy will discard empty p elements
     * @see Configuration#dropEmptyParas
     */
    public boolean getDropEmptyParas()
    {
        return configuration.dropEmptyParas;
    }

    /**
     * <code>fix-bad-comments</code>- fix comments with adjacent hyphens.
     * @param fixComments <code>true</code> if tidy should fix comments with adjacent hyphens
     * @see Configuration#fixComments
     */
    public void setFixComments(boolean fixComments)
    {
        configuration.fixComments = fixComments;
    }

    /**
     * <code>fix-bad-comments</code>- fix comments with adjacent hyphens.
     * @return <code>true</code> if tidy will fix comments with adjacent hyphens
     * @see Configuration#fixComments
     */
    public boolean getFixComments()
    {
        return configuration.fixComments;
    }

    /**
     * <code>wrap-asp</code>- wrap within ASP pseudo elements.
     * @param wrapAsp <code>true</code> if tidy should wrap within ASP pseudo elements
     * @see Configuration#wrapAsp
     */
    public void setWrapAsp(boolean wrapAsp)
    {
        configuration.wrapAsp = wrapAsp;
    }

    /**
     * <code>wrap-asp</code>- wrap within ASP pseudo elements.
     * @return <code>true</code> if tidy will wrap within ASP pseudo elements
     * @see Configuration#wrapAsp
     */
    public boolean getWrapAsp()
    {
        return configuration.wrapAsp;
    }

    /**
     * <code>wrap-jste</code>- wrap within JSTE pseudo elements.
     * @param wrapJste <code>true</code> if tidy should wrap within JSTE pseudo elements
     * @see Configuration#wrapJste
     */
    public void setWrapJste(boolean wrapJste)
    {
        configuration.wrapJste = wrapJste;
    }

    /**
     * <code>wrap-jste</code>- wrap within JSTE pseudo elements.
     * @return <code>true</code> if tidy will wrap within JSTE pseudo elements
     * @see Configuration#wrapJste
     */
    public boolean getWrapJste()
    {
        return configuration.wrapJste;
    }

    /**
     * <code>wrap-php</code>- wrap within PHP pseudo elements.
     * @param wrapPhp <code>true</code> if tidy should wrap within PHP pseudo elements
     * @see Configuration#wrapPhp
     */
    public void setWrapPhp(boolean wrapPhp)
    {
        configuration.wrapPhp = wrapPhp;
    }

    /**
     * <code>wrap-php</code>- wrap within PHP pseudo elements.
     * @return <code>true</code> if tidy will wrap within PHP pseudo elements
     * @see Configuration#wrapPhp
     */
    public boolean getWrapPhp()
    {
        return configuration.wrapPhp;
    }

    /**
     * <code>fix-backslash</code>- fix URLs by replacing \ with /.
     * @param fixBackslash <code>true</code> if tidy should fix URLs by replacing \ with /
     * @see Configuration#fixBackslash
     */
    public void setFixBackslash(boolean fixBackslash)
    {
        configuration.fixBackslash = fixBackslash;
    }

    /**
     * <code>fix-backslash</code>- fix URLs by replacing \ with /.
     * @return <code>true</code> if tidy will fix URLs by replacing \ with /
     * @see Configuration#fixBackslash
     */
    public boolean getFixBackslash()
    {
        return configuration.fixBackslash;
    }

    /**
     * <code>indent-attributes</code>- newline+indent before each attribute.
     * @param indentAttributes <code>true</code> if tidy should output a newline+indent before each attribute
     * @see Configuration#indentAttributes
     */
    public void setIndentAttributes(boolean indentAttributes)
    {
        configuration.indentAttributes = indentAttributes;
    }

    /**
     * <code>indent-attributes</code>- newline+indent before each attribute.
     * @return <code>true</code> if tidy will output a newline+indent before each attribute
     * @see Configuration#indentAttributes
     */
    public boolean getIndentAttributes()
    {
        return configuration.indentAttributes;
    }

    /**
     * <code>doctype</code>- user specified doctype.
     * @param doctype <code>omit | auto | strict | loose | <em>fpi</em></code> where the <em>fpi </em> is a string
     * similar to &quot;-//ACME//DTD HTML 3.14159//EN&quot; Note: for <em>fpi </em> include the double-quotes in the
     * string.
     * @see Configuration#docTypeStr
     * @see Configuration#docTypeMode
     */
    public void setDocType(String doctype)
    {
        if (doctype != null)
        {
            configuration.docTypeStr = (String) ParsePropertyImpl.DOCTYPE.parse(doctype, "doctype", configuration);
        }
    }

    /**
     * <code>doctype</code>- user specified doctype.
     * @return <code>omit | auto | strict | loose | <em>fpi</em></code> where the <em>fpi </em> is a string similar
     * to &quot;-//ACME//DTD HTML 3.14159//EN&quot; Note: for <em>fpi </em> include the double-quotes in the string.
     * @see Configuration#docTypeStr
     * @see Configuration#docTypeMode
     */
    public String getDocType()
    {
        String result = null;
        switch (configuration.docTypeMode)
        {
            case Configuration.DOCTYPE_OMIT :
                result = "omit";
                break;
            case Configuration.DOCTYPE_AUTO :
                result = "auto";
                break;
            case Configuration.DOCTYPE_STRICT :
                result = "strict";
                break;
            case Configuration.DOCTYPE_LOOSE :
                result = "loose";
                break;
            case Configuration.DOCTYPE_IGNORE :
                result = "ignore";
                break;
            case Configuration.DOCTYPE_USER :
                result = configuration.docTypeStr;
                break;
        }
        return result;
    }

    /**
     * <code>logical-emphasis</code>- replace i by em and b by strong.
     * @param logicalEmphasis <code>true</code> if tidy should replace i by em and b by strong
     * @see Configuration#logicalEmphasis
     */
    public void setLogicalEmphasis(boolean logicalEmphasis)
    {
        configuration.logicalEmphasis = logicalEmphasis;
    }

    /**
     * <code>logical-emphasis</code>- replace i by em and b by strong.
     * @return <code>true</code> if tidy will replace i by em and b by strong
     * @see Configuration#logicalEmphasis
     */
    public boolean getLogicalEmphasis()
    {
        return configuration.logicalEmphasis;
    }

    /**
     * <code>assume-xml-procins</code> This option specifies if Tidy should change the parsing of processing
     * instructions to require ?> as the terminator rather than >. This option is automatically set if the input is in
     * XML.
     * @param xmlPIs <code>true</code> if tidy should expect a ?> at the end of processing instructions
     * @see Configuration#xmlPIs
     */
    public void setXmlPIs(boolean xmlPIs)
    {
        configuration.xmlPIs = xmlPIs;
    }

    /**
     * <code>assume-xml-procins</code> This option specifies if Tidy should change the parsing of processing
     * instructions to require ?> as the terminator rather than >. This option is automatically set if the input is in
     * XML.
     * @return <code>true</code> if tidy will expect a ?> at the end of processing instructions
     * @see Configuration#xmlPIs
     */
    public boolean getXmlPIs()
    {
        return configuration.xmlPIs;
    }

    /**
     * <code>enclose-text</code>- if true text at body is wrapped in &lt;p&gt;'s.
     * @param encloseText <code>true</code> if tidy should wrap text at body in &lt;p&gt;'s.
     * @see Configuration#encloseBodyText
     */
    public void setEncloseText(boolean encloseText)
    {
        configuration.encloseBodyText = encloseText;
    }

    /**
     * <code>enclose-text</code>- if true text at body is wrapped in &lt;p&gt;'s.
     * @return <code>true</code> if tidy will wrap text at body in &lt;p&gt;'s.
     * @see Configuration#encloseBodyText
     */
    public boolean getEncloseText()
    {
        return configuration.encloseBodyText;
    }

    /**
     * <code>enclose-block-text</code>- if true text in blocks is wrapped in &lt;p&gt;'s.
     * @param encloseBlockText <code>true</code> if tidy should wrap text text in blocks in &lt;p&gt;'s.
     * @see Configuration#encloseBlockText
     */
    public void setEncloseBlockText(boolean encloseBlockText)
    {
        configuration.encloseBlockText = encloseBlockText;
    }

    /**
     * <code>enclose-block-text</code>- if true text in blocks is wrapped in &lt;p&gt;'s. return <code>true</code>
     * if tidy should will text text in blocks in &lt;p&gt;'s.
     * @see Configuration#encloseBlockText
     */
    public boolean getEncloseBlockText()
    {
        return configuration.encloseBlockText;
    }

    /**
     * <code>word-2000</code>- draconian cleaning for Word2000.
     * @param word2000 <code>true</code> if tidy should clean word2000 documents
     * @see Configuration#word2000
     */
    public void setWord2000(boolean word2000)
    {
        configuration.word2000 = word2000;
    }

    /**
     * <code>word-2000</code>- draconian cleaning for Word2000.
     * @return <code>true</code> if tidy will clean word2000 documents
     * @see Configuration#word2000
     */
    public boolean getWord2000()
    {
        return configuration.word2000;
    }

    /**
     * <code>tidy-mark</code>- add meta element indicating tidied doc.
     * @param tidyMark <code>true</code> if tidy should add meta element indicating tidied doc
     * @see Configuration#tidyMark
     */
    public void setTidyMark(boolean tidyMark)
    {
        configuration.tidyMark = tidyMark;
    }

    /**
     * <code>tidy-mark</code>- add meta element indicating tidied doc.
     * @return <code>true</code> if tidy will add meta element indicating tidied doc
     * @see Configuration#tidyMark
     */
    public boolean getTidyMark()
    {
        return configuration.tidyMark;
    }

    /**
     * <code>add-xml-space</code>- if set to yes adds xml:space attr as needed.
     * @param xmlSpace <code>true</code> if tidy should add xml:space attr as needed
     * @see Configuration#xmlSpace
     */
    public void setXmlSpace(boolean xmlSpace)
    {
        configuration.xmlSpace = xmlSpace;
    }

    /**
     * <code>add-xml-space</code>- if set to yes adds xml:space attr as needed.
     * @return <code>true</code> if tidy will add xml:space attr as needed
     * @see Configuration#xmlSpace
     */
    public boolean getXmlSpace()
    {
        return configuration.xmlSpace;
    }

    /**
     * <code>gnu-emacs</code>- if true format error output for GNU Emacs.
     * @param emacs <code>true</code> if tidy should format error output for GNU Emacs
     * @see Configuration#emacs
     */
    public void setEmacs(boolean emacs)
    {
        configuration.emacs = emacs;
    }

    /**
     * <code>gnu-emacs</code>- if true format error output for GNU Emacs.
     * @return <code>true</code> if tidy will format error output for GNU Emacs
     * @see Configuration#emacs
     */
    public boolean getEmacs()
    {
        return configuration.emacs;
    }

    /**
     * <code>literal-attributes</code>- if true attributes may use newlines.
     * @param literalAttribs <code>true</code> if attributes may use newlines
     * @see Configuration#literalAttribs
     */
    public void setLiteralAttribs(boolean literalAttribs)
    {
        configuration.literalAttribs = literalAttribs;
    }

    /**
     * <code>literal-attributes</code>- if true attributes may use newlines.
     * @return <code>true</code> if attributes may use newlines
     * @see Configuration#literalAttribs
     */
    public boolean getLiteralAttribs()
    {
        return configuration.literalAttribs;
    }

    /**
     * <code>print-body-only</code>- output BODY content only.
     * @param bodyOnly true = print only the document body
     * @see Configuration#bodyOnly
     */
    public void setPrintBodyOnly(boolean bodyOnly)
    {
        configuration.bodyOnly = bodyOnly;
    }

    /**
     * <code>print-body-only</code>- output BODY content only.
     * @return true if tidy will print only the document body
     */
    public boolean getPrintBodyOnly()
    {
        return configuration.bodyOnly;
    }

    /**
     * <code>fix-uri</code>- fix uri references applying URI encoding if necessary.
     * @param fixUri true = fix uri references
     * @see Configuration#fixUri
     */
    public void setFixUri(boolean fixUri)
    {
        configuration.fixUri = fixUri;
    }

    /**
     * <code>fix-uri</code>- output BODY content only.
     * @return true if tidy will fix uri references
     */
    public boolean getFixUri()
    {
        return configuration.fixUri;
    }

    /**
     * <code>lower-literals</code>- folds known attribute values to lower case.
     * @param lowerLiterals true = folds known attribute values to lower case
     * @see Configuration#lowerLiterals
     */
    public void setLowerLiterals(boolean lowerLiterals)
    {
        configuration.lowerLiterals = lowerLiterals;
    }

    /**
     * <code>lower-literals</code>- folds known attribute values to lower case.
     * @return true if tidy will folds known attribute values to lower case
     */
    public boolean getLowerLiterals()
    {
        return configuration.lowerLiterals;
    }

    /**
     * <code>hide-comments</code>- hides all (real) comments in output.
     * @param hideComments true = hides all comments in output
     * @see Configuration#hideComments
     */
    public void setHideComments(boolean hideComments)
    {
        configuration.hideComments = hideComments;
    }

    /**
     * <code>hide-comments</code>- hides all (real) comments in output.
     * @return true if tidy will hide all comments in output
     */
    public boolean getHideComments()
    {
        return configuration.hideComments;
    }

    /**
     * <code>indent-cdata</code>- indent CDATA sections.
     * @param indentCdata true = indent CDATA sections
     * @see Configuration#indentCdata
     */
    public void setIndentCdata(boolean indentCdata)
    {
        configuration.indentCdata = indentCdata;
    }

    /**
     * <code>indent-cdata</code>- indent CDATA sections.
     * @return true if tidy will indent CDATA sections
     */
    public boolean getIndentCdata()
    {
        return configuration.indentCdata;
    }

    /**
     * <code>force-output</code>- output document even if errors were found.
     * @param forceOutput true = output document even if errors were found
     * @see Configuration#forceOutput
     */
    public void setForceOutput(boolean forceOutput)
    {
        configuration.forceOutput = forceOutput;
    }

    /**
     * <code>force-output</code>- output document even if errors were found.
     * @return true if tidy will output document even if errors were found
     */
    public boolean getForceOutput()
    {
        return configuration.forceOutput;
    }

    /**
     * <code>show-errors</code>- set the number of errors to put out.
     * @param showErrors number of errors to put out
     * @see Configuration#showErrors
     */
    public void setShowErrors(int showErrors)
    {
        configuration.showErrors = showErrors;
    }

    /**
     * <code>show-errors</code>- number of errors to put out.
     * @return the number of errors tidy will put out
     */
    public int getShowErrors()
    {
        return configuration.showErrors;
    }

    /**
     * <code>ascii-chars</code>- convert quotes and dashes to nearest ASCII char.
     * @param asciiChars true = convert quotes and dashes to nearest ASCII char
     * @see Configuration#asciiChars
     */
    public void setAsciiChars(boolean asciiChars)
    {
        configuration.asciiChars = asciiChars;
    }

    /**
     * <code>ascii-chars</code>- convert quotes and dashes to nearest ASCII char.
     * @return true if tidy will convert quotes and dashes to nearest ASCII char
     */
    public boolean getAsciiChars()
    {
        return configuration.asciiChars;
    }

    /**
     * <code>join-classes</code>- join multiple class attributes.
     * @param joinClasses true = join multiple class attributes
     * @see Configuration#joinClasses
     */
    public void setJoinClasses(boolean joinClasses)
    {
        configuration.joinClasses = joinClasses;
    }

    /**
     * <code>join-classes</code>- join multiple class attributes.
     * @return true if tidy will join multiple class attributes
     */
    public boolean getJoinClasses()
    {
        return configuration.joinClasses;
    }

    /**
     * <code>join-styles</code>- join multiple style attributes.
     * @param joinStyles true = join multiple style attributes
     * @see Configuration#joinStyles
     */
    public void setJoinStyles(boolean joinStyles)
    {
        configuration.joinStyles = joinStyles;
    }

    /**
     * <code>join-styles</code>- join multiple style attributes.
     * @return true if tidy will join multiple style attributes
     */
    public boolean getJoinStyles()
    {
        return configuration.joinStyles;
    }

    /**
     * <code>trim-empty-elements</code>- trim empty elements.
     * @param trim-empty-elements true = trim empty elements
     * @see Configuration#trimEmpty
     */
    public void setTrimEmptyElements(boolean trimEmpty)
    {
        configuration.trimEmpty = trimEmpty;
    }

    /**
     * <code>trim-empty-elements</code>- trim empty elements.
     * @return true if tidy will trim empty elements
     */
    public boolean getTrimEmptyElements()
    {
        return configuration.trimEmpty;
    }

    /**
     * <code>replace-color</code>- replace hex color attribute values with names.
     * @param replaceColor true = replace hex color attribute values with names
     * @see Configuration#replaceColor
     */
    public void setReplaceColor(boolean replaceColor)
    {
        configuration.replaceColor = replaceColor;
    }

    /**
     * <code>replace-color</code>- replace hex color attribute values with names.
     * @return true if tidy will replace hex color attribute values with names
     */
    public boolean getReplaceColor()
    {
        return configuration.replaceColor;
    }

    /**
     * <code>escape-cdata</code>- replace CDATA sections with escaped text.
     * @param escapeCdata true = replace CDATA sections with escaped text
     * @see Configuration#escapeCdata
     */
    public void setEscapeCdata(boolean escapeCdata)
    {
        configuration.escapeCdata = escapeCdata;
    }

    /**
     * <code>escape-cdata</code> -replace CDATA sections with escaped text.
     * @return true if tidy will replace CDATA sections with escaped text
     */
    public boolean getEscapeCdata()
    {
        return configuration.escapeCdata;
    }

    /**
     * <code>repeated-attributes</code>- keep first or last duplicate attribute.
     * @param repeatedAttributes <code>Configuration.KEEP_FIRST | Configuration.KEEP_LAST</code>
     * @see Configuration#duplicateAttrs
     */
    public void setRepeatedAttributes(int repeatedAttributes)
    {
        configuration.duplicateAttrs = repeatedAttributes;
    }

    /**
     * <code>repeated-attributes</code>- keep first or last duplicate attribute.
     * @return <code>Configuration.KEEP_FIRST | Configuration.KEEP_LAST</code>
     */
    public int getRepeatedAttributes()
    {
        return configuration.duplicateAttrs;
    }

    /**
     * <code>keep-time</code>- if true last modified time is preserved.
     * @param keepFileTimes <code>true</code> if tidy should preserved last modified time in input file.
     * @todo <strong>this is NOT supported at this time. </strong>
     * @see Configuration#keepFileTimes
     */
    public void setKeepFileTimes(boolean keepFileTimes)
    {
        configuration.keepFileTimes = keepFileTimes;
    }

    /**
     * <code>keep-time</code>- if true last modified time is preserved.
     * @return <code>true</code> if tidy will preserved last modified time in input file.
     * @todo <strong>this is NOT supported at this time. </strong>
     * @see Configuration#keepFileTimes
     */
    public boolean getKeepFileTimes()
    {
        return configuration.keepFileTimes;
    }

    /**
     * Sets the character encoding used both for input and for output.
     * @param charencoding encoding constant
     * @deprecated set input/output encoding using java encoding names
     */
    public void setCharEncoding(int charencoding)
    {
        String ceName = configuration.convertCharEncoding(charencoding);
        if (ceName != null)
        {
            configuration.setInCharEncodingName(ceName);
            configuration.setOutCharEncodingName(ceName);
        }
    }

    /**
     * Returns the configured character encoding.
     * @return character encoding constant
     * @deprecated from r8 tidy can use different encoding for input and output. This method will only return the
     * <strong>input </strong> character encoding.
     */
    public int getCharEncoding()
    {
        return configuration.getInCharEncoding();
    }

    /**
     * @param slidestyle N/A
     * @deprecated does nothing
     */
    public void setSlidestyle(String slidestyle)
    {
        configuration.slidestyle = slidestyle;
    }

    /**
     * @deprecated does nothing
     * @return <code>null</code>
     */
    public String getSlidestyle()
    {
        return null;
    }

    /**
     * <code>output-raw</code>- avoid mapping values > 127 to entities. This has the same effect of specifying a
     * "raw" encoding in the original version of tidy.
     * @param rawOut avoid mapping values > 127 to entities
     * @see Configuration#rawOut
     */
    public void setRawOut(boolean rawOut)
    {
        configuration.rawOut = rawOut;
    }

    /**
     * <code>output-raw</code>- avoid mapping values > 127 to entities.
     * @return <code>true</code> if tidy will not map values > 127 to entities
     * @see Configuration#rawOut
     */
    public boolean getRawOut()
    {
        return configuration.rawOut;
    }

    /**
     * <code>input-encoding</code> the character encoding used for input.
     * @param encoding a valid java encoding name
     */
    public void setInputEncoding(String encoding)
    {
        configuration.setInCharEncodingName(encoding);
    }

    /**
     * <code>input-encoding</code> the character encoding used for input.
     * @return the java name of the encoding currently used for input
     */
    public String getInputEncoding()
    {
        return configuration.getInCharEncodingName();
    }

    /**
     * <code>output-encoding</code> the character encoding used for output.
     * @param encoding a valid java encoding name
     */
    public void setOutputEncoding(String encoding)
    {
        configuration.setOutCharEncodingName(encoding);
    }

    /**
     * <code>output-encoding</code> the character encoding used for output.
     * @return the java name of the encoding currently used for output
     */
    public String getOutputEncoding()
    {
        return configuration.getOutCharEncodingName();
    }
    /**
     * <code>move-elements</code>- move style to head, th to thead etc.
     * @param move allow to move elements in page
     * @see Configuration#moveElements
     */
    public void setMoveElements(boolean move)
    {
        configuration.moveElements = move;
    }

    /**
     * <code>move-elements</code>- move style to head, th to thead etc.
     * @return <code>true</code> if tidy will move elements in page to proper position
     * @see Configuration#moveElements
     */
    public boolean getMoveElements()
    {
        return configuration.moveElements;
    }

}