# List.java

    /*
    ** Module   : List.java
    ** Abstract : Implementation of the Progress.Collections.List builtin class.
    **
    ** Copyright (c) 2025, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- -------------------------------Description--------------------------------
    ** 001 ICP 20250224 First version.
    ** 002 ICP 20250414 Added implementation for builtin functions.
    */

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

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

    import java.util.ArrayList;

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

    /**
     * Implementation of the Progress.Collections.List builtin class.
     */
    @LegacyResource(resource = "Progress.Collections.List")
    @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
    @LegacySerializable
    public final class List<T extends _BaseObject_>
    extends BaseObject
    implements Ilist<T>,
               Icollection<T>,
               Iiterable
    {
       @LegacySignature(type = Type.PROPERTY, name = "Count")
       private integer count = TypeFactory.integer();

       @LegacySignature(type = Type.PROPERTY, name = "IsEmpty")
       private logical isEmpty = TypeFactory.logical();

       /** The collection of elements in the list */
       private java.util.List<object<? extends _BaseObject_>> elements;

       @LegacySignature(type = Type.CONSTRUCTOR, name = "List")
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
       public void __collections_list_constructor__()
       {
          __lang_BaseObject_constructor__();
          elements = new ArrayList<>();
          count.assign(0);
          isEmpty.assign(true);
       }

       @LegacySignature(type = Type.CONSTRUCTOR, name = "List", parameters =
          {
             @LegacyParameter(name = "capacity", type = "INTEGER", mode = "INPUT")
          })
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
       public void __collections_list_constructor__(final integer capacity)
       {
          __lang_BaseObject_constructor__();
          elements = new ArrayList<>(capacity.intValue());
          count.assign(0);
          isEmpty.assign(true);
       }

       @LegacySignature(type = Type.GETTER, name = "Count", returns = "INTEGER")
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
       public integer getCount()
       {
          return count.duplicate();
       }

       @LegacySignature(type = Type.GETTER, name = "IsEmpty", returns = "LOGICAL")
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
       public logical getIsEmpty()
       {
          return isEmpty.duplicate();
       }

       @LegacySignature(type = Type.METHOD, name = "Add", returns = "LOGICAL", parameters =
          {
             @LegacyParameter(name = "element",
                              type = "OBJECT",
                              qualified = "progress.lang.object",
                              mode = "INPUT")
          })
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
       public logical add(final object<T> _element)
       {
          elements.add(_element);
          count.assign(elements.size());
          isEmpty.assign(false);

          return logical.TRUE;
       }

       @LegacySignature(type = Type.METHOD, name = "AddAll", returns = "LOGICAL", parameters =
          {
             @LegacyParameter(name = "otherCollections",
                              type = "OBJECT",
                              qualified = "progress.collections.icollection",
                              mode = "INPUT")
          })
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
       public logical addAll(final object<? extends Icollection> otherCollections)
       {
          boolean addedAny = false;

          if (otherCollections.isUnknown())
          {
             ErrorManager.recordOrThrowError(
                18193,
                "Invalid value specified for parameter 'otherCollections' of method or constructor 'addAll'",
                false
             );
             return logical.FALSE;
          }

          object<? extends Iiterator> it = otherCollections.ref().getIterator();

          while (it.ref().moveNext().booleanValue())
          {
             object elem = it.ref().getCurrent();
             elements.add(elem);
             addedAny = true;
          }

          if (addedAny)
          {
             count.assign(elements.size());
             isEmpty.assign(false);
          }

          return logical.of(addedAny);
       }

       @LegacySignature(type = Type.METHOD, name = "Clear")
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
       public void clear_()
       {
          elements.clear();
          count.assign(0);
          isEmpty.assign(true);
       }

       @LegacySignature(type = Type.METHOD, name = "Contains", returns = "LOGICAL", parameters =
          {
             @LegacyParameter(name = "element",
                              type = "OBJECT",
                              qualified = "progress.lang.object",
                              mode = "INPUT")
          })
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
       @Override
       public logical contains(final object<T> element)
       {
          for (object<? extends _BaseObject_> obj : elements)
          {
             if (obj == null && element == null)
             {
                return logical.TRUE;
             }
             else if (obj.isUnknown() && element.isUnknown())
             {
                return logical.TRUE;
             }
             else if (obj.equals(element))
             {
                return logical.TRUE;
             }
          }
          return logical.FALSE;
       }

       @LegacySignature(type = Type.METHOD,
                        name = "Get",
                        returns = "OBJECT",
                        qualified = "progress.lang.object",
                        parameters =
          {
             @LegacyParameter(name = "index", type = "INTEGER", mode = "INPUT")
          })
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
       public object<? extends com.goldencode.p2j.oo.lang._BaseObject_> get(final integer index)
       {
          int idx = index.intValue();

          if (idx < 1 || idx > elements.size())
          {
             ErrorManager.recordOrThrowError(
                18193,
                "Invalid value specified for parameter 'index' of method or constructor 'Get'",
                false
             );
             return null;
          }
          return elements.get(idx - 1);
       }

       @LegacySignature(type = Type.METHOD,
                        name = "GetIterator",
                        returns = "OBJECT",
                        qualified = "progress.collections.iiterator")
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
       public object<? extends com.goldencode.p2j.oo.collections.Iiterator> getIterator()
       {
          object<ListIterator> iter = TypeFactory.object(ListIterator.class);
          iter.assign(ObjectOps.newInstance(ListIterator.class));
          iter.ref().setElements(elements);
          return iter;
       }

       @LegacySignature(type = Type.METHOD, name = "IndexOf", returns = "INTEGER", parameters =
          {
             @LegacyParameter(name = "element",
                              type = "OBJECT",
                              qualified = "progress.lang.object",
                              mode = "INPUT")
          })
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
       public integer indexOf_(final object<? extends com.goldencode.p2j.oo.lang._BaseObject_> element)
       {
          if (element == null || element.isUnknown())
          {
             return new integer(0);
          }

          for (int i = 0; i < elements.size(); i++)
          {
             if (elements.get(i).equals(element))
             {
                return new integer(i + 1);
             }
          }
          return new integer(0);
       }

       @LegacySignature(type = Type.METHOD, name = "Insert", parameters =
          {
             @LegacyParameter(name = "index", type = "INTEGER", mode = "INPUT"),
             @LegacyParameter(name = "element",
                              type = "OBJECT",
                              qualified = "progress.lang.object",
                              mode = "INPUT")
          })
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
       public void insert(final integer index, final object<? extends _BaseObject_> element)
       {
          int idx = index.intValue();

          if (idx < 1 || idx > elements.size() + 1)
          {
             ErrorManager.recordOrThrowError(
                18193,
                "Invalid value specified for parameter 'index' of method or constructor 'Insert'",
                false
             );
             return;
          }

          elements.add(idx - 1, element);
          count.assign(elements.size());
          isEmpty.assign(false);
       }

       @LegacySignature(type = Type.METHOD, name = "Insert", parameters =
          {
             @LegacyParameter(name = "index", type = "INTEGER", mode = "INPUT"),
             @LegacyParameter(name = "otherCollections",
                              type = "OBJECT",
                              qualified = "progress.collections.icollection",
                              mode = "INPUT")
          })
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
       public void insert_1(final integer index, final object<? extends Icollection> otherCollections)
       {
          int idx = index.intValue();

          if (idx < 1 || idx > elements.size() + 1)
          {
             ErrorManager.recordOrThrowError(
                18193,
                "Invalid value specified for parameter 'index' of method or constructor 'Insert'",
                false
             );
             return;
          }

          // Prevent inserting self
          if (otherCollections.ref() == this)
          {
             ErrorManager.recordOrThrowError(
                18193,
                "Invalid value specified for parameter 'otherCollections' of method or constructor 'Insert'",
                false
             );
             return;
          }

          object<? extends Iiterator> it = (object<? extends Iiterator>) otherCollections.ref().getIterator();
          int insertionPoint = idx - 1;
          java.util.List<object<? extends _BaseObject_>> toInsert = new ArrayList<>();

          while (it.ref().moveNext().booleanValue())
          {
             toInsert.add(it.ref().getCurrent());
          }

          if (!toInsert.isEmpty())
          {
             elements.addAll(insertionPoint, toInsert);
             count.assign(elements.size());
             isEmpty.assign(elements.isEmpty());
          }
       }

       @LegacySignature(type = Type.METHOD, name = "Remove", returns = "LOGICAL", parameters =
          {
             @LegacyParameter(name = "element",
                              type = "OBJECT",
                              qualified = "progress.lang.object",
                              mode = "INPUT")
          })
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
       public logical remove(final object<? extends com.goldencode.p2j.oo.lang._BaseObject_> element)
       {
          if (element == null || element.isUnknown())
          {
             return logical.FALSE;
          }

          for (int i = 0; i < elements.size(); i++)
          {
             if (elements.get(i).equals(element))
             {
                elements.remove(i);
                count.assign(elements.size());
                isEmpty.assign(elements.isEmpty());
                return logical.TRUE;
             }
          }

          return logical.FALSE;
       }

       @LegacySignature(type = Type.METHOD, name = "RemoveAt", parameters =
          {
             @LegacyParameter(name = "index", type = "INTEGER", mode = "INPUT")
          })
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
       public void removeAt(final integer index)
       {
          int idx = index.intValue();

          if (idx < 1 || idx > elements.size())
          {
             ErrorManager.recordOrThrowError(
                18193,
                "Invalid value specified for parameter 'index' of method or constructor 'RemoveAt'",
                false
             );
             return;
          }

          elements.remove(idx - 1);
          count.assign(elements.size());
          isEmpty.assign(elements.isEmpty());
       }

       @LegacySignature(type = Type.METHOD,
                        name = "Set",
                        returns = "OBJECT",
                        qualified = "progress.lang.object",
                        parameters =
          {
             @LegacyParameter(name = "index", type = "INTEGER", mode = "INPUT"),
             @LegacyParameter(name = "element", type = "OBJECT", qualified = "progress.lang.object", mode = "INPUT")
          })
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
       public object<? extends _BaseObject_> set(final integer index,
                                                 final object<? extends _BaseObject_> element)
       {
          int idx = index.intValue();

          if (idx < 1 || idx > elements.size())
          {
             ErrorManager.recordOrThrowError(
                18193,
                "Invalid value specified for parameter 'index' of method or constructor 'Set'",
                false
             );
             return null;
          }
          return elements.set(idx - 1, element);
       }
    }