# MatchMetrics.java

    /*
    ** Module   : MemberMetrics.java
    ** Abstract : container for metrics state related to the usage of a given class member
    **
    ** Copyright (c) 2021-2023, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- --------------------------------------Description---------------------------------------
    ** 001 GES 20210408 First version.
    ** 002 CA  20230928 Refactored the fuzzy method resolution to be used by runtime, too.
    */

    /*
    ** This program is free software: you can redistribute it and/or modify
    ** it under the terms of the GNU Affero General Public License as
    ** published by the Free Software Foundation, either version 3 of the
    ** License, or (at your option) any later version.
    **
    ** This program is distributed in the hope that it will be useful,
    ** but WITHOUT ANY WARRANTY; without even the implied warranty of
    ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    ** GNU Affero General Public License for more details.
    **
    ** You may find a copy of the GNU Affero GPL version 3 at the following
    ** location: https://www.gnu.org/licenses/agpl-3.0.en.html
    **
    ** Additional terms under GNU Affero GPL version 3 section 7:
    **
    **   Under Section 7 of the GNU Affero GPL version 3, the following additional
    **   terms apply to the works covered under the License.  These additional terms
    **   are non-permissive additional terms allowed under Section 7 of the GNU
    **   Affero GPL version 3 and may not be removed by you.
    **
    **   0. Attribution Requirement.
    **
    **     You must preserve all legal notices or author attributions in the covered
    **     work or Appropriate Legal Notices displayed by works containing the covered
    **     work.  You may not remove from the covered work any author or developer
    **     credit already included within the covered work.
    **
    **   1. No License To Use Trademarks.
    **
    **     This license does not grant any license or rights to use the trademarks
    **     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
    **     of Golden Code Development Corporation. You are not authorized to use the
    **     name Golden Code, FWD, or the names of any author or contributor, for
    **     publicity purposes without written authorization.
    **
    **   2. No Misrepresentation of Affiliation.
    **
    **     You may not represent yourself as Golden Code Development Corporation or FWD.
    **
    **     You may not represent yourself for publicity purposes as associated with
    **     Golden Code Development Corporation, FWD, or any author or contributor to
    **     the covered work, without written authorization.
    **
    **   3. No Misrepresentation of Source or Origin.
    **
    **     You may not represent the covered work as solely your work.  All modified
    **     versions of the covered work must be marked in a reasonable way to make it
    **     clear that the modified work is not originating from Golden Code Development
    **     Corporation or FWD.  All modified versions must contain the notices of
    **     attribution required in this license.
    */

    package com.goldencode.p2j.uast;

    /**
     * Stores metrics state related to the usage of a given class member.  This state cannot be stored in the
     * member data itself, since it is different at every usage location of the given member.
     */
    public class MatchMetrics
    implements Comparable<MatchMetrics>
    {
       /** The member to which the metrics refer. */
       MethodData data;

       /** Number of exact matches. */
       int exact = 0;

       /** Number of matches due to widening or narrowing conversion. */
       int cvt = 0;

       /** Number of exact extent matches (none to none, fixed to fixed, indeterminate to indeterminate). */
       int extExact = 0;

       /** Number of matches due to fixed extent to indeterminate conversion. */
       int extCvt = 0;

       /** Number of wildcard matches. */
       int wildcard = 0;

       /** Number of OO inheritance levels the caller type is from the callee type. */
       int[] ooLvl;

       /** Type overrides needed due to fuzzy matching. */
       String[] overrides;

       /**
        * Construct an instance which references the given member.
        *
        * @param    data
        *           The member being referenced.
        */
       public MatchMetrics(MethodData data)
       {
          this.data      = data;
          this.ooLvl     = new int[data.getSignature().length];
          this.overrides = new String[data.getSignature().length];
       }

       /**
        * Compares this object with the given other object to calculate a relative ordering between the two
        * instances.
        *
        * @param    other
        *           The other instance.  Must NOT be {@code null}.
        *
        * @return   -1, 0 or 1 if this instance is less than, equal to, or greater than the other object.
        *
        * @throws   NullPointerException
        *           If the parameter is {@code null}.
        */
       public int compareTo(MatchMetrics other)
       {
          int diffExact  = exact - other.exact;
          int diffCvt    = cvt - other.cvt;
          int diffExt    = extExact - other.extExact;
          int diffExtCvt = extCvt - other.extCvt;

          if (diffExact == 0 && diffCvt == 0 && diffExt == 0 && diffExtCvt == 0)
          {
             return compareInheritanceLevels(other);
          }
          else if (diffExact > 0 ||
                   (diffExact == 0 && diffCvt > 0) ||
                   (diffExact == 0 && diffCvt == 0 && diffExt > 0) ||
                   (diffExact == 0 && diffCvt == 0 && diffExt == 0 && diffExtCvt > 0))
          {
             return 1;
          }
          else
          {
             return -1;
          }
       }

       /**
        * Report if the two instances have equivalent state.
        *
        * @param    other
        *           The other instance to check against.
        *
        * @return   {@code true} if the other instance is non-null, is the same class and the state is equivalent
        *           as reported by {@link #compareTo}.  {@code false} otherwise.
        */
       public boolean equals(Object other)
       {
          if (other == null || !(other instanceof MatchMetrics))
          {
             return false;
          }

          return compareTo((MatchMetrics) other) == 0;
       }

       /**
        * Render the state of the instance in a text form.
        *
        * @return   The rendered instance.
        */
       public String toString()
       {
          return String.format("METRICS %d exact; %d cvt; %d extExact; %d extCvt; %d wildcard; " +
                               "%s ooLvl; %s overrides; \n        %s data",
                               exact,
                               cvt,
                               extExact,
                               extCvt,
                               wildcard,
                               ooLvl,
                               overrides,
                               data);
       }

       /**
        * Compares this object with the given other object to calculate if one of them matched based on OO
        * inheritance and is "closer" in its relationship.  The first OO level that is different will
        * determine the outcome unless no OO levels are different in which case the instances are equivalent.
        *
        * @param    other
        *           The other instance.  Must NOT be {@code null}.
        *
        * @return   -1, 0 or 1 if this instance is less than (farther than), equal to, or greater than (closer
        *           than) the other object.
        *
        * @throws   NullPointerException
        *           If the parameter is {@code null}.
        */
       private int compareInheritanceLevels(MatchMetrics other)
       {
          for (int i = 0; i < ooLvl.length; i++)
          {
             int diff = ooLvl[i] - other.ooLvl[i];

             if (diff > 0)
             {
                // farther away than other
                return -1;
             }
             else if (diff < 0)
             {
                // closer than other
                return 1;
             }
          }

          // no difference across the entire array
          return 0;
       }
    }