# ExtentTracker.java

    /*
    ** Module   : ExtentTracker.java
    ** Abstract : Helper object to track extents during temp-table data import.
    **
    ** Copyright (c) 2017-2024, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- ---------------------------------------Description---------------------------------------
    ** 001 ECF 20190123 Extracted from XmlImport.
    ** 002 OM  20201120 Small fix in constructor.
    ** 003 CA  20210510 Fixed JSON and XML serialization when XML-NODE-NAME/SERIALIZE-NAME field options are set.
    ** 004 CA  20240320 Avoid BDTs within internal FWD runtime.  Replaced iterators with Java 'for', where it
    **                  applies.
    */

    /*
    ** 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.persist.serial;

    import java.util.*;

    /**
     * Helper object which tracks current and maximum index values for extent fields. This is
     * used to get the next index value needed for a setter method invocation when reading and
     * setting elements into an extent field in the current DMO. A range check is performed to
     * ensure too many array elements are not set.
     */
    class ExtentTracker
    {
       /** Extent index trackers mapped to XML content names for columns */
       private final Map<String, ExtentTracker.Tracker> trackers = new HashMap<>();

       /**
        * Constructor. Initializes a map for extent fields, if any, in a temp-table.
        *
        * @param   schema
        *          Schema information for the temp-table.
        * @param   json
        *          Flag indicating if this is for JSON (when <code>true</code>) or XML (when <code>false</code>).
        */
       ExtentTracker(TempTableSchema schema, boolean json)
       {
          ArrayList<TempTableSchema.Column> columns = schema.columns();
          for (int k = 0; k < columns.size(); k++)
          {
             TempTableSchema.Column column = columns.get(k);

             Integer extent = column.getExtent();
             if (extent != null && extent > 0)
             {
                String name = json ? column.getSerializeName() : column.getXmlNodeName();
                ExtentTracker.Tracker tracker = new Tracker(extent);
                trackers.put(name, tracker);
             }
          }
       }

       /**
        * Reset the current index values to 0 for all extent fields being tracked.
        */
       void reset()
       {
          for (ExtentTracker.Tracker tracker : trackers.values())
          {
             tracker.reset();
          }
       }

       /**
        * Get the index value to be used to set the next element in the extent field associated
        * with the given name.
        *
        * @param   name
        *          Name associated with column data in XML content.
        *
        * @return  Next index value for extent field setter call.
        *
        * @throws  ArrayIndexOutOfBoundsException
        *          if the current index value reaches the size of the extent field.
        */
       Integer getNext(String name)
       {
          ExtentTracker.Tracker tracker = trackers.get(name);

          return (tracker == null ? null : tracker.getNext());
       }

       /**
        * Helper which tracks current and maximum index values for a single extent field.
        */
       private static class Tracker
       {
          /** Size of extent field */
          private final int max;

          /** Current index value */
          private int current = 0;

          /**
           * Constructor.
           *
           * @param   max
           *          Size of extent field.
           */
          Tracker(int max)
          {
             this.max = max;
          }

          /**
           * Get the index value to be used to set the next element in the extent field.
           *
           * @return  Next index value for extent field setter call.
           *
           * @throws  ArrayIndexOutOfBoundsException
           *          if the current index value reaches the size of the extent field.
           */
          Integer getNext()
          {
             if (current >= max)
             {
                throw new ArrayIndexOutOfBoundsException();
             }

             return current++;
          }

          /**
           * Reset the current value to 0.
           */
          void reset()
          {
             current = 0;
          }
       }
    }