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

import eh.eh_Debug;

//*****************************************************************************
/** <p>A repository for the information about an XSL pattern which is used to
 *  determine precedence of patterns.</p>
 *
 *  <p>The values herein are calculated once as the XSL stylesheet is parsed, to
 *  enable efficient subsequent processing. To improve efficiency still further,
 *  a single overall match level is also calculated, taking into account the
 *  precendence of the constituent values. This only works if none of the
 *  constituent values exceeds 9; if any value exceeds 9, the individual
 *  values are compared.</p>
 *
 *  <p>Note that this class has no provision for resetting values: it assumes
 *  values will be set once at XSL parse time, and therefore only accommodates
 *  incrementing (increasing) values but not decrementing them.</p>
 */
public class xs_PatternMatchLevel
{
    /** The overall match level, based on a weighted calculation on the
     *  constituent values. */
    protected long    OverallMatchLevel          = 0;

    /** Is the OverallMatchLevel valid for use in a simple comparison of
     *  two match levels? (It will be valid if all the constituent values are
     *  less than 9.) If false, a match is calculated laboriously by comparing
     *  each constituent value in turn. */
    protected boolean OverallMatchLevelValidFlag = true;

    /** 1 - The importance of the rule to which this match level belongs. */
    protected int     RuleImportanceLevel       = 0;

    /** 2 - The number of 'id' attributes in the pattern. */
    protected int     IdCount                   = 0;

    /** 3 - The number of 'class' attributes in the pattern. */
    protected int     ClassCount                = 0;

    /** 4 - The number of element or target-element elements that have a type
     *  attribute. */
    protected int     TypeElementCount          = 0;

    /** 5 - The number of wildcards in the pattern. ('A wildcard is an any element, an
     *  element element without a type attribute, or a target-element element without
     *  a type attribute.') */
    protected int     WildcardCount             = 0;

    /** 6 - The priority of the rule to which this match level belongs. */
    protected int     RulePriorityLevel         = 0;

    /** 7 - The number of number of only qualifiers in the pattern. */
    protected int     OnlyCount                 = 0;

    /** 8 - The number of position qualifiers in the pattern. */
    protected int     PositionCount             = 0;

    /** 9 - The number of attribute specifications in the pattern. */
    protected int     AttSpecCount              = 0;

    //*****************************************************************************
    /** Compare this pattern match level against the InputPatternMatchLevel. If the
     *  overall match level of both are valid, then a simple comparison of them are
     *  made; otherwise the individual constituents are compared one by one.
     *
     *  @param  InputMatchLevel  The pattern match level to compare this against
     *  @return                  0 if this pattern match level is equal to the
     *                            InputMatchLevel; less than 0 if this pattern match
     *                            level is less than the InputMatchLevel; greater
     *                            than 0 if this pattern match level is greater than
     *                            the InputMatchLevel.
     */
    public int compareTo(xs_PatternMatchLevel  InputMatchLevel)
    {
        int CompResult = 0;
        if (    OverallMatchLevelValidFlag
             && InputMatchLevel.OverallMatchLevelValidFlag)
            // Just compare the calculated overall match levels.
            CompResult = compareTo(OverallMatchLevel,
                                   InputMatchLevel.OverallMatchLevel);
        else
            // Perform laborious comparison.
            CompResult = laboriousCompareTo(InputMatchLevel);

        eh_Debug.add(8, "xs_PatternMatchLevel.compareTo: Comparison result = "
                                                                     + CompResult);  //TEMP
        return CompResult;
    }

    //*****************************************************************************
    /** Perform a laborious comparison between this pattern match level and the
     *  That is, compare the individual constituents one by one.
     *
     *  @param  InputMatchLevel  The pattern match level to compare this against
     *  @return                  0 if this pattern match level is equal to the
     *                            InputMatchLevel; less than 0 if this pattern match
     *                            level is less than the InputMatchLevel; greater
     *                            than 0 if this pattern match level is greater than
     *                            the InputMatchLevel.
     */
    public int laboriousCompareTo(xs_PatternMatchLevel  InputMatchLevel)
    {
        int CompResult = compareTo(RuleImportanceLevel,
                                   InputMatchLevel.RuleImportanceLevel);
        if (CompResult == 0)
        {
            CompResult = compareTo(IdCount,
                                   InputMatchLevel.IdCount);
            if (CompResult == 0)
            {
                CompResult = compareTo(ClassCount,
                                       InputMatchLevel.ClassCount);
                if (CompResult == 0)
                {
                    CompResult = compareTo(TypeElementCount,
                                           InputMatchLevel.TypeElementCount);
                    if (CompResult == 0)
                    {
                        // Note that the wildcard comparison is 'the other way round',
                        // because the pattern with *fewer* wildcards takes precedence.
                        CompResult = compareTo(InputMatchLevel.WildcardCount,
                                               WildcardCount);
                        if (CompResult == 0)
                        {
                            CompResult = compareTo(RulePriorityLevel,
                                                   InputMatchLevel.RulePriorityLevel);
                            if (CompResult == 0)
                            {
                                CompResult = compareTo(OnlyCount,
                                                       InputMatchLevel.OnlyCount);
                                if (CompResult == 0)
                                {
                                    CompResult = compareTo(PositionCount,
                                                           InputMatchLevel.PositionCount);
                                    if (CompResult == 0)
                                        CompResult = compareTo(AttSpecCount,
                                                               InputMatchLevel.AttSpecCount);
                                }
                            }
                        }
                    }
                }
            }
        }

        return CompResult;
    }

