<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    targetNamespace="http://www.pullreports.com/catalog-1.5.0"
    xmlns:pr="http://www.pullreports.com/catalog-1.5.0" elementFormDefault="qualified">

    <xs:element name="catalog">
      <xs:complexType>
        <xs:sequence>
          <xs:element ref="pr:access_control_voter" minOccurs="0" maxOccurs="1"/>
          <xs:element ref="pr:report" maxOccurs="unbounded"/>
          <xs:element ref="pr:column_group" minOccurs="0" maxOccurs="unbounded"/>
          <xs:element ref="pr:table" minOccurs="0" maxOccurs="unbounded"/>
          <xs:element ref="pr:global_label_value_list" minOccurs="0" maxOccurs="unbounded"/>
        </xs:sequence> 
        <xs:attribute name="id" use="required">
            <xs:simpleType>
              <xs:restriction base="xs:string">
                    <xs:pattern value="[A-Za-z0-9\-_]*"/>
              </xs:restriction>
            </xs:simpleType>
        </xs:attribute>
        <xs:attribute name="name" type="xs:string" use="required"/>
      </xs:complexType>
      <!--  report id's must be unique in the catalog. -->
      <xs:key name="reportKey">
        <xs:selector xpath="pr:report"/>
        <xs:field xpath="@id"/>
      </xs:key>
      <!--  id's of top level (immediate children of catalog) tables must be unique. -->
      <xs:key name="globalTableKey">
        <xs:selector xpath="pr:table"/>
        <xs:field xpath="@id"/>
      </xs:key>
      <!--  they are referenced by table_refs -->
      <xs:keyref name="globalTableKeyRef" refer="pr:globalTableKey">
          <xs:selector xpath=".//pr:table_ref"/>
          <xs:field xpath="@ref"/>
      </xs:keyref>
      <!--  id's of column_groups must be unique. -->
      <xs:key name="globalColumnGroupKey">
        <xs:selector xpath="pr:column_group"/>
        <xs:field xpath="@id"/>
      </xs:key>
      <!--  they are referenced by column_group_refs -->
      <xs:keyref name="globalColumnGroupKeyRef" refer="pr:globalColumnGroupKey">
          <xs:selector xpath=".//pr:column_group_ref"/>
          <xs:field xpath="@ref"/>
      </xs:keyref>
      <!--  id's of global_label_value_lists must be unique. -->
      <xs:key name="globalLabelValueListKey">
        <xs:selector xpath="pr:global_label_value_list"/>
        <xs:field xpath="@id"/>
      </xs:key>
      <!--  they are referenced by column globalLabelValueListRef(s)-->
      <xs:keyref name="globalLabelValueListKeyRef" refer="pr:globalLabelValueListKey">
          <xs:selector xpath=".//pr:global_label_value_list_ref"/>
          <xs:field xpath="@ref"/>
      </xs:keyref>
    </xs:element>

    <xs:element name="report">
      <xs:complexType>
          <xs:sequence>
              <xs:element ref="pr:description" minOccurs="0" maxOccurs="1"/>
              <xs:element ref="pr:access_control_voter" minOccurs="0" maxOccurs="1"/>
              <xs:element ref="pr:export_config" minOccurs="0" maxOccurs="1"/>
              <xs:choice>
                  <xs:element ref="pr:table" minOccurs="1" maxOccurs="1"/>
                  <xs:element ref="pr:table_ref" minOccurs="1" maxOccurs="1"/>
              </xs:choice>
          </xs:sequence>
          <xs:attribute name="id" use="required">
              <xs:simpleType>
                  <xs:restriction base="xs:string">
                        <xs:pattern value="[A-Za-z0-9\-_]*"/>
                  </xs:restriction>
              </xs:simpleType>
          </xs:attribute>
          <xs:attribute name="name" type="xs:string" use="required"/>
      </xs:complexType>
    </xs:element>

    <xs:element name="export_config">
      <xs:complexType>
          <xs:all>
              <xs:element ref="pr:kml" minOccurs="0" />
              <xs:element ref="pr:geojson" minOccurs="0" />
          </xs:all>
          <xs:attribute name="defaultSort" type="xs:string"/>
          <xs:attribute name="defaultColumns">
             <xs:simpleType>
                <xs:restriction base="xs:string">
                    <xs:minLength value="1"/>
                    <xs:pattern value="[A-Za-z0-9\-_,]*"/>
                </xs:restriction>
            </xs:simpleType>
          </xs:attribute>
      </xs:complexType>
    </xs:element>

    <xs:element name="kml">
      <xs:complexType>
          <xs:sequence>
              <xs:element name="placemark_name_template" type="xs:string" minOccurs="0" maxOccurs="1"/>
          </xs:sequence>
          <xs:attribute name="geometryColumnPath" type="xs:string" use="required"/>
      </xs:complexType>
    </xs:element>

    <xs:element name="geojson">
      <xs:complexType>
          <xs:attribute name="geometryColumnPath" type="xs:string" use="required"/>
      </xs:complexType>
    </xs:element>

    <xs:element name="table_ref">
      <xs:complexType>
          <xs:sequence>
              <xs:element ref="pr:description" minOccurs="0" maxOccurs="1"/>
              <xs:element ref="pr:pre_filter" minOccurs="0" maxOccurs="unbounded"/>
              <xs:element ref="pr:relationship" minOccurs="0" maxOccurs="unbounded"/>
          </xs:sequence>
          <xs:attribute name="ref" type="xs:Name" use="required"/>
          <xs:attribute name="id" type="xs:Name" use="required"/>
          <xs:attribute name="displayName" type="xs:string" />
      </xs:complexType>
      <xs:key name="tableRefKey">
        <xs:selector xpath="./pr:relationship/pr:table|./pr:relationship/pr:table_ref"/>
        <xs:field xpath="@id"/>
      </xs:key>
    </xs:element>

    <xs:element name="table">
      <xs:complexType>
          <xs:sequence>
              <xs:element ref="pr:description" minOccurs="0" maxOccurs="1"/>
              <xs:element ref="pr:subquery" minOccurs="0" maxOccurs="1"/>
              <xs:choice minOccurs="1" maxOccurs="unbounded">
                  <xs:element ref="pr:column"/>
                  <xs:element ref="pr:column_group_ref"/>
              </xs:choice>
              <xs:element ref="pr:pre_filter" minOccurs="0" maxOccurs="unbounded"/>
              <xs:element ref="pr:relationship" minOccurs="0" maxOccurs="unbounded"/>
          </xs:sequence>
          <xs:attribute name="id" type="xs:Name" use="required"/> <!-- >use="required"/-->
          <xs:attribute name="displayName" type="xs:string" use="required"/>
          <xs:attribute name="name" type="xs:string"/>
      </xs:complexType>
      <!--  id's must be unique within a column to support field restrictions -->
      <xs:key name="columnKey">
        <xs:selector xpath="./pr:column"/>
        <xs:field xpath="@id"/>
      </xs:key>
      <xs:key name="tableKey">
        <xs:selector xpath="./pr:relationship/pr:table|./pr:relationship/pr:table_ref"/>
        <xs:field xpath="@id"/>
      </xs:key>
    </xs:element>

    <xs:element name="column">
      <xs:complexType>
          <xs:sequence>
              <xs:element ref="pr:description" minOccurs="0" maxOccurs="1"/>
              <xs:element ref="pr:access_control_voter" minOccurs="0" maxOccurs="1"/>
              <xs:element ref="pr:output_transform" minOccurs="0" maxOccurs="1"/>
              <xs:element name="filter_column_transform" type="xs:string" minOccurs="0" maxOccurs="1"/>
              <xs:element name="filter_value_transform" type="xs:string" minOccurs="0" maxOccurs="1"/>
              <xs:element name="url_template" type="xs:string" minOccurs="0" maxOccurs="1"/>
              <xs:choice minOccurs="0" maxOccurs="1">
                  <xs:element ref="pr:global_label_value_list_ref" minOccurs="1" maxOccurs="1"/>
                  <xs:element ref="pr:label_value_list" minOccurs="1" maxOccurs="1"/>
              </xs:choice>
          </xs:sequence>

          <xs:attribute name="id" type="xs:Name" use="required" />
          <xs:attribute name="name" type="xs:string" use="required"/>
          <xs:attribute name="paramType" type="pr:jdbcType" default="java.lang.String"/>
          <xs:attribute name="displayName" type="xs:string" />
          <xs:attribute name="export" type="xs:boolean" default="true"/>
      </xs:complexType>
    </xs:element>

    <xs:simpleType name="jdbcType">
      <xs:restriction base="xs:string">
        <xs:enumeration value="java.lang.Boolean" />
        <xs:enumeration value="java.lang.Long" />
        <xs:enumeration value="java.sql.Date" />
        <xs:enumeration value="java.sql.Time" />
        <xs:enumeration value="java.sql.Timestamp" />
        <xs:enumeration value="java.lang.Double" />
        <xs:enumeration value="java.lang.Float" />
        <xs:enumeration value="java.lang.Integer" />
        <xs:enumeration value="java.lang.String" />
      </xs:restriction>
    </xs:simpleType>

    <xs:element name="column_group_ref">
      <xs:complexType>
          <xs:attribute name="ref" type="xs:Name" use="required"/>
      </xs:complexType>
    </xs:element>

    <xs:element name="column_group">
      <xs:complexType>
          <xs:sequence>
              <xs:element ref="pr:column" minOccurs="1" maxOccurs="unbounded"/>
          </xs:sequence>
          <xs:attribute name="id" type="xs:Name" use="required"/>
      </xs:complexType>
      <!--  column id's must be unique within a column group -->
      <xs:key name="columnGroupKey">
        <xs:selector xpath="./pr:column"/>
        <xs:field xpath="@id"/>
      </xs:key>
    </xs:element>

    <xs:element name="description">
      <xs:complexType>
         <xs:simpleContent>
            <xs:extension base="pr:nonWhitespace"/>
        </xs:simpleContent>
      </xs:complexType>
    </xs:element>

    <xs:element name="output_transform">
      <xs:complexType>
         <xs:simpleContent>
            <xs:extension base="xs:string">
              <xs:attribute name="applyToSort" type="xs:boolean" default="true"/>
            </xs:extension>
        </xs:simpleContent>
      </xs:complexType>
    </xs:element>

    <xs:element name="pre_filter">
      <xs:complexType>
         <xs:simpleContent>
            <xs:extension base="xs:string"/>
        </xs:simpleContent>
      </xs:complexType>
    </xs:element>

    <xs:element name="relationship">
      <xs:complexType>
          <xs:sequence>
              <xs:element ref="pr:access_control_voter" minOccurs="0" maxOccurs="1"/>
              <xs:choice>
                  <xs:element ref="pr:join_column" minOccurs="1" maxOccurs="unbounded"/>
                  <xs:element ref="pr:join_table" minOccurs="1" maxOccurs="1"/>
              </xs:choice>
              <xs:choice>
                  <xs:element ref="pr:table" minOccurs="1" maxOccurs="1"/>
                  <xs:element ref="pr:table_ref" minOccurs="1" maxOccurs="1"/>
              </xs:choice>
          </xs:sequence>
          <xs:attribute name="cardinality" type="pr:cardinality" default="many"/>
          <xs:attribute name="join" type="pr:joinType" default="left"/>
      </xs:complexType>
    </xs:element>

    <xs:simpleType name="joinType">
      <xs:restriction base="xs:string">
        <xs:enumeration value="left" />
        <xs:enumeration value="inner" />
      </xs:restriction>
    </xs:simpleType>

    <xs:simpleType name="cardinality">
      <xs:restriction base="xs:string">
        <xs:enumeration value="one" />
        <xs:enumeration value="many" />
      </xs:restriction>
    </xs:simpleType>
    
    <xs:element name="join_column">
      <xs:complexType>
          <xs:attribute name="columnName" type="xs:string" use="required"/>
          <xs:attribute name="referencedColumnName" type="xs:string" use="required"/>
          <xs:attribute name="referencedTablePath" type="xs:string" />
      </xs:complexType>
    </xs:element>

    <xs:element name="join_table">
      <xs:complexType>
          <xs:sequence>
              <xs:element ref="pr:join_columns" minOccurs="1" maxOccurs="1"/>
              <xs:element ref="pr:inverse_join_columns" minOccurs="1" maxOccurs="1"/>
          </xs:sequence>
          <xs:attribute name="name" type="xs:string" use="required"/>
      </xs:complexType>
    </xs:element>

    <xs:element name="join_columns">
      <xs:complexType>
          <xs:sequence>
              <xs:element ref="pr:join_column" minOccurs="1" maxOccurs="unbounded"/>
          </xs:sequence>
      </xs:complexType>
    </xs:element>

    <xs:element name="inverse_join_columns">
      <xs:complexType>
          <xs:sequence>
              <xs:element ref="pr:join_column" minOccurs="1" maxOccurs="unbounded"/>
          </xs:sequence>
      </xs:complexType>
    </xs:element>

    <xs:element name="global_label_value_list">
      <xs:complexType>
          <xs:choice>
              <xs:element ref="pr:label_value_query" minOccurs="1" maxOccurs="1"/>
              <xs:element ref="pr:label_values" minOccurs="1" maxOccurs="1"/>
          </xs:choice>
          <xs:attribute name="id" type="xs:Name" use="required"/>
      </xs:complexType>
    </xs:element>

    <xs:element name="global_label_value_list_ref">
      <xs:complexType>
          <xs:attribute name="ref" type="xs:Name" use="required"/>
      </xs:complexType>
    </xs:element>

    <xs:element name="label_value_list">
      <xs:complexType>
          <xs:choice>
              <xs:element ref="pr:label_value_query" minOccurs="1" maxOccurs="1"/>
              <xs:element ref="pr:label_value_query_default" minOccurs="1" maxOccurs="1"/>
              <xs:element ref="pr:label_values" minOccurs="1" maxOccurs="1"/>
          </xs:choice>
      </xs:complexType>
    </xs:element>

    <xs:element name="label_value_query">
      <xs:complexType>
        <xs:simpleContent>
           <xs:extension base="pr:nonWhitespace">
             <xs:attribute name="labelColumn" type="xs:string" default="label"/>
             <xs:attribute name="valueColumn" type="xs:string" default="value"/>
             <xs:attribute name="groupColumn" type="xs:string"/>
           </xs:extension>
        </xs:simpleContent>
        </xs:complexType>
    </xs:element>

    <xs:element name="label_value_query_default">
      <xs:complexType></xs:complexType>
    </xs:element>

    <xs:element name="label_values">
      <xs:complexType>
        <xs:choice minOccurs="1" maxOccurs="unbounded">
            <xs:element ref="pr:label_value_group"/>
            <xs:element ref="pr:label_value"/>
        </xs:choice>
      </xs:complexType>
    </xs:element>

    <xs:element name="label_value_group">
      <xs:complexType>
        <xs:sequence>
          <xs:element ref="pr:label_value" minOccurs="1" maxOccurs="unbounded"/>
        </xs:sequence>
        <xs:attribute name="label" type="xs:string" use="required"/>
      </xs:complexType>
    </xs:element>

    <xs:element name="label_value">
      <xs:complexType>
        <xs:simpleContent>
           <xs:extension base="xs:string">
              <xs:attribute name="value" type="xs:string" use="required"/>
           </xs:extension>
        </xs:simpleContent>
      </xs:complexType>
    </xs:element>

    <xs:element name="subquery">
      <xs:complexType mixed='true'>
        <xs:sequence>
           <xs:element ref="pr:description" minOccurs="0" maxOccurs="1"/>
         </xs:sequence>
          <xs:attribute name="provider" type="xs:string" />
      </xs:complexType>
    </xs:element>

    <xs:element name="access_control_voter">
      <xs:complexType>
        <xs:simpleContent>
           <xs:extension base="xs:string">
              <xs:attribute name="voter" type="xs:string" use="required"/>
           </xs:extension>
        </xs:simpleContent>
      </xs:complexType>
    </xs:element>

    <xs:simpleType name="nonWhitespace">  
        <xs:restriction base="xs:string">  
          <xs:minLength value="1" />
          <xs:pattern value="(\s*[^\s]\s*)+"></xs:pattern>
        </xs:restriction>  
    </xs:simpleType>

</xs:schema>
