<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="ul:rules"
    elementFormDefault="qualified"
    xmlns="ul:rules"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
>

  <xs:element name="rules">
    <xs:complexType>
      <xs:sequence minOccurs="0" maxOccurs="unbounded">
        <xs:element name="rule" type="ruleType"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

  <!-- rule type definition -->
  <xs:complexType name="ruleType">
    <xs:sequence>
      <xs:element name="msg" type="msgType" minOccurs="0" maxOccurs="unbounded"/>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element name="genMsg" type="genMsgType"/>
        <xs:element name="genMsgSeq" type="genMsgSeqType"/>
      </xs:choice>
      <xs:element name="idinfo" type="varType" minOccurs="0" maxOccurs="1"/>
    </xs:sequence>
    <xs:attribute name="name" type="xs:string" use="optional"/>
  </xs:complexType>

  <!-- message type definition -->
  <xs:complexType name="msgType">
    <xs:sequence minOccurs="0" maxOccurs="1">
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element name="equals" type="equalsType"/>
        <xs:element name="equalsSeq" type="equalsSeqType"/>
      </xs:choice>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element name="store" type="storeType"/>
        <xs:element name="storeSeq" type="storeSeqType"/>
      </xs:choice>
    </xs:sequence>
    <xs:attribute name="type" type="xs:int" use="required"/>
    <!-- problem: should be strings like WM_LBUTTONDOWN, but program needs ints -->
    <!--<xs:attribute name="type" type="xs:string" use="required"/>-->
    <xs:attribute name="multiple" type="xs:boolean" use="optional"/>
  </xs:complexType>
  
  <!-- storage types for message nodes -->
  <!-- a restriction forbidding "this" would be nice -->
  <xs:complexType name="storeType">
    <xs:sequence>
      <xs:element name="resolveHwnd" type="resolveTargetType" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
    <xs:attribute name="var" use="required" type="storVarName"/>
  </xs:complexType>
  <xs:complexType name="storeSeqType">
    <xs:sequence>
      <xs:element name="resolveHwnd" type="resolveTargetType" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
    <xs:attribute name="varSeq" use="required" type="storVarName"/>
  </xs:complexType>
  <xs:complexType name="resolveTargetType">
    <xs:attribute name="param" type="xs:string"/>
    <xs:attribute name="storeParam" type="xs:string"/>
  </xs:complexType>
  
  <!-- equals type for message nodes -->
  <xs:complexType name="equalsType">
    <xs:sequence minOccurs="2" maxOccurs="2">
      <xs:group ref="valueGroup"/>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="equalsSeqType">
    <xs:sequence>
      <xs:element name="seqValue" type="seqValueType"/>
      <xs:choice>
        <xs:group ref="seqValueGroup"/>
      </xs:choice>
    </xs:sequence>
  </xs:complexType>

  <!-- types for generating messages -->
  <xs:complexType name="genMsgType">
    <xs:choice>
      <xs:sequence>
        <xs:element name="type" type="varType"/>
        <xs:element name="target" type="varType"/>
        <xs:element name="LPARAM" type="PARAMtype" minOccurs="0" maxOccurs="1"/>
        <xs:element name="WPARAM" type="PARAMtype" minOccurs="0" maxOccurs="1"/>
      </xs:sequence>
      <xs:element name="storedVar">
        <xs:complexType>
          <xs:attribute name="obj" type="xs:string"/>
        </xs:complexType>
      </xs:element>
    </xs:choice>
    <xs:attribute name="delay" type="xs:int" use="required"/>
  </xs:complexType>
  <xs:complexType name="genMsgSeqType">
    <xs:choice>
      <xs:sequence>
        <xs:element name="type" type="seqType"/>
        <!-- target must be a variable! -->
        <xs:element name="target">
          <xs:complexType >
            <xs:sequence>
              <xs:element name="seqValue" type="seqValueType"/>
            </xs:sequence>
          </xs:complexType>
        </xs:element>        
        <xs:element name="LPARAM" type="seqPARAMtype" minOccurs="0" maxOccurs="1"/>
        <xs:element name="WPARAM" type="seqPARAMtype" minOccurs="0" maxOccurs="1"/>
      </xs:sequence>
      <xs:element name="storedSeqVar">
        <xs:complexType>
          <xs:attribute name="seqObj" type="xs:string"/>
        </xs:complexType>
      </xs:element>
    </xs:choice>
    <xs:attribute name="delay" type="xs:int" use="required"/>
  </xs:complexType>

  <xs:complexType name="PARAMtype">
    <xs:choice>
      <xs:group ref="valueGroup"/>
      <xs:sequence>
        <xs:element name="LOWORD" type="varType"/>
        <xs:element name="HIWORD" type="varType"/>
      </xs:sequence>
    </xs:choice>
  </xs:complexType>
  
  <xs:complexType name="seqPARAMtype">
    <xs:choice>
      <xs:group ref="seqValueGroup"/>
      <xs:sequence>
        <xs:element name="LOWORD" type="seqType"/>
        <xs:element name="HIWORD" type="seqType"/>
      </xs:sequence>
    </xs:choice>
  </xs:complexType>
  
  
  <xs:complexType name="seqValueType">
    <xs:attribute name ="seqObj" type="xs:string" use="required"/>
    <xs:attribute name ="param" type="xs:string" use="required"/>
  </xs:complexType>

  <!-- values that can be used by equals and genMsg nodes -->
  <xs:group name="valueGroup">
    <xs:choice>
      <xs:element name="paramValue" type="paramValueType"/>
      <xs:element name="constValue" type="constValueType"/>
      <xs:element name="winInfoValue" type ="winInfoValueType"/>
      <xs:element name="msgInfoValue" type="msgInfoType"/>
    </xs:choice>
  </xs:group>
  <xs:complexType name="varType">
    <xs:group ref="valueGroup"/>
  </xs:complexType>
  
  <xs:group name="seqValueGroup">
    <xs:choice>
      <xs:element name="constValue" type="constValueType"/>
      <xs:element name="seqValue" type="seqValueType"/>
    </xs:choice>
  </xs:group>
  <xs:complexType name="seqType">
    <xs:group ref="seqValueGroup"/>
  </xs:complexType>
  
  <xs:complexType name="paramValueType">
    <xs:attribute name="obj" type="xs:string" use="required"/>
    <xs:attribute name="param" type="xs:string" use="required"/>
  </xs:complexType>
  <xs:complexType name="constValueType">
    <xs:attribute name="value" use="required"/>
  </xs:complexType>
  <xs:complexType name="winInfoValueType">
    <xs:attribute name="obj" type="xs:string" use="required"/>
    <xs:attribute name="winParam" type="winParamType" use="required"/>
  </xs:complexType>
  <xs:complexType name="msgInfoType">
    <xs:attribute name="obj" type="xs:string" use="required"/>
    <xs:attribute name="msgParam" type="msgParamType" use="required"/>
  </xs:complexType>
  <xs:simpleType name="winParamType">
    <xs:restriction base="xs:string">
      <xs:enumeration value="class"/>
      <xs:enumeration value="resourceId"/>
      <xs:enumeration value="hwnd"/>
      <xs:enumeration value="parentTarget"/>
      <xs:enumeration value="parentClass"/>
    </xs:restriction>
  </xs:simpleType>
  <xs:simpleType name="msgParamType">
    <xs:restriction base="xs:string">
      <xs:enumeration value="type"/>
      <xs:enumeration value="target"/>
    </xs:restriction>
  </xs:simpleType>
  

  <xs:simpleType name="storVarName">
    <xs:restriction base="xs:string">
      <!-- this regex is formally not supported by XMLSchema, als look-arounds and \b are not supported :/ -->
      <xs:pattern value="(?:(?!(?>\bthis\b))\w)+"/>
    </xs:restriction>
  </xs:simpleType>
</xs:schema>
