content: /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You under the Apache License, Version 2.0
   * (the "License"); you may not use this file except in compliance with
   * the License.  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package mf.org.apache.xerces.impl.xs;
  
  import mf.org.apache.xerces.impl.xs.util.XSObjectListImpl;
  import mf.org.apache.xerces.xs.XSAnnotation;
  import mf.org.apache.xerces.xs.XSConstants;
  import mf.org.apache.xerces.xs.XSModelGroup;
  import mf.org.apache.xerces.xs.XSNamespaceItem;
  import mf.org.apache.xerces.xs.XSObjectList;
  
  
  /**
   * Store schema model group declaration.
   *
   * @author Sandy Gao, IBM
   * @version $Id: XSModelGroupImpl.java 699892 2008-09-28 21:08:27Z mrglavas $
   * @xerces.internal
   */
  public class XSModelGroupImpl implements XSModelGroup {
  
      // types of model groups
      // REVISIT: can't use same constants as those for particles, because
      // there are place where the constants are used together. For example,
      // to check whether the content is an element or a sequence.
      public static final short MODELGROUP_CHOICE = 101;
      public static final short MODELGROUP_SEQUENCE = 102;
      public static final short MODELGROUP_ALL = 103;
  
      // compositor of the model group
      public short fCompositor;
  
      // particles
      public XSParticleDecl[] fParticles = null;
      public int fParticleCount = 0;
  
      // this particle's optional annotations
      public XSObjectList fAnnotations = null;
      /**
       * get the string description of this particle
       */
      private String fDescription = null;
  
      // whether this model group contains nothing
      public boolean isEmpty() {
          for (int i = 0; i < fParticleCount; i++) {
              if (!fParticles[i].isEmpty())
                  return false;
          }
          return true;
      }
  
      /**
       * 3.8.6 Effective Total Range (all and sequence) and
       * Effective Total Range (choice)
       * The following methods are used to return min/max range for a particle.
       * They are not exactly the same as it's described in the spec, but all the
       * values from the spec are retrievable by these methods.
       */
      public int minEffectiveTotalRange() {
          if (fCompositor == MODELGROUP_CHOICE)
              return minEffectiveTotalRangeChoice();
          else
              return minEffectiveTotalRangeAllSeq();
      }
  
      // return the sum of all min values of the particles
      private int minEffectiveTotalRangeAllSeq() {
          int total = 0;
          for (int i = 0; i < fParticleCount; i++)
              total += fParticles[i].minEffectiveTotalRange();
          return total;
      }
  
      // return the min of all min values of the particles
      private int minEffectiveTotalRangeChoice() {
          int min = 0, one;
          if (fParticleCount > 0)
              min = fParticles[0].minEffectiveTotalRange();
  
          for (int i = 1; i < fParticleCount; i++) {
              one = fParticles[i].minEffectiveTotalRange();
              if (one < min)
                  min = one;
          }
  
          return min;
      }
  
      public int maxEffectiveTotalRange() {
          if (fCompositor == MODELGROUP_CHOICE)
              return maxEffectiveTotalRangeChoice();
          else
              return maxEffectiveTotalRangeAllSeq();
      }
  
      // if one of the max value of the particles is unbounded, return unbounded;
      // otherwise return the sum of all max values
      private int maxEffectiveTotalRangeAllSeq() {
          int total = 0, one;
          for (int i = 0; i < fParticleCount; i++) {
              one = fParticles[i].maxEffectiveTotalRange();
              if (one == SchemaSymbols.OCCURRENCE_UNBOUNDED)
                  return SchemaSymbols.OCCURRENCE_UNBOUNDED;
              total += one;
          }
          return total;
      }
  
      // if one of the max value of the particles is unbounded, return unbounded;
      // otherwise return the max of all max values
      private int maxEffectiveTotalRangeChoice() {
          int max = 0, one;
          if (fParticleCount > 0) {
              max = fParticles[0].maxEffectiveTotalRange();
              if (max == SchemaSymbols.OCCURRENCE_UNBOUNDED)
                  return SchemaSymbols.OCCURRENCE_UNBOUNDED;
          }
  
          for (int i = 1; i < fParticleCount; i++) {
              one = fParticles[i].maxEffectiveTotalRange();
              if (one == SchemaSymbols.OCCURRENCE_UNBOUNDED)
                  return SchemaSymbols.OCCURRENCE_UNBOUNDED;
              if (one > max)
                  max = one;
          }
          return max;
      }
  
      @Override
      public String toString() {
          // REVISIT: Commented code may help to eliminate redundant parentheses (test first before committing)
          if (fDescription == null) {
              StringBuffer buffer = new StringBuffer();
              if (fCompositor == MODELGROUP_ALL)
                  buffer.append("all(");
              else  //if (fMinOccurs != 1 || fMaxOccurs != 1)
                  buffer.append('(');
              if (fParticleCount > 0)
                  buffer.append(fParticles[0].toString());
              for (int i = 1; i < fParticleCount; i++) {
                  if (fCompositor == MODELGROUP_CHOICE)
                      buffer.append('|');
                  else
                      buffer.append(',');
                  buffer.append(fParticles[i].toString());
              }
              //if (fCompositor == MODELGROUP_ALL || fMinOccurs != 1 || fMaxOccurs != 1)
              buffer.append(')');
              fDescription = buffer.toString();
          }
          return fDescription;
      }
  
      public void reset() {
          fCompositor = MODELGROUP_SEQUENCE;
          fParticles = null;
          fParticleCount = 0;
          fDescription = null;
          fAnnotations = null;
      }
  
      /**
       * Get the type of the object, i.e ELEMENT_DECLARATION.
       */
      @Override
      public short getType() {
          return XSConstants.MODEL_GROUP;
      }
  
      /**
       * The <code>name</code> of this <code>XSObject</code> depending on the
       * <code>XSObject</code> type.
       */
      @Override
      public String getName() {
          return null;
      }
  
      /**
       * The namespace URI of this node, or <code>null</code> if it is
       * unspecified.  defines how a namespace URI is attached to schema
       * components.
       */
      @Override
      public String getNamespace() {
          return null;
      }
  
      /**
       * {compositor} One of all, choice or sequence. The valid constants values
       * are: ALL, CHOICE, SEQUENCE.
       */
      @Override
      public short getCompositor() {
          if (fCompositor == MODELGROUP_CHOICE)
              return XSModelGroup.COMPOSITOR_CHOICE;
          else if (fCompositor == MODELGROUP_SEQUENCE)
              return XSModelGroup.COMPOSITOR_SEQUENCE;
          else
              return XSModelGroup.COMPOSITOR_ALL;
      }
  
      /**
       * {particles} A list of particles
       */
      @Override
      public XSObjectList getParticles() {
          return new XSObjectListImpl(fParticles, fParticleCount);
      }
  
      /**
       * Optional. Annotation.
       */
      @Override
      public XSAnnotation getAnnotation() {
          return (fAnnotations != null) ? (XSAnnotation) fAnnotations.item(0) : null;
      }
  
      /**
       * Optional. Annotations.
       */
      @Override
      public XSObjectList getAnnotations() {
          return (fAnnotations != null) ? fAnnotations : XSObjectListImpl.EMPTY_LIST;
      }
  
      /**
       * @see mf.org.apache.xerces.xs.XSObject#getNamespaceItem()
       */
      @Override
      public XSNamespaceItem getNamespaceItem() {
          return null;
      }
  
  } // class XSModelGroupImpl
  