/**
   * Checks the SequenceOf_value kind value against this type.
   *
   * <p>Please note, that this function can only be called once we know for sure that the value is
   * of set-of type.
   *
   * @param timestamp the timestamp of the actual semantic check cycle.
   * @param value the value to be checked
   * @param expectedValue the kind of value expected here.
   * @param incompleteAllowed wheather incomplete value is allowed or not.
   * @param implicit_omit true if the implicit omit optional attribute was set for the value, false
   *     otherwise
   */
  public void checkThisValueSequenceOf(
      final CompilationTimeStamp timestamp,
      final SequenceOf_Value value,
      final Expected_Value_type expectedValue,
      final boolean incompleteAllowed,
      final boolean implicit_omit,
      final boolean strElem) {
    if (value.isIndexed()) {
      boolean checkHoles = Expected_Value_type.EXPECTED_CONSTANT.equals(expectedValue);
      BigInteger maxIndex = BigInteger.valueOf(-1);
      Map<BigInteger, Integer> indexMap =
          new HashMap<BigInteger, Integer>(value.getNofComponents());
      for (int i = 0, size = value.getNofComponents(); i < size; i++) {
        IValue component = value.getValueByIndex(i);
        IValue index = value.getIndexByIndex(i);
        IReferenceChain referenceChain =
            ReferenceChain.getInstance(IReferenceChain.CIRCULARREFERENCE, true);
        IValue indexLast = index.getValueRefdLast(timestamp, referenceChain);
        referenceChain.release();

        if (indexLast.getIsErroneous(timestamp)
            || !Value_type.INTEGER_VALUE.equals(indexLast.getValuetype())) {
          checkHoles = false;
        } else {
          BigInteger tempIndex = ((Integer_Value) indexLast).getValueValue();
          if (tempIndex.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) == 1) {
            index
                .getLocation()
                .reportSemanticError(
                    MessageFormat.format(
                        "A integer value less than `{0}'' was expected for indexing type `{1}'' instead of `{2}''",
                        Integer.MAX_VALUE, getTypename(), tempIndex));
            checkHoles = false;
          } else if (tempIndex.compareTo(BigInteger.ZERO) == -1) {
            index
                .getLocation()
                .reportSemanticError(
                    MessageFormat.format(
                        "A non-negative integer value was expected for indexing type `{0}'' instead of `{1}''",
                        getTypename(), tempIndex));
            checkHoles = false;
          } else if (indexMap.containsKey(tempIndex)) {
            index
                .getLocation()
                .reportSemanticError(
                    MessageFormat.format(
                        "Duplicate index value `{0}'' for components {1} and {2}",
                        tempIndex, indexMap.get(tempIndex), i + 1));
            checkHoles = false;
          } else {
            indexMap.put(tempIndex, Integer.valueOf(i + 1));
            if (maxIndex.compareTo(tempIndex) == -1) {
              maxIndex = tempIndex;
            }
          }
        }

        component.setMyGovernor(getOfType());
        IValue tempValue2 = getOfType().checkThisValueRef(timestamp, component);
        getOfType()
            .checkThisValue(
                timestamp,
                tempValue2,
                new ValueCheckingOptions(
                    expectedValue, incompleteAllowed, false, true, implicit_omit, strElem));
      }
      if (checkHoles) {
        if (maxIndex.compareTo(BigInteger.valueOf(indexMap.size() - 1)) != 0) {
          value
              .getLocation()
              .reportSemanticError("It's not allowed to create hole(s) in constant values");
        }
      }
    } else {
      for (int i = 0, size = value.getNofComponents(); i < size; i++) {
        IValue component = value.getValueByIndex(i);
        component.setMyGovernor(getOfType());
        if (Value_type.NOTUSED_VALUE.equals(component.getValuetype())) {
          if (!incompleteAllowed) {
            component.getLocation().reportSemanticError(INCOMPLETEPRESENTERROR);
          }
        } else {
          IValue tempValue2 = getOfType().checkThisValueRef(timestamp, component);
          getOfType()
              .checkThisValue(
                  timestamp,
                  tempValue2,
                  new ValueCheckingOptions(
                      expectedValue, incompleteAllowed, false, true, implicit_omit, strElem));
        }
      }
    }
  }
  @Override
  public void checkThisTemplate(
      final CompilationTimeStamp timestamp,
      final ITTCN3Template template,
      final boolean isModified,
      final boolean implicitOmit) {
    registerUsage(template);
    template.setMyGovernor(this);

    switch (template.getTemplatetype()) {
      case OMIT_VALUE:
        if (template.getLengthRestriction() != null) {
          template.getLocation().reportSemanticWarning(REDUNDANTLENGTHRESTRICTION);
        }
        break;
      case PERMUTATION_MATCH:
        {
          PermutationMatch_Template permutationTemplate = (PermutationMatch_Template) template;
          int nofComponents = permutationTemplate.getNofTemplates();
          for (int i = 0; i < nofComponents; i++) {
            ITTCN3Template templateComponent =
                permutationTemplate.getTemplateByIndex(
                    i); // FIXME: type is ok? It should be ITemplateListItem!
            templateComponent.setMyGovernor(getOfType());
            templateComponent =
                getOfType()
                    .checkThisTemplateRef(
                        timestamp,
                        templateComponent); // It does not do anything for AllElementsFrom, it is ok
            templateComponent.checkThisTemplateGeneric(
                timestamp,
                getOfType(),
                false,
                false,
                true,
                true,
                implicitOmit); // it is a special for AllElementsFrom, it is the usual for
                               // TemplateBody
          }
          break;
        }
      case SUPERSET_MATCH:
        {
          SupersetMatch_Template supersetTemplate = (SupersetMatch_Template) template;
          int nofComponents = supersetTemplate.getNofTemplates();
          for (int i = 0; i < nofComponents; i++) {
            ITTCN3Template templateComponent =
                supersetTemplate.getTemplateByIndex(
                    i); // FIXME: type is ok? It should be ITemplateListItem!
            templateComponent.setMyGovernor(getOfType());
            templateComponent =
                getOfType()
                    .checkThisTemplateRef(
                        timestamp,
                        templateComponent); // It does not do anything for AllElementsFrom, it is ok
            templateComponent.checkThisTemplateGeneric(
                timestamp,
                getOfType(),
                false,
                false,
                true,
                true,
                implicitOmit); // it is a special for AllElementsFrom, it is the usual for
                               // TemplateBody
          }
          break;
        }
      case SUBSET_MATCH:
        {
          SubsetMatch_Template subsetTemplate = (SubsetMatch_Template) template;
          int nofComponents = subsetTemplate.getNofTemplates();
          for (int i = 0; i < nofComponents; i++) {
            ITTCN3Template templateComponent =
                subsetTemplate.getTemplateByIndex(
                    i); // FIXME: type is ok? It should be ITemplateListItem!
            templateComponent.setMyGovernor(getOfType());
            templateComponent =
                getOfType()
                    .checkThisTemplateRef(
                        timestamp,
                        templateComponent); // It does not do anything for AllElementsFrom, it is ok
            templateComponent.checkThisTemplateGeneric(
                timestamp,
                getOfType(),
                false,
                false,
                true,
                true,
                implicitOmit); // it is a special for AllElementsFrom, it is the usual for
                               // TemplateBody
          }
          break;
        }
      case TEMPLATE_LIST:
        {
          Completeness_type completeness =
              template.getCompletenessConditionSeof(timestamp, isModified);
          Template_List base = null;
          int nofBaseComps = 0;
          if (Completeness_type.PARTIAL.equals(completeness)) {
            ITTCN3Template tempBase = template.getBaseTemplate();
            if (tempBase != null) {
              tempBase = tempBase.getTemplateReferencedLast(timestamp);
            }

            if (tempBase == null) {
              setIsErroneous(true);
              return;
            }

            base = ((Template_List) tempBase);
            nofBaseComps = base.getNofTemplates();
          }

          Template_List templateList = (Template_List) template;
          int nofComponents = templateList.getNofTemplates();
          for (int i = 0; i < nofComponents; i++) {
            ITTCN3Template component = templateList.getTemplateByIndex(i);
            component.setMyGovernor(getOfType());
            if (base != null && nofBaseComps > i) {
              component.setBaseTemplate(base.getTemplateByIndex(i));
            } else {
              component.setBaseTemplate(null);
            }

            component = getOfType().checkThisTemplateRef(timestamp, component);

            switch (component.getTemplatetype()) {
              case PERMUTATION_MATCH:
              case SUPERSET_MATCH:
              case SUBSET_MATCH:
                // FIXME: for Complement??? case COMPLEMENTED_LIST: ???
                // the elements of permutation has to be checked by u.seof.ofType
                // the templates within the permutation always have to be complete
                component.checkThisTemplateGeneric(
                    timestamp, this, false, false, true, true, implicitOmit);
                break;
              case TEMPLATE_NOTUSED:
                if (Completeness_type.MUST_COMPLETE.equals(completeness)) {
                  component.getLocation().reportSemanticError(NOTUSEDNOTALLOWED1);
                } else if (Completeness_type.PARTIAL.equals(completeness) && i >= nofBaseComps) {
                  component.getLocation().reportSemanticError(NOTUSEDNOTALLOWED2);
                }
                break;
              default:
                boolean embeddedModified =
                    (completeness == Completeness_type.MAY_INCOMPLETE)
                        || (completeness == Completeness_type.PARTIAL && i < nofBaseComps);
                component.checkThisTemplateGeneric(
                    timestamp, getOfType(), embeddedModified, false, true, true, implicitOmit);
                break;
            }
          }
          break;
        }
      case INDEXED_TEMPLATE_LIST:
        {
          Map<Long, Integer> indexMap = new HashMap<Long, Integer>();
          Indexed_Template_List indexedTemplateList = (Indexed_Template_List) template;
          for (int i = 0, size = indexedTemplateList.getNofTemplates(); i < size; i++) {
            IndexedTemplate indexedTemplate = indexedTemplateList.getIndexedTemplateByIndex(i);
            Value indexValue = indexedTemplate.getIndex().getValue();
            ITTCN3Template templateComponent = indexedTemplate.getTemplate();

            IReferenceChain chain =
                ReferenceChain.getInstance(IReferenceChain.CIRCULARREFERENCE, true);
            IValue lastValue = indexValue.getValueRefdLast(timestamp, chain);
            chain.release();
            if (Value_type.INTEGER_VALUE.equals(lastValue.getValuetype())) {
              long index = ((Integer_Value) lastValue).getValue();
              if (index > Integer.MAX_VALUE) {
                indexValue
                    .getLocation()
                    .reportSemanticError(
                        MessageFormat.format(
                            TOOBIGINDEXTEMPLATE, Integer.MAX_VALUE, getTypename(), index));
                indexValue.setIsErroneous(true);
              } else if (index < 0) {
                indexValue
                    .getLocation()
                    .reportSemanticError(
                        MessageFormat.format(
                            NONNEGATIVEINDEXEXPECTEDTEMPLATE, getTypename(), index));
                indexValue.setIsErroneous(true);
              } else {
                if (indexMap.containsKey(index)) {
                  indexValue
                      .getLocation()
                      .reportSemanticError(
                          MessageFormat.format(DUPLICATEINDEX, index, i + 1, indexMap.get(index)));
                  indexValue.setIsErroneous(true);
                } else {
                  indexMap.put(index, i);
                }
              }
            } else {
              indexValue.getLocation().reportSemanticError(INTEGERINDEXEXPECTED);
              indexValue.setIsErroneous(true);
            }

            templateComponent.setMyGovernor(getOfType());
            templateComponent = getOfType().checkThisTemplateRef(timestamp, templateComponent);
            templateComponent.checkThisTemplateGeneric(
                timestamp, getOfType(), true, false, true, true, implicitOmit);
          }
          break;
        }
      default:
        template
            .getLocation()
            .reportSemanticError(
                MessageFormat.format(
                    TEMPLATENOTALLOWED, template.getTemplateTypeName(), getTypename()));
        break;
    }
  }
  private void classifyFieldSpecification(final CompilationTimeStamp timestamp) {
    final IReferenceChain temporalReferenceChain =
        ReferenceChain.getInstance(IReferenceChain.CIRCULARREFERENCE, true);

    if (isOptional && (null != defaultSetting1 || null != mDefaultSetting)) {
      location.reportSemanticError("OPTIONAL and DEFAULT are mutually exclusive");
      isOptional = false;
    }

    if (temporalReferenceChain.add(this) && null != governorReference) {
      governorReference.setMyScope(myObjectClass.getMyScope());

      if (null != defaultSetting1) {
        defaultSetting1.setMyScope(myObjectClass.getMyScope());
      }

      if (identifier.isvalidAsnObjectSetFieldReference()
          && governorReference.refersToSettingType(
              timestamp, Setting_type.S_OC, temporalReferenceChain)) {
        ObjectSet defaultObjectset = null;
        if (null != mDefaultSetting) {
          defaultObjectset = ParserFactory.createObjectSetDefinition(mDefaultSetting);
        }
        fieldSpecification =
            new ObjectSet_FieldSpecification(
                identifier, new ObjectClass_refd(governorReference), isOptional, defaultObjectset);
      } else if (identifier.isvalidAsnObjectFieldReference()
          && governorReference.refersToSettingType(
              timestamp, Setting_type.S_OC, temporalReferenceChain)) {
        ASN1Object defaultObject = null;
        if (null != defaultSetting1) {
          defaultObject = new ReferencedObject(defaultSetting1);
        } else if (null != mDefaultSetting) {
          defaultObject = new Object_Definition(mDefaultSetting);
        }

        fieldSpecification =
            new Object_FieldSpecification(
                identifier, new ObjectClass_refd(governorReference), isOptional, defaultObject);
      } else if (identifier.isvalidAsnValueFieldReference()
          && (governorReference.refersToSettingType(
                  timestamp, Setting_type.S_T, temporalReferenceChain)
              || governorReference.refersToSettingType(
                  timestamp, Setting_type.S_VS, temporalReferenceChain))) {
        IValue defaultValue = null;

        if (null != defaultSetting1) {
          if (defaultSetting1 instanceof Defined_Reference
              && null == defaultSetting1.getModuleIdentifier()) {
            defaultValue =
                new Undefined_LowerIdentifier_Value(defaultSetting1.getId().newInstance());
          } else {
            defaultValue = new Referenced_Value(defaultSetting1);
          }
        } else if (null != mDefaultSetting) {
          defaultValue = ParserFactory.createUndefinedBlockValue(mDefaultSetting);
        }
        fieldSpecification =
            new FixedTypeValue_FieldSpecification(
                identifier,
                new Referenced_Type(governorReference),
                false,
                isOptional,
                null != defaultSetting1 && null != mDefaultSetting,
                defaultValue);
      }
    }

    if (null == fieldSpecification) {
      location.reportSemanticError(CANNOTRECOGNISE);
      fieldSpecification =
          new Erroneous_FieldSpecification(
              identifier, isOptional, null != defaultSetting1 || null != mDefaultSetting);
    } else {
      if (null != myObjectClass) {
        fieldSpecification.setMyObjectClass(myObjectClass);
      }
    }

    fieldSpecification.setFullNameParent(getNameParent());
    fieldSpecification.setLocation(location);

    temporalReferenceChain.release();
  }