    //*****************************************************************************
    /** Compare two integers.
     *
     *  @param  InputValue1  The first comarison value
     *  @param  InputValue2  The second comarison value
     *  @return              0 if InputValue1 is equal to InputValue2;
     *                       less than 0 if InputValue1 is less than InputValue2
     *                       greater than 0 if InputValue1 is greater than InputValue2
     */
    public int compareTo(int  InputValue1, int  InputValue2)
    {
	    return (InputValue1 == InputValue2 ? 0 : (InputValue1 < InputValue2 ? -1 : 1));
    }

    //*****************************************************************************
    /** Compare two longs.
     *
     *  @param  InputValue1  The first comarison value
     *  @param  InputValue2  The second comarison value
     *  @return              0 if InputValue1 is equal to InputValue2;
     *                        less than 0 if InputValue1 is less than InputValue2
     *                        greater than 0 if InputValue1 is greater than InputValue2
     */
    public int compareTo(long  InputValue1, long  InputValue2)
    {
	    return (InputValue1 == InputValue2 ? 0 : (InputValue1 < InputValue2 ? -1 : 1));
    }

    //*****************************************************************************
    /** Add the constituents of the InputMatchLevel to this match level.
     *
     *  @param InputMatchLevel  The match level whose constituents are to be added
     */
    public void increment(xs_PatternMatchLevel  InputMatchLevel)
    {
//        setRuleImportanceLevel(InputMatchLevel.RuleImportanceLevel);
        incrementIdCount(InputMatchLevel.IdCount);
        incrementClassCount(InputMatchLevel.ClassCount);
        incrementTypeElementCount(InputMatchLevel.TypeElementCount);
        incrementWildcardCount(InputMatchLevel.WildcardCount);
//        setRulePriorityLevel(InputMatchLevel.RulePriorityLevel);
        incrementOnlyCount(InputMatchLevel.OnlyCount);
        incrementPositionCount(InputMatchLevel.PositionCount);
        incrementAttSpecCount(InputMatchLevel.AttSpecCount);
    }

    //*****************************************************************************
    /** Set the importance of the rule to which this match level belongs. (1)
     *
     *  @param InputRuleImportanceLevel  The importance of the rule to which this
     *                                    match level belongs
     */
    public void setRuleImportanceLevel(int  InputRuleImportanceLevel)
    {
        RuleImportanceLevel = InputRuleImportanceLevel;
        synchronize(RuleImportanceLevel);
    }

    //*****************************************************************************
    /** Increment the number of 'id' attributes in the pattern. (2)
     *
     *  @param InputIdCount  The number to be added to the number 'id' attributes in
     *                        the pattern
     */
    public void incrementIdCount(int  InputIdCount)
    {
        IdCount += InputIdCount;
        synchronize(IdCount);
    }

    //*****************************************************************************
    /** Increment the number of 'class' attributes in the pattern. (3)
     *
     *  @param InputClassCount  The number to be added to the number of 'class'
     *                           attributes in the pattern
     */
    public void incrementClassCount(int  InputClassCount)
    {
        ClassCount += InputClassCount;
        synchronize(ClassCount);
    }

    //*****************************************************************************
    /** Increment the number of element or target-element elements that have a type
     *  attribute. (4)
     *
     *  @param InputTypeElementCount  The number to be added to the number of element
     *                                 or target-element elements that have a type
     *                                 attribute
     */
    public void incrementTypeElementCount(int  InputTypeElementCount)
    {
        TypeElementCount += InputTypeElementCount;
        synchronize(TypeElementCount);
    }

    //*****************************************************************************
    /** Increment the number of wildcards in the pattern. (5)
     *
     *  @param InputWildcardCount  The number to be added to the number of wildcards
     *                              in the pattern
     */
    public void incrementWildcardCount(int  InputWildcardCount)
    {
        WildcardCount += InputWildcardCount;
        synchronize(WildcardCount);
    }

    //*****************************************************************************
    /** Set the priority of the rule to which this match level belongs. (6)
     *
     *  @param  The priority of the rule to which this match level belongs
     */
    public void setRulePriorityLevel(int  InputRulePriorityLevel)
    {
        RulePriorityLevel = InputRulePriorityLevel;
        synchronize(RulePriorityLevel);
    }

    //*****************************************************************************
    /** Increment the number of only qualifiers in the pattern. (7)
     *
     *  @param InputOnlyCount  The number to be added to the number of only
     *                          qualifiers in the pattern
     */
    public void incrementOnlyCount(int  InputOnlyCount)
    {
        OnlyCount += InputOnlyCount;
        synchronize(OnlyCount);
    }

