//*****************************************************************************
/*
** FILE:   xm_SimpleNodeFormatter.java
**
** (c) 1998 Steve Withall.
**
** HISTORY:
**    24May98  stevew  Created.
**    05Jul98  stevew  Moved from package xg to xm.
*/
package xm;

import xg.xg_Element;
import xg.xg_Node;

import xa.xa_NodeTypeChoiceList;

import java.util.Vector;

//*****************************************************************************
/** <p>To reformat an xg_Node (and its children) in a simple way, according to
 *  the following rules:</p>
 *
 *  <LI>Each node is to be preceded by a fixed piece of whitespace (by default
 *      just a carriage-return) and then another piece for each level deep in
 *      the node hierarchy (by default a single tab). Note that this is NOT done
 *      for the top-level node: it is given no preceding whitespace.
 *
 *  <LI>If the node is an element, its end tag is given the same preceding
 *      whitespace as the node itself.
 *
 *  <LI>If the node is an element, its attributes are split over multiple lines
 *      so as to prevent excessively long lines. (If one attribute name/value is
 *      excessively long, nothing is done about it.) [This feature is not yet
 *      supported.]
 */
public class xm_SimpleNodeFormatter extends xm_NodeFormatter
{
    /** The piece of whitespace which always precedes a node (except the top-level
     *  node). */
    protected  String    FixedPrecedingWhitespace    = "\n";

    /** The piece of whitespace to precede a node for each level deep the node is
     *  in its hierarchy. This whitespace follows the FixedPrecedingWhitespace. */
    protected  String    PerLevelPrecedingWhitespace = "\t";

    /** The source line length we would rather not exceed. */
    protected  int       DesiredMaxLineLength        = 80;  //TBD Not yet used

    //*****************************************************************************
    /** Format the given node, and its children.
     *
     *  @param  InputNode          The node to reformat
     *  @param  InputOpeningDepth  The depth of the node in the hierarchy. This
     *                              allows a node to be reformatted to fit in with
     *                              its surroundings (its parent and siblings). For
     *                              a top-level node, this should be 0.
     */
    public void format(xg_Node  InputNode, int  InputOpeningDepth)
    {
        // Set this node's preceding whitespace.
        if (InputOpeningDepth > 0)
        {
            StringBuffer  WhitespaceBuffer = new StringBuffer(FixedPrecedingWhitespace);
            for (int  DepthLevel = 0; DepthLevel < InputOpeningDepth; DepthLevel++)
            {
                WhitespaceBuffer.append(PerLevelPrecedingWhitespace);
            }
            InputNode.setPrecedingWhitespace(WhitespaceBuffer.toString() );

            if (InputNode instanceof xg_Element)
            {
                // This is an element. Indent its end tag the same as its start
                // - iff it contains child elements of its own. (The rationale is
                // that if it merely contains other content, it will fit neatly on
                // one line and needs no extra whitespace before its end tag.)
                Vector  ChildElements = InputNode.getChildrenOfType(xa_NodeTypeChoiceList.ELEMENT_TYPE);
                if (ChildElements.size() > 0)
                    ((xg_Element)InputNode).setTrailingWhitespace(WhitespaceBuffer.toString() );
            }
        }
        else
        {
            InputNode.setPrecedingWhitespace(null);
            if (InputNode instanceof xg_Element)
                ((xg_Element)InputNode).setTrailingWhitespace(null);
        }

        // Format each of this node's children.
        formatChildren(InputNode, InputOpeningDepth);
    }

    //*****************************************************************************
    /** Set the piece of whitespace which always precedes a node.
     *
     *  @param  InputFixedPrecedingWhitespace   The piece of whitespace to always
     *                                           precede a node
     */
    public void setFixedPrecedingWhitespace(String  InputFixedPrecedingWhitespace)
    {
        FixedPrecedingWhitespace = InputFixedPrecedingWhitespace;
    }

    //*****************************************************************************
    /** Set the piece of whitespace to precede a node for each level deep the node
     *  is in its hierarchy.
     *
     *  @param  InputPerLevelPrecedingWhitespace  The piece of whitespace to precede
     *                                             a node for each level deep
     */
    public void setPerLevelPrecedingWhitespace(String  InputPerLevelPrecedingWhitespace)
    {
        PerLevelPrecedingWhitespace = InputPerLevelPrecedingWhitespace;
    }

    //*****************************************************************************
    /** Set the source line length we would rather not exceed.
     *
     *  @param  InputDesiredMaxLineLength  The desired maximum source line length
     */
    public void setDesiredMaxLineLength(int  InputDesiredMaxLineLength)
    {
        DesiredMaxLineLength = InputDesiredMaxLineLength;
    }

    //*****************************************************************************
    /** Get the piece of whitespace which always precedes a node.
     *
     *  @return  InputFixedPrecedingWhitespace   The piece of whitespace to always
     *                                            precede a node
     */
    public String getFixedPrecedingWhitespace()
    {
        return FixedPrecedingWhitespace;
    }

    //*****************************************************************************
    /** Get the piece of whitespace to precede a node for each level deep the node
     *  is in its hierarchy.
     *
     *  @return  InputPerLevelPrecedingWhitespace  The piece of whitespace to precede
     *                                               a node for each level deep
     */
    public String getPerLevelPrecedingWhitespace()
    {
        return PerLevelPrecedingWhitespace;
    }

    //*****************************************************************************
    /** Get the source line length we would rather not exceed.
     *
     *  @return  InputDesiredMaxLineLength  The desired maximum source line length
     */
    public int getDesiredMaxLineLength()
    {
        return DesiredMaxLineLength;
    }
}

//*****************************************************************************
