<?xml version="1.0" encoding="UTF-8"?>
<!--

    Copyright (c) 1997, 2021 Oracle and/or its affiliates. All rights reserved.

    This program and the accompanying materials are made available under the
    terms of the Eclipse Distribution License v. 1.0, which is available at
    http://www.eclipse.org/org/documents/edl-v10.php.

    SPDX-License-Identifier: BSD-3-Clause

-->

<grammar
  ns="http://www.w3.org/2001/XMLSchema"
  xmlns:cc="http://www.xml.gr.jp/xmlns/relaxngcc"
  xmlns="http://relaxng.org/ns/structure/1.0"
  datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"
  >



  <define name="complexType"
    cc:return-type="ComplexTypeImpl" cc:return-value="result">
    <cc:java-body>
      private ComplexTypeImpl result;
      private Ref.Type baseType;
      private Ref.ContentType contentType;
      
      // local variables for simpleContent/restriction
      private Ref.SimpleType baseContentType;
      private RestrictionSimpleTypeImpl contentSimpleType;
      
      private Locator locator,locator2;
      
      private static class BaseContentSimpleTypeRef implements Ref.SimpleType {
        private final Ref.Type baseType;
        private BaseContentSimpleTypeRef(Ref.Type _baseType ) { this.baseType = _baseType; }
        public XSSimpleType getType() {
          return (XSSimpleType)((XSComplexType)baseType.getType()).getContentType();
        }
      }
      
    </cc:java-body>
    
    <element name="complexType">
      <cc:java>locator = $runtime.copyLocator();</cc:java>
      <optional>
        <attribute name="abstract">
          <data type="boolean" cc:alias="abstractValue" />
        </attribute>
      </optional>
      <optional>
        <attribute name="block">
          <ref name="erSet" cc:alias="blockValue"/>
        </attribute>
      </optional>
      <optional>
        <attribute name="final">
          <ref name="erSet" cc:alias="finalValue"/>
        </attribute>
      </optional>
      <!--optional>
        <attribute name="ID">
          <data type="ID"/>
        </attribute>
      </optional-->
      <optional>
        <attribute name="mixed">
          <data type="boolean" cc:alias="mixedValue"/>
        </attribute>
      </optional>
      <optional>
        <attribute name="name">
          <data type="NCName" cc:alias="name" />
        </attribute>
      </optional>
      fa = <ref name="foreignAttributes"/>(fa);
      <optional>
        <ref name="annotation" cc:alias="annotation"/>(null,AnnotationContext.COMPLEXTYPE_DECL);
      </optional>
      
      <!-- body of the complex type -->
      <choice>
        <element name="simpleContent">
          <!--optional>
            <attribute name="ID">
              <data type="ID"/>
            </attribute>
          </optional-->
          fa = <ref name="foreignAttributes"/>(fa);
          <optional>
            annotation = <ref name="annotation"/>(annotation,AnnotationContext.COMPLEXTYPE_DECL);
          </optional>
          <choice>
            <!-- simpleContent/restriction -->
            <element name="restriction">
              <cc:java>locator2 = $runtime.copyLocator();</cc:java>
              <attribute name="base">
                <ref name="qname" cc:alias="baseTypeName"/>
                <cc:java>
                  baseType = new DelayedRef.Type(
                    $runtime, locator2, $runtime.currentSchema, baseTypeName );
                </cc:java>
              </attribute>
              <!--optional>
                <attribute name="ID">
                  <data type="ID"/>
                </attribute>
              </optional-->
              fa = <ref name="foreignAttributes"/>(fa);
              <optional>
                annotation = <ref name="annotation"/>(annotation,AnnotationContext.COMPLEXTYPE_DECL);
              </optional>
              <optional>
                <ref name="simpleType" cc:alias="baseContentType"/>
              </optional>
              <cc:java>
                if(baseContentType==null) {
                  // contentType of the base type, which must be a complex type
                  baseContentType = new BaseContentSimpleTypeRef(baseType);
                }
                
                contentSimpleType = new RestrictionSimpleTypeImpl(
                  $runtime.document, null/*?*/, locator2, null,
                  null, true, Collections.EMPTY_SET, baseContentType );
                contentType = contentSimpleType;
              </cc:java>
              <zeroOrMore>
                <ref name="facet" cc:alias="facet"/>
                <cc:java>contentSimpleType.addFacet(facet);</cc:java>
              </zeroOrMore>
              <cc:java>
                makeResult(XSType.RESTRICTION);
                result.setContentType(contentType);
              </cc:java>
              <ref name="attributeUses" cc:with-params="result" />
            </element>
            
            <!-- simpleContent/extension -->
            <element name="extension">
              <cc:java>locator2 = $runtime.copyLocator();</cc:java>
              <attribute name="base">
                <ref name="qname" cc:alias="baseTypeName"/>
                <cc:java>
                  baseType = new DelayedRef.Type(
                    $runtime, locator2, $runtime.currentSchema, baseTypeName );
                </cc:java>
              </attribute>
              <!--optional>
                <attribute name="ID">
                  <data type="ID"/>
                </attribute>
              </optional-->
              fa = <ref name="foreignAttributes"/>(fa);
              <optional>
                annotation = <ref name="annotation"/>(annotation,AnnotationContext.COMPLEXTYPE_DECL);
              </optional>
              <cc:java>
                contentType = new BaseContentRef($runtime,baseType);
                makeResult(XSType.EXTENSION);
                result.setContentType(contentType);
              </cc:java>
              <ref name="attributeUses" cc:with-params="result" />
            </element>
          </choice>
        </element>
        <element name="complexContent">
          <!--optional>
            <attribute name="ID">
              <data type="ID"/>
            </attribute>
          </optional-->
          <optional>
            <attribute name="mixed">
              <data type="boolean" cc:alias="mixedValue"/>
            </attribute>
          </optional>
          fa = <ref name="foreignAttributes"/>(fa);
          <optional>
            annotation = <ref name="annotation"/>(annotation,AnnotationContext.COMPLEXTYPE_DECL);
          </optional>
          <choice>
            <!-- complexContent/restriction -->
            <element name="restriction">
              <cc:java>locator2 = $runtime.copyLocator();</cc:java>
              <attribute name="base">
                <ref name="qname" cc:alias="baseTypeName"/>
                <cc:java>
                  baseType = new DelayedRef.Type(
                    $runtime, locator2, $runtime.currentSchema, baseTypeName );
                  makeResult(XSType.RESTRICTION);
                </cc:java>
              </attribute>
              <!--optional>
                <attribute name="ID">
                  <data type="ID"/>
                </attribute>
              </optional-->
              fa = <ref name="foreignAttributes"/>(fa);
              <optional>
                annotation = <ref name="annotation"/>(annotation,AnnotationContext.COMPLEXTYPE_DECL);
              </optional>
              <ref name="complexType_complexContent_body"
                cc:alias="explicitContent" cc:with-params="result" />
              <cc:java>
                result.setContentType(explicitContent);
              </cc:java>
            </element>
            <!-- complexContent/extension -->
            <element name="extension">
              <cc:java>locator2 = $runtime.copyLocator();</cc:java>
              <attribute name="base">
                <ref name="qname" cc:alias="baseTypeName"/>
                <cc:java>
                  baseType = new DelayedRef.Type(
                    $runtime, locator2, $runtime.currentSchema, baseTypeName );
                  makeResult(XSType.EXTENSION);
                </cc:java>
              </attribute>
              <!--optional>
                <attribute name="ID">
                  <data type="ID"/>
                </attribute>
              </optional-->
              fa = <ref name="foreignAttributes"/>(fa);
              <optional>
                annotation = <ref name="annotation"/>(annotation,AnnotationContext.COMPLEXTYPE_DECL);
              </optional>
              <ref name="complexType_complexContent_body"
                cc:alias="explicitContent" cc:with-params="result" />
              <cc:java>
                result.setExplicitContent(explicitContent);
                result.setContentType(
                  buildComplexExtensionContentModel(explicitContent));
              </cc:java>
            </element>
          </choice>
        </element>
        
        <!-- restriction from anyType -->
        <group>
          <cc:java>
            baseType = $runtime.parser.schemaSet.anyType;
            makeResult(XSType.RESTRICTION);
          </cc:java>
          <ref name="complexType_complexContent_body"
            cc:alias="explicitContent" cc:with-params="result"/>
          <cc:java>
            result.setContentType(explicitContent);
          </cc:java>
        </group>
      </choice>
    </element>
    <cc:java-body>
      // baseType and contentType must be computed before calling this method.
      private void makeResult( int derivationMethod ) {
      
        if(finalValue==null)
          finalValue = $runtime.finalDefault;
        if(blockValue==null)
          blockValue = $runtime.blockDefault;
        
        result = new ComplexTypeImpl(
            $runtime.document,
            annotation,
            locator,
            fa,
            name,
            name==null,
            $runtime.parseBoolean(abstractValue),
            derivationMethod,
            baseType,
            finalValue,
            blockValue,
            $runtime.parseBoolean(mixedValue)
        );
      }
      
      // I had to make them static inner classes (as opposed to anonymous ones),
      // so that they will not keep references to parser.
      
      private static class BaseComplexTypeContentRef implements Ref.ContentType {
        private final Ref.Type baseType;
        private BaseComplexTypeContentRef(Ref.Type _baseType) { this.baseType = _baseType; }
        public XSContentType getContentType() {
            return ((XSComplexType)baseType.getType()).getContentType();
        }
      }
      private static class InheritBaseContentTypeRef implements Ref.ContentType {
        private final Ref.Type baseType;
        private final XSContentType empty;
        private final XSContentType expContent;
        private final SchemaDocumentImpl currentDocument;
        private InheritBaseContentTypeRef(
          Ref.Type _baseType,XSContentType _explicitContent,NGCCRuntimeEx $runtime) {
          
          this.baseType = _baseType;
          this.currentDocument = $runtime.document;
          expContent = _explicitContent;
          this.empty = $runtime.parser.schemaSet.empty;
        }
          public XSContentType getContentType() {
              XSContentType baseContentType = 
                  ((XSComplexType)baseType.getType()).getContentType();
              if(baseContentType==empty)
                  return expContent;
              else
                  return new ParticleImpl( currentDocument, null, new ModelGroupImpl(
                    currentDocument,
                      null, null, null, XSModelGroup.SEQUENCE,
                      new ParticleImpl[]{
                          (ParticleImpl)baseContentType,
                          (ParticleImpl)expContent}), null );
          }
      };
      
      private Ref.ContentType buildComplexExtensionContentModel( XSContentType explicitContent ) {
        
        if(explicitContent==$runtime.parser.schemaSet.empty)
          return new BaseComplexTypeContentRef(baseType);
        else
          return new InheritBaseContentTypeRef(baseType,explicitContent,$runtime);
      }
    </cc:java-body>
  </define>
  
  
  
  <define name="complexType_complexContent_body"
    cc:params="AttributesHolder owner"
    cc:return-type="ContentTypeImpl" cc:return-value="particle">
    
    <cc:java-body>
      private ContentTypeImpl particle;
    </cc:java-body>
    <optional>
      <ref name="particle" cc:alias="particle"/>
    </optional>
    <ref name="attributeUses" cc:with-params="owner" />
    if(particle==null)
 	  particle = $runtime.parser.schemaSet.empty;
  </define>


</grammar>
