<?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="elementDeclBody"
    cc:params="Locator locator, boolean isGlobal"
    cc:return-type="ElementDecl" cc:return-value="makeResult()">
    
    <!--
      the isGlobal flag indicates whether this element declaration
      is global or not
    -->
    <cc:java-body>
      private boolean form;
      private boolean formSpecified;
      private Ref.Type type;
      private List idcs = new ArrayList();  // identity constraints

      private DelayedRef.Element substHeadRef;
      
      private ElementDecl makeResult() {
        if(finalValue==null)
          finalValue = new Integer($runtime.finalDefault);
        if(blockValue==null)
          blockValue = new Integer($runtime.blockDefault);
        
        if(!formSpecified)
          form = $runtime.elementFormDefault;
        if(isGlobal)  // global elements are always qualified
          form = true;
        
        String tns;
        if(form)    tns = $runtime.currentSchema.getTargetNamespace();
        else        tns = "";
        
        if( type==null ) {
        	if( substHeadRef!=null )
        		type = new SubstGroupBaseTypeRef(substHeadRef);
        	else
        		type = $runtime.parser.schemaSet.anyType;
        }
        
        ElementDecl ed = new ElementDecl(
            $runtime,
            $runtime.document,
            annotation,
            locator,
            fa,
            tns,
            name,
            !isGlobal,
            $runtime.createXmlString(defaultValue),
            $runtime.createXmlString(fixedValue),
            $runtime.parseBoolean(nillable),
            $runtime.parseBoolean(abstractValue),
            (java.lang.Boolean)(formSpecified ? form : null),
            type,
            substHeadRef,
            blockValue.intValue(),
            finalValue.intValue(),
            idcs);
        
        // if this element has anonymous complex type, it will be set here.
        if(type instanceof ComplexTypeImpl)
          ((ComplexTypeImpl)type).setScope(ed);
        return ed;
      }
    </cc:java-body>
    
    fa = <ref name="foreignAttributes"/>(fa);
    <optional>
      <attribute name="abstract">
        <data type="boolean" cc:alias="abstractValue"/>
      </attribute>
    </optional>
    <optional>
      <attribute name="block">
        <ref name="ersSet" cc:alias="blockValue"/>
      </attribute>
    </optional>
    <optional>
      <attribute name="final">
        <ref name="erSet" cc:alias="finalValue" />
      </attribute>
    </optional>
    <optional>
      <attribute name="default">
        <text cc:alias="defaultValue"/>
      </attribute>
    </optional>
    <optional>
      <attribute name="fixed">
        <text cc:alias="fixedValue"/>
      </attribute>
    </optional>
    <optional>
      <attribute name="form">
        <ref name="qualification" cc:alias="form" />
        formSpecified = true;
      </attribute>
    </optional>
    <!--optional>
      <attribute name="ID">
        <data type="ID"/>
      </attribute>
    </optional-->
    <attribute name="name">
      <data type="NCName" cc:alias="name"/>
    </attribute>
    <optional>
      <attribute name="nillable">
        <data type="boolean" cc:alias="nillable" />
      </attribute>
    </optional>
    <optional>
      <attribute name="substitutionGroup">
        <ref name="qname" cc:alias="substRef" />
        <cc:java>
          substHeadRef = new DelayedRef.Element(
            $runtime, locator, $runtime.currentSchema, substRef );
        </cc:java>
      </attribute>
    </optional>
    
    <optional>
      <ref name="annotation" cc:alias="annotation"/>(null,AnnotationContext.ELEMENT_DECL);
    </optional>
    
    <!-- type of the element -->
    <optional>
      <choice>
        <ref name="simpleType" cc:alias="type"/>
        <ref name="complexType" cc:alias="type"/>
        <group>
          <attribute name="type">
            <ref name="qname" cc:alias="typeName"/>
          </attribute>
          <cc:java>
            type = new DelayedRef.Type(
              $runtime, locator, $runtime.currentSchema, typeName );
          </cc:java>
        </group>
      </choice>
    </optional>
    <zeroOrMore>
      idc = <ref name="identityConstraint"/>
      idcs.add(idc);
    </zeroOrMore>
  </define>
  
  <!-- TODO -->
  <define name="identityConstraint"
    cc:return-type="IdentityConstraintImpl" cc:return-value="makeResult()">
    <cc:java-body>
      private short category;
      private List fields = new ArrayList();
      private XPathImpl selector;
      private DelayedRef.IdentityConstraint refer = null;

      private IdentityConstraintImpl makeResult() {
        return new IdentityConstraintImpl($runtime.document,ann,$runtime.copyLocator(),fa,
          category,name,selector,fields,refer);
      }
    </cc:java-body>
    <element>
      <choice>
        <name>key</name>
        <name>keyref</name>
        <name>unique</name>
      </choice>

      if($localName.equals("key"))
        category = XSIdentityConstraint.KEY;
      else
      if($localName.equals("keyref"))
        category = XSIdentityConstraint.KEYREF;
      else
      if($localName.equals("unique"))
        category = XSIdentityConstraint.UNIQUE;


      fa = <ref name="foreignAttributes"/>(null);
      name = <attribute name="name" />
      <optional>
        <attribute name="refer">
          ref = <ref name="qname" />
          <cc:java>
            refer = new DelayedRef.IdentityConstraint(
              $runtime, $runtime.copyLocator(), $runtime.currentSchema, ref );
          </cc:java>
        </attribute>
      </optional>

      <optional>
        ann = <ref name="annotation"/>(null,AnnotationContext.IDENTITY_CONSTRAINT);
      </optional>
      <element name="selector">
        selector = <ref name="xpath" />
      </element>
      <oneOrMore>
        <element name="field">
          field = <ref name="xpath" />
          fields.add(field);
        </element>
      </oneOrMore>
    </element>
  </define>
  
  <define name="xpath"
    cc:return-type="XPathImpl" cc:return-value="makeResult()">
    <cc:java-body>
      private XPathImpl makeResult() {
        return new XPathImpl($runtime.document,ann,$runtime.copyLocator(),fa,
          $runtime.createXmlString(xpath));
      }
    </cc:java-body>

    fa = <ref name="foreignAttributes"/>(null);
    xpath = <attribute name="xpath" /> 
    <optional>
      ann = <ref name="annotation"/>(null,AnnotationContext.XPATH);
    </optional>
  </define>
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  <define name="erSet" cc:return-type="Integer" cc:return-value="makeResult()">
    <cc:java-body>
      private Integer makeResult() {
        if(v==null)     return new Integer($runtime.finalDefault);
        
        if(v.indexOf("#all")!=-1)
            return new Integer(XSType.EXTENSION|XSType.RESTRICTION);
        
        int r = 0;
        
        if(v.indexOf("extension")!=-1)      r|=XSType.EXTENSION;
        if(v.indexOf("restriction")!=-1)    r|=XSType.RESTRICTION;
        
        return new Integer(r);
      }
    </cc:java-body>
    
    <text cc:alias="v"/>
    
    <!--choice>
      <value>#all</value>
      <list>
        <choice>
          <value>extension</value>
          <value>restriction</value>
        </choice>
      </list>
    </choice-->
  </define>
  
  
  <define name="ersSet" cc:return-type="Integer" cc:return-value="makeResult()">
    <cc:java-body>
      private Integer makeResult() {
        if(v==null)     return new Integer($runtime.blockDefault);
        
        if(v.indexOf("#all")!=-1)
            return new Integer(
              XSType.EXTENSION|XSType.RESTRICTION|XSType.SUBSTITUTION);
        
        int r = 0;
        
        if(v.indexOf("extension")!=-1)      r|=XSType.EXTENSION;
        if(v.indexOf("restriction")!=-1)    r|=XSType.RESTRICTION;
        if(v.indexOf("substitution")!=-1)   r|=XSType.SUBSTITUTION;
        
        return new Integer(r);
      }
    </cc:java-body>
    <text cc:alias="v"/>
    <!--choice>
      <value>#all</value>
      <list>
        <choice>
          <value>extension</value>
          <value>restriction</value>
          <value>substitution</value>
        </choice>
      </list>
    </choice-->
  </define>
  
  
</grammar>
