# DataProvider_.java

    /*
    ** Module   : DataProvider.java
    ** Abstract : Implementation of the OEUnit.Data.DataProvider class.
    **
    ** Copyright (c) 2023, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- ---------------------------------------Description----------------------------------------
    ** 001 VVT 20230318 Created initial version
    ** 002 CA  20230817 Removed ObjectOps.register, as this registration is handled by runtime.
    ** 003 CA  20231113 The 'execute' method must be annotated with LegacySignature Type.Execute, and also can be
    **                  dropped if is a no-op.
    */

    /*
    ** 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.oo.oeunit.data;

    import com.goldencode.p2j.util.*;
    import com.goldencode.p2j.oo.lang.*;
    import com.goldencode.p2j.persist.*;
    import com.goldencode.p2j.persist.lock.*;

    import static com.goldencode.p2j.report.ReportConstants.*;
    import static com.goldencode.p2j.util.BlockManager.*;
    import static com.goldencode.p2j.util.InternalEntry.Type;
    import static com.goldencode.p2j.util.logical.*;
    import static com.goldencode.p2j.util.TextOps.*;

    /**
     * Implementation for OEUnit.Data.DataProvider.
     */
    @LegacyResource(resource = "OEUnit.Data.DataProvider")
    @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
    public class DataProvider_
    extends BaseObject
    {
       /**
        * Temptable handle
        */
       @LegacySignature(type = Type.VARIABLE, name = "ttData")
       protected handle ttData = TypeFactory.handle();

       /**
        * Query handle
        */
       @LegacySignature(type = Type.VARIABLE, name = "ttQuery")
       protected handle ttQuery = TypeFactory.handle();

       /**
        * Current data size
        */
       private int size;

       /**
        * Static constructor
        */
       @LegacySignature(type = Type.CONSTRUCTOR)
       public static void __oeunit_data_DataProvider__constructor__static__()
       {
          externalProcedure(DataProvider_.class, new Block((Body) () ->
          {
             onRoutineLevel(Condition.ERROR, Action.THROW);
          }));
       }

       /**
        * Constructor
        */
       @LegacySignature(type = Type.CONSTRUCTOR)
       public void __oeunit_data_dataProvider__constructor__()
       {
          internalProcedure(DataProvider_.class, this, "__oeunit_data_dataProvider_constructor__", new Block((Body) () ->
          {
             __lang_BaseObject_constructor__();
             setSize(new integer(0));
          }));
       }

       /**
        * Destructor
        */
       @LegacySignature(type = Type.DESTRUCTOR)
       public void __oeunit_data_DataProvider__destructor__()
       {
          internalProcedure(DataProvider_.class, this, "__oeunit_data_DataProvider_destructor__", new Block((Body) () ->
          {
             if (ttData._isValid())
             {
                HandleOps.delete(ttData);
             }

             if (ttQuery._isValid())
             {
                ttQuery.unwrapQuery().queryClose();
                HandleOps.delete(ttQuery);
             }
          }));
       }

       /**
        * The 'execute' method
        */
       @LegacySignature(type = Type.EXECUTE)
       public void __oeunit_data_DataProvider__execute__()
       {
          onRoutineLevel(Condition.ERROR, Action.THROW);
       }

       /**
        * Initialize from a JSON string.
        *
        * @param  json
        *         the JSON string
        *
        * @return {@code true} if the operation completed successfully.
        */
       @LegacySignature(type = Type.METHOD, name = "FromJSON", returns = "LOGICAL", parameters =
       {
          @LegacyParameter(name = "json", type = "LONGCHAR", mode = "INPUT")
       })
       public logical fromJson(final Text json)
       {
          return function(DataProvider_.class, this, "FromJSON", logical.class, new Block((Body) () -> {
             if (ttQuery._isValid())
             {
                HandleOps.delete(ttQuery);
             }

             if (ttData._isValid())
             {
                HandleOps.delete(ttData);
             }

             TempTableBuilder.create(ttData);
             @SuppressWarnings("resource")
             final logical res = ttData.unwrapJsonData().readJson(new SourceData("LONGCHAR", json),
                      new character("EMPTY"));
             countSize();
             storeReturnValue(res);
          }));
       }

       /**
        * Initialize from a JSON file.
        *
        * @param  path
        *         path to a JSON file
        *
        * @return {@code true} if the operation completed successfully.
        */
       @LegacySignature(type = Type.METHOD, name = "FromJSONFile", returns = "LOGICAL", parameters =
       {
          @LegacyParameter(name = "path", type = "CHARACTER", mode = "INPUT")
       })
       public logical fromJsonfile(final Text path)
       {
          return function(DataProvider_.class, this, "FromJSONFile", logical.class, new Block((Body) () ->
          {
             if (ttQuery._isValid())
             {
                HandleOps.delete(ttQuery);
             }

             if (ttData._isValid())
             {
                HandleOps.delete(ttData);
             }

             TempTableBuilder.create(ttData);
             @SuppressWarnings("resource")
             final logical res = ttData.unwrapJsonData().readJson(new SourceData("FILE", path), new character("EMPTY"));
             countSize();
             storeReturnValue(res);
          }));
       }

       /**
        * Initialize from a TEMP-TABLE
        *
        * @param  _ttSrc
        *         source table handle
        *
        * @return {@code true} if the operation completed successfully.
        */
       @LegacySignature(type = Type.METHOD, name = "FromTempTable", returns = "LOGICAL", parameters =
       {
          @LegacyParameter(name = "ttSrc", type = "HANDLE", mode = "INPUT")
       })
       public logical fromTempTable(final handle _ttSrc)
       {
          final handle ttSrc = TypeFactory.initInput(_ttSrc);

          return function(DataProvider_.class, this, "FromTempTable", logical.class, new Block((Body) () ->
          {
             if (ttQuery._isValid())
             {
                HandleOps.delete(ttQuery);
             }

             if (ttData._isValid())
             {
                HandleOps.delete(ttData);
             }

             TempTableBuilder.create(ttData);
             final logical res = ttData.unwrapTempTableDuplicator().copyTempTable(ttSrc);
             countSize();
             storeReturnValue(res);
          }));
       }

       /**
        * Initialize from an XML string
        *
        * @param  xml
        *         source XML code
        *
        * @return {@code true} if the operation completed successfully.
        */
       @LegacySignature(type = Type.METHOD, name = "FromXML", returns = "LOGICAL", parameters =
       {
          @LegacyParameter(name = "xml", type = "LONGCHAR", mode = "INPUT")
       })
       public logical fromXml(final Text xml)
       {
          return function(DataProvider_.class, this, "FromXML", logical.class, new Block((Body) () ->
          {
             if (ttQuery._isValid())
             {
                HandleOps.delete(ttQuery);
             }

             if (ttData._isValid())
             {
                HandleOps.delete(ttData);
             }

             TempTableBuilder.create(ttData);
             @SuppressWarnings("resource")
             final logical res = ttData.unwrapXmlData().readXml(new SourceData("LONGCHAR", xml),
                      new character("EMPTY"), new character(), new logical());
             countSize();
             storeReturnValue(res);
          }));
       }

       /**
        * Initialize from an XML file
        *
        * @param  path
        *         path to the source XML file
        *
        * @return {@code true} if the operation completed successfully.
        */
       @LegacySignature(type = Type.METHOD, name = "FromXMLFile", returns = "LOGICAL", parameters =
       {
          @LegacyParameter(name = "path", type = "CHARACTER", mode = "INPUT")
       })
       public logical fromXmlfile(final Text path)
       {
          return function(DataProvider_.class, this, "FromXMLFile", logical.class, new Block((Body) () ->
          {
             if (ttQuery._isValid())
             {
                HandleOps.delete(ttQuery);
             }

             if (ttData._isValid())
             {
                HandleOps.delete(ttData);
             }

             TempTableBuilder.create(ttData);
             @SuppressWarnings("resource")
             final logical res = ttData.unwrapXmlData().readXml(new SourceData("FILE", path), new character("EMPTY"),
                      new character(), new logical());
             countSize();
             storeReturnValue(res);
          }));
       }

       /**
        * Get list of parameters
        *
        * @return see above
        */
       @LegacySignature(type = Type.METHOD, name = "GetParameterList", returns = "OBJECT", qualified = "progress.lang.parameterlist")
       public object<? extends ParameterList> getParameterList()
       {
          final handle bufHandle = TypeFactory.handle();
          final handle fieldHandle = TypeFactory.handle();
          final object<? extends com.goldencode.p2j.oo.lang.ParameterList> params = TypeFactory
                   .object(com.goldencode.p2j.oo.lang.ParameterList.class);

          return function(DataProvider_.class, this, "GetParameterList", object.class, new Block((Body) () ->
                   {
                      if (!ttData._isValid())
                      {
                         returnError();
                         return;
                      }

                      if (!ttQuery._isValid() || !ttQuery.unwrapOpenable().isOpen().booleanValue())
                      {
                         resetQuery();
                      }

                      if (!ttQuery.unwrapQuery().isOffEnd().booleanValue())
                      {
                         bufHandle.assign(ttQuery.unwrapBufferCollection().bufferHandle(1));

                         if (_not(bufHandle.unwrapAvailable().available()))
                         {
                            moveFirst();
                         }

                         final integer numParams = bufHandle.unwrapBuffer().numFields();
                         params.assign(ObjectOps.newInstance(com.goldencode.p2j.oo.lang.ParameterList.class, "I",
                                  numParams));

                         final integer i = TypeFactory.integer();
                         ToClause toClause0 = new ToClause(i, 1, numParams);

                         doTo("loopLabel1", toClause0, new Block((Body) () -> {
                            {
                               fieldHandle.assign(bufHandle.unwrapBuffer().bufferField(i));
                               params.ref().setParameter(i, fieldHandle.unwrapCommonField().getDataType(),
                                        new character("INPUT"), Call.valueReference(fieldHandle));
                            }
                         }));
                      }
                      storeReturnValue(params);
                   }));
       }

       /**
        * Get size property
        *
        * @return see above
        */
       @LegacySignature(type = Type.GETTER, name = "Size", returns = "INTEGER")
       public integer getSize()
       {
          return function(DataProvider_.class, this, "Size", integer.class, new Block((Body) () ->
          {
             storeReturnValue(size);
          }));
       }

       /**
        * Move to the first entry.
        *
        * @return {@code true} if this operation was successful.
        */
       @LegacySignature(type = Type.METHOD, name = "MoveFirst", returns = "LOGICAL")
       public logical moveFirst()
       {
          return function(DataProvider_.class, this, "MoveFirst", logical.class, new Block((Body) () ->
          {
             if (!ttQuery._isValid())
             {
                resetQuery();
             }

             storeReturnValue(ttQuery._isValid() &&
                      ttQuery.unwrapQuery().getFirst(LockType.LT_NONE).booleanValue());
          }));
       }

       /**
        * Move to the last entry.
        *
        * @return {@code true} if this operation was successful.
        */
       @LegacySignature(type = Type.METHOD, name = "MoveLast", returns = "LOGICAL")
       public logical moveLast()
       {
          return function(DataProvider_.class, this, "MoveLast", logical.class, new Block((Body) () ->
          {
             if (_not(ttQuery.isValid()))
             {
                resetQuery();
             }

             storeReturnValue(
                      ttQuery._isValid() && ttQuery.unwrapQuery().getLast(LockType.LT_NONE).booleanValue());
          }));
       }

       /**
        * Move to the next entry.
        *
        * @return {@code true} if this operation was successful.
        */
       @LegacySignature(type = Type.METHOD, name = "MoveNext", returns = "LOGICAL")
       public logical moveNext()
       {
          return function(DataProvider_.class, this, "MoveNext", logical.class, new Block((Body) () ->
          {
             if (_not(ttQuery.isValid()))
             {
                resetQuery();
             }

             storeReturnValue(ttQuery._isValid() && _moveNext());
          }));
       }

       /**
        * Move to the previous entry.
        *
        * @return {@code true} if this operation was successful.
        */
       @LegacySignature(type = Type.METHOD, name = "MovePrev", returns = "LOGICAL")
       public logical movePrev()
       {
          return function(DataProvider_.class, this, "MovePrev", logical.class, new Block((Body) () ->
          {
             if (_not(ttQuery.isValid()))
             {
                resetQuery();
             }

             storeReturnValue(
                      ttQuery._isValid() && ttQuery.unwrapQuery().getPrevious(LockType.LT_NONE).booleanValue());
          }));
       }

       /**
        * MoveNext internal implementation.
        *
        * @return {@code true} is the call was successful
        */
       private final boolean _moveNext()
       {
          return ttQuery.unwrapQuery().getNext(LockType.LT_NONE).booleanValue();
       }

       /**
        * Count number of entries
        */
       private final void countSize()
       {
          size = 0;

          resetQuery();

          while(_moveNext())
          {
             size++;
          }

          resetQuery();
       }

       /**
        * Reset the query
        */
       private final void resetQuery()
       {
          if (!ttData._isValid())
          {
             return;
          }

          if (ttQuery._isValid())
          {
             ttQuery.unwrapQuery().queryClose();
             HandleOps.delete(ttQuery);
          }

          final character qry = concat("FOR EACH ", ttData.unwrap().name());
          QueryWrapper.createQuery(ttQuery);
          ttQuery.unwrapBufferCollection().setBuffers(ttData.unwrapTempTable().defaultBufferHandle());

          if ((ttQuery.unwrapQuery().prepare(qry)).booleanValue())
          {
             ttQuery.unwrapQuery().queryOpen();
          }
          else
          {
             if (ttQuery._isValid())
             {
                HandleOps.delete(ttQuery);
             }
          }
       }

       /**
        * Set size property
        *
        * @param newSize
        *        the new size
        */
       @LegacySignature(type = Type.SETTER, name = "Size", parameters =
       {
          @LegacyParameter(name = "var", type = "INTEGER", mode = "INPUT")
       })
       private void setSize(final integer newSize)
       {
          internalProcedure(DataProvider_.class, this, "Size", new Block((Body) () ->
          {
             size = newSize.intValue();
          }));
       }
    }