# CountAccumulator.java

    /*
    ** Module   : CountAccumulator.java
    ** Abstract : Accumulator implementation which counts loop iterations
    **
    ** Copyright (c) 2004-2022, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- --JPRM-- -----------------------------------Description-----------------------------------
    ** 001 ECF 20051227   @23780 Created initial version. Counts iterations of
    **                           a loop. Statistics are maintained for both
    **                           the full count and for the current break
    **                           group.
    ** 002 ECF 20060104   @23815 Consolidated constructors. Separate ctors
    **                           which accepted a FieldReference and an
    **                           Expression were replaced with a single ctor
    **                           which accepts a Resolvable data source.
    ** 003 ECF 20060111   @23863 Added constructors for primitive types. These
    **                           are needed to support accumulation of literal
    **                           values.
    ** 004 ECF 20060118   @23984 Added support for break groups. Made mods to
    **                           support new base class architecture.
    ** 005 ECF 20060503   @25950 Added support for accumulation using external
    **                           data sources. Added features required by code
    **                           converted from aggregators in display
    **                           statements.
    ** 006 ECF 20060615   @27354 Initialize and reset data sources to unknown
    **                           value. This is consistent with Progress.
    ** 007 GES 20060830   @28983 Removed H006 and moved back to a zero based
    **                           approach. The count variable can never be
    **                           unknown and is not accessed directly so there
    **                           is no reason to use a wrapper. By default, if
    **                           one has a CONDITIONAL accumulate stmt an
    **                           accumulator is initialized to zero so that
    **                           the accum function will return zero and not
    **                           unknown even if the condition never occurs
    **                           (so that the accumulate stmt is never called
    **                           before the accum function is used to query
    **                           the accumulated result). There must have been
    **                           some case which H006 was designed to fix but
    **                           at this time that case cannot be found AND
    **                           it is certainly not correct for the default
    **                           result. In the case that an accumulate does
    **                           occur, the accumulated datum is ignored and
    **                           the outcome can never be unknown! So at this
    **                           time, the unknown value processing seems to
    **                           be OK.
    ** 008 ECF 20070627   @34322 Ensure safe result is returned if no data has
    **                           been accumulated. Added safety ctor and
    **                           removed unused ctor variants. Reworked inner
    **                           Data class. New implementation ensures the
    **                           proper default result (either unknown value or
    **                           0) is returned, depending upon how the
    **                           accumulator has been initialized and used.
    ** 009 CA  20080213   @37132 Added Data.deepCopy and Data.assign method
    **                           implementation. Added new constructor -
    **                           CountAccumulator(Resolvable, boolean) used
    **                           by Accumulator.deepCopy() to instantiate a new
    **                           accumulator of this type without registering
    **                           to AccumulatorManager or TransactionManager.
    ** 010 CA  20080326   @37833 On instantiation, the accumulator is set to
    **                           unknown; the accumulator will be reset only
    **                           when a block which uses it is entered.
    ** 011 ECF 20080702   @39027 Refactored constructors. This was done to
    **                           support conversion changes made to fix a
    **                           memory leak in the framework.
    ** 012 GES 20080917   @39851 Minor class name change. Also changed the
    **                           default scope level to NEXT instead of
    **                           CURRENT.
    ** 013 CA  20160721          Cleaned up the c'tors - all accumulators register in the next scope,
    **                           as they are defined and created as instance fields.
    ** 014 CA  20220514          Accumulators can be explicitly assigned via their associated variable - added
    **                           stubbed setters.
    */
    /*
    ** 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.util;

    /**
     * A simple accumulator implementation which counts the total number of loop
     * iterations performed, as well as the number of loop iterations performed
     * within the current break group. Results are retrieved using one of the
     * <code>getResult</code> method variants.
     */
    public final class CountAccumulator
    extends Accumulator
    {
       /** Relative weight of this accumulator type for sorting purposes */
       static final int WEIGHT = TotalAccumulator.WEIGHT + 1;

       /**
        * Constructor which stores no data source.  This instance expects to be
        * fed data from an external source via its <code>accumulate</code>
        * method.  The accumulator is registered with the AccumulatorManager and
        * the TransactionManager in the next scope.
        */
       public CountAccumulator()
       {
          super();
       }

       /**
        * Constructor which stores a <code>Resolvable</code> as the accumulator's
        * data source.  When an iteration occurs, the accumulator gathers its data
        * by resolving the current value of the data source. The accumulator is
        * registered with the AccumulatorManager and the TransactionManager, in the next scope.
        *
        * @param   dataSource
        *          Data source from which data is collected.
        * @param   register
        *          This flag will be <code>false</code> only if a copy object is instantiated.
        *          Because we use the copy only for roll-back purposes, we do not need to add it to
        *          the TransactionManager or AccumulatorManager.
        */
       public CountAccumulator(Resolvable dataSource, boolean register)
       {
          super(dataSource, register);
       }

       /**
        * Get the full result of all accumulations so far for this accumulator,
        * across all break groups.
        *
        * @return  Current full result.
        */
       public BaseDataType getFullResult()
       {
          return getResult(null);
       }

       /**
        * Get the current subgroup result for the first registered break group in
        * this accumulator.  Subsequent break groups, if any, are ignored.
        *
        * @return  Subgroup result for first registered break group, or
        *          <code>null</code> if no subgroups are being tracked by this
        *          accumulator.
        */
       public BaseDataType getSubResult()
       {
          Resolvable key = getFirstBreakGroupKey();
          if (key == null)
          {
             return null;
          }

          return getResult(key);
       }

       /**
        * Get the label associated with this accumulator type, for use in the UI.
        *
        * @return  Label associated with this accumulator type.
        */
       public String getLabel()
       {
          return "COUNT";
       }

       /**
        * Get the relative weight associated with this accumulator type, for use
        * in sorting accumulator instances of different types according to their
        * natural display order.
        *
        * @return  An integer which represents this accumulator's sorting weight
        *          relative to other accumulator types.
        */
       public int getWeight()
       {
          return WEIGHT;
       }

       /**
        * Assign this accumulator's value.
        *
        * @param    v
        *           The new value.
        */
       public void setResult(long v)
       {
          UnimplementedFeature.missing("Accumulator assignment is not supported: COUNT");
       }

       /**
        * Assign this accumulator's value.
        *
        * @param    v
        *           The new value.
        */
       public void setResult(NumberType v)
       {
          UnimplementedFeature.missing("Accumulator assignment is not supported: COUNT");
       }

       /**
        * Get the full count of iterations performed for the enclosing loop.
        *
        * @return  Total number of iterations performed.
        */
       public integer getResult()
       {
          return getResult(null);
       }

       /**
        * Get the count of iterations performed for the enclosing loop, but only
        * since the current break group counter was last reset.
        *
        * @param   breakGroupKey
        *          Key identifying the break group for which the data is desired.
        *
        * @return  Iteration count since the specified break group counter was
        *          last reset.
        */
       public integer getResult(Resolvable breakGroupKey)
       {
          return (integer) calculate(breakGroupKey);
       }

       /**
        * Create a data bundle which understands how to calculate an iteration
        * count.
        *
        * @return  An instance of {@link CountAccumulator.Data}.
        */
       protected DataBundle createDataBundle()
       {
          return (new Data());
       }

       /**
        * A <code>DataBundle</code> implementation which keeps a running iteration
        * count, and returns it upon request.
        */
       private class Data
       implements DataBundle
       {
          /** Iteration counter. */
          private integer count = null;

          /**
           * Construct an instance of this class, setting the starting total to
           * either unknown value or 0, depending upon whether the enclosing
           * accumulator is initialized for use.
           */
          private Data()
          {
             count = new integer();
          }

          /**
           * Reset (to zero) the counter variable, in preparation for beginning
           * a new break group.
           */
          public void reset()
          {
             count = new integer(0);
          }

          /**
           * Increment both the iteration count.
           *
           * @param    datum
           *           Datum to be accumulated;  ignored in this case, since it is
           *           only the fact that the loop iterated which is important.
           */
          public void accumulate(BaseDataType datum)
          {
             count.increment();
          }

          /**
           * Return the current iteration count.
           *
           * @return   Iteration count (zero if no {@link #accumulate} ever
           *           occurred).
           */
          public BaseDataType calculate()
          {
             return count.duplicate();
          }

          /**
           * This is a form of a copy constructor that makes a deep copy of the
           * current instance and returns this copy as a new instance of the same
           * class.
           *
           * @return   An instance of the same class whose data is identical to
           *           that of this instance.
           */
          public Undoable deepCopy()
          {
             Data copy = new Data();

             copy.count = (integer) this.count.deepCopy();

             return copy;
          }

          /**
           * Sets the state of this instance based on the state of the passed instance.
           *
           * @param    value
           *           The instance from which to copy state.
           */
          public void assign(Undoable value)
          {
             Data copy = (Data) value;

             this.count.assign(copy.count);
          }
       }
    }