//*****************************************************************************
/*
** FILE:   xs_PatternElement.java
**
** (c) 1998 Steve Withall.
**
** HISTORY:
**    18Jun98  stevew  Created.
*/
package xs;

import xg.xg_Element;
import xg.xg_Node;

import eh.eh_Debug;

//*****************************************************************************
/** An XML element representing a pattern within an XSL rule.
*/
public class xs_PatternElement extends xg_Element
{
    /** The (largely derivative) information about this pattern which is used
     *  to determine precedence between patterns. */
    xs_PatternMatchLevel  MatchLevel          = new xs_PatternMatchLevel();

    /** This pattern's number in the form of a string. Each pattern is given a
     *  sequential number within the rule it belongs to. This number is tagged
     *  on to the sequential number allocated to the rule, to yield a string of
     *  the form "r.p". This numbering is performed during XML parsing of the
     *  This number string is used purely to assist identification for a human
     *  user, and plays no part whatsoever in the XSL processing itself. */
    protected String      PatternNumberString = null;

    /** The name of the attribute used to identify the ID of this pattern. */
    public final static String IdAttName    = "id";

    /** The name of the attribute used to identify the class of this pattern. */
    public final static String ClassAttName = "class";

    //*****************************************************************************
    /** Construct a pattern element with no type and no name.
     */
    public xs_PatternElement()
    {
    }

    //*****************************************************************************
    /** Construct a pattern element with a name.
     *
     *  @param  InputNodeName  The name of the element
     */
    public xs_PatternElement(String InputNodeName)
    {
        super(InputNodeName);
    }

    //*****************************************************************************
    /** See if this pattern matches the InputSourceElement, and is a better match
     *  than the InputBestPattern (which may be null). If so, return true;
     *  otherwise return false.
     *
     *  @param      InputBestPattern    The best pattern found in previous rules
     *                                   (or null if no match has so far been found)
     *  @param      InputSourceElement  The source element to match
     *  @return                         true if this is now the best match; false
     *                                   if not
     *  @exception  xs_StyleException   An error occurred processing the actions
     */
    public boolean isBestMatch(xs_PatternElement  InputBestPattern,
                               xg_Element         InputSourceElement)
                                                throws xs_StyleException
    {
        eh_Debug.add(9, "xs_PatternElement.isBestMatch: Is pattern #" + PatternNumberString
                               + " the best for " + InputSourceElement + "?");
        boolean  BestMatchFlag = false;

        // Before bothering to see if this pattern matches the InputSourceElement,
        // check if this pattern is better than the current best matching pattern.
        if (    (InputBestPattern == null)
             || (compareMatchLevelTo(InputBestPattern) > 0) )
            BestMatchFlag = isMatch(InputSourceElement);

        if (BestMatchFlag)
            eh_Debug.add(8, "xs_PatternElement.matchPattern: Pattern #" + PatternNumberString
                               + " is (so far) the best for " + InputSourceElement);
        else
            eh_Debug.add(8, "xs_PatternElement.matchPattern: Pattern #" + PatternNumberString
                               + " is NOT the best for " + InputSourceElement);
        return BestMatchFlag;
    }

    //*****************************************************************************
    /** See if this pattern matches the InputSourceElement. If so, return true.
     *  We expect this to be overridden in derived classes - because this version
     *  always returns false.
     *
     *  @param      InputSourceElement  The source node to match
     *  @return                         The best pattern after checking this one: it
     *                                   will either be InputBestPattern or this
     *  @exception  xs_StyleException   An error occurred
     */
    public boolean isMatch(xg_Element  InputSourceElement) throws xs_StyleException
    {
        eh_Debug.add(8, "xs_PatternElement.isMatch: Pattern #" + PatternNumberString
                               + " is not a match for " + InputSourceElement);
        return false;
    }

    //*****************************************************************************
    /** Compare the match level of this pattern against that of the InputPatternElement.
     *
     *  @param  InputPatternElement  The pattern to compare against
     *  @return                      0 if this pattern's match level is equal to the
     *                                InputPatternElement's match level; less than 0
     *                                if this pattern's match level is less than the
     *                                InputPatternElement; greater than 0 if this
     *                                pattern's match level is greater than the
     *                                InputMatchLevel.
     */
    public int compareMatchLevelTo(xs_PatternElement  InputPatternElement)
    {
        return (MatchLevel.compareTo(InputPatternElement.MatchLevel) );
    }

    //*****************************************************************************
    /** Calculate this pattern's match level, which includes figuring out the
     *  value of each of the match level's constituents.
     */
    public void calcMatchLevel()
    {
    }

    //*****************************************************************************
    /** Add to this pattern's match level the match level of each of our children.
     *  We assume each child's match level has already correctly calculated its own
     *  match level (including taking into account its own children).
     */
    public void addMatchLevelsOfChildren()
    {
        xg_Node            ChildNode    = null;
        xs_PatternElement  ChildPattern = null;
        for (int ChildIndex = 0; ChildIndex < getChildCount(); ChildIndex++)
        {
            ChildNode = (xg_Node)getChildAt(ChildIndex);
            if (ChildNode instanceof xs_PatternElement)
            {
                ChildPattern = (xs_PatternElement)ChildNode;
                MatchLevel.increment(ChildPattern.getMatchLevel() );
            }
        }
    }

    //*****************************************************************************
    /** Set this pattern's identification number string (of the form "r.p", where
     *  r is the InputRuleNumber and p is the InputPatternNumber).
     *
     *  @param  InputRuleNumber     The sequential number given to the rule to which
     *                               this pattern belongs
     *  @param  InputPatternNumber  The sequential number given to this pattern
     *                               within its rule
     */
    public void setRuleNumber(int  InputRuleNumber,
                              int  InputPatternNumber)
    {
        PatternNumberString = new String(InputRuleNumber + "." + InputPatternNumber);
    }

    //*****************************************************************************
    /** Get this pattern's match level: the values which are used in determining
     *  which pattern to use in a given circumstance.
     *
     *  @return  This pattern's match level
     */
    public xs_PatternMatchLevel getMatchLevel()
    {
        return MatchLevel;
    }

    //*****************************************************************************
    /** Get this patterns's sequential number (which must be set manually via an
     *  external call to setPatternNumber() ).
     *
     *  @return  A string representation of the identification number given to this
     *            pattern
     */
    public String getPatternNumberString()
    {
        return PatternNumberString;
    }

    //*****************************************************************************
    /** Return a string representation of the element (intended for use as debug
     *  output).
     *
     *  @return  String representing the node name and its type.
     */
    public String toString()
    {
        return("XSL '" + NodeName + "' pattern (#" + PatternNumberString + ")");
    }
}

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