    //*****************************************************************************
    /** Increment the number of position qualifiers in the pattern. (8)
     *
     *  @param InputPositionCount  The number to be added to the number of position
     *                              qualifiers in the pattern
     */
    public void incrementPositionCount(int  InputPositionCount)
    {
        PositionCount += InputPositionCount;
        synchronize(PositionCount);
    }

    //*****************************************************************************
    /** Increment the number of attribute specifications in the pattern. (9)
     *
     *  @param InputAttSpecCount  The number to be added to the number of attribute
     *                             specifications in the pattern
     */
    public void incrementAttSpecCount(int  InputAttSpecCount)
    {
        AttSpecCount += InputAttSpecCount;
        synchronize(AttSpecCount);
    }

    //*****************************************************************************
    /** Recalculate the OverallMatchLevel and the OverallMatchLevelValidFlag after
     *  setting or incrementing one of the constituents, whose new value is
     *  InputConstituentValue.
     *
     *  @param InputConstituentValue  The new value of a constituent which has just
     *                                 changed
     */
    protected void synchronize(int  InputConstituentValue)
    {
        if (InputConstituentValue > 9)
        {
            OverallMatchLevel          = 0;
            OverallMatchLevelValidFlag = false;
        }
        else
            calcOverallMatchLevel();
    }

    //*****************************************************************************
    /** Calculate the overall match level, based on the constituent values.
     *
     *  @return  The overall match level
     */
    public long calcOverallMatchLevel()
    {
        OverallMatchLevel = RuleImportanceLevel * 10;
        OverallMatchLevel = (OverallMatchLevel + IdCount) * 10;
        OverallMatchLevel = (OverallMatchLevel + ClassCount) * 10;
        OverallMatchLevel = (OverallMatchLevel + TypeElementCount) * 10;
        OverallMatchLevel = (OverallMatchLevel + (9 - WildcardCount)) * 10;
        OverallMatchLevel = (OverallMatchLevel + RulePriorityLevel) * 10;
        OverallMatchLevel = (OverallMatchLevel + OnlyCount) * 10;
        OverallMatchLevel = (OverallMatchLevel + PositionCount) * 10;
        OverallMatchLevel += AttSpecCount;
        return OverallMatchLevel;
    }

    //*****************************************************************************
    /** Get the overall match level, based on the constituent values.
     *
     *  @return  The overall match level
     */
    public long getOverallMatchLevel()
    {
        return OverallMatchLevel;
    }

    //*****************************************************************************
    /** Get the flag which indicates whether the overall match level is valid for
     *  comparison purposes.
     *
     *  @return  The overall match level valid flag
     */
    public boolean isOverallMatchLevelValid()
    {
        return OverallMatchLevelValidFlag;
    }

    //*****************************************************************************
    /** Get the importance of the rule to which this match level belongs. (1)
     *
     *  @return  The importance of the rule to which this match level belongs
     */
    public int getRuleImportanceLevel()
    {
        return RuleImportanceLevel;
    }

    //*****************************************************************************
    /** Get the number of 'id' attributes in the pattern. (2)
     *
     *  @return  The number of 'id' attributes in the pattern
     */
    public int getIdCount()
    {
        return IdCount;
    }

    //*****************************************************************************
    /** Get the number of 'class' attributes in the pattern. (3)
     *
     *  @return  The number of 'class' attributes in the pattern
     */
    public int getClassCount()
    {
        return ClassCount;
    }

    //*****************************************************************************
    /** Get the number of element or target-element elements that have a type
     *  attribute. (4)
     *
     *  @return  The number of element or target-element elements that have a type
     *            attribute
     */
    public int getTypeElementCount()
    {
        return TypeElementCount;
    }

    //*****************************************************************************
    /** Get the number of wildcards in the pattern. (5)
     *
     *  @return  The number of wildcards in the pattern
     */
    public int getWildcardCount()
    {
        return WildcardCount;
    }

    //*****************************************************************************
    /** Get the priority of the rule to which this match level belongs. (6)
     *
     *  @return  The priority of the rule to which this match level belongs
     */
    public int getRulePriorityLevel()
    {
        return RulePriorityLevel;
    }

    //*****************************************************************************
    /** Get the number of only qualifiers in the pattern. (7)
     *
     *  @return  The number of only qualifiers in the pattern
     */
    public int getOnlyCount()
    {
        return OnlyCount;
    }

    //*****************************************************************************
    /** Get the number of position qualifiers in the pattern. (8)
     *
     *  @return  The number of position qualifiers in the pattern
     */
    public int getPositionCount()
    {
        return PositionCount;
    }

    //*****************************************************************************
    /** Get the number of attribute specifications in the pattern. (9)
     *
     *  @return  The number of attribute specifications in the pattern
     */
    public int getAttSpecCount()
    {
        return AttSpecCount;
    }
}

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