<?xml version="1.0" encoding="UTF-8"?>
<!-- This is a validating schematron file for the mobyle service       -->
<!-- definitions, heavily inspired by existing python-based            -->
<!-- validators from Bertrand Néron and Nicolas Joly 			       -->
<!--                                                			       -->
<!-- Author: Hervé Ménager					             		       -->
<!-- 'Biological Software and Databases' Group, Institut Pasteur, Paris.  		-->
<!-- Distributed under LGPLv2 Licence. Please refer to the COPYING.LIB document.-->
<schema xmlns="http://purl.oclc.org/dsdl/schematron" >
     <pattern id="check_program">
          <rule context="program">
       	   	   <let name="commandElementsCount" value="./head/command"/>
       	   	   <let name="iscommandParametersCount" value="count(.//parameter[@iscommand='1' and not(precond) and not(ancestor::paragraph/precond)])"/>
       	   	   <let name="stdoutParametersCount" value="count(.//parameter[@isstdout='1' and not(precond) and not(ancestor::paragraph/precond)])"/>
       	   	   <let name="stderrParametersCount" value="count(.//parameter[@isstderr='1' and not(precond) and not(ancestor::paragraph/precond)])"/>
               <assert test="not(count(.//parameter[@iscommand='1'])=1 and $commandElementsCount=1)">
               A program cannot contain both a command element and an iscommand parameter
               </assert>
               <assert test="not($iscommandParametersCount=0 and $commandElementsCount=0)">
               A program has to contain one command element or one iscommand parameter:
               (<value-of select="$iscommandParametersCount"/> iscommand parameters, 
               <value-of select="$commandElementsCount"/> command elements)
               </assert>
               <assert test="$iscommandParametersCount &lt;= 1">
               	Only one parameter can be iscommand if no precond specified (current number in document: <value-of select="$iscommandParametersCount"/>)
               </assert>
               <assert test="$stdoutParametersCount &lt;= 1">
               	Only one parameter can link to standard output if no precond specified (current number in document: <value-of select="$stdoutParametersCount"/>)
               </assert>
               <assert test="$stderrParametersCount &lt;= 1">
               	Only one parameter can link to standard error if no precond specified (current number in document: <value-of select="$stderrParametersCount"/>)
               </assert>
          </rule>
          <rule context="program/head/name">
           	   <assert test="not($fileNameParameter) or concat(text(),'.xml')=$fileNameParameter">
               Inconsistency between file name (<value-of select="$fileNameParameter"/>) and name value (<value-of select="text()"/>).
          	   </assert>
    	  </rule>          
     	<rule context="workflow">
     		<assert test="count(.//parameter[@isout])>0">
     			At least one output parameter must be specified in the workflow.
     		</assert>
     	</rule>
     	<rule context="workflow//parameter">
     		<let name="parameter_id" value="@id"/>
     		<assert test="@id">
     			An id attribute must be specified for workflow parameters, missing in parameter "<value-of select="name/text()"/>".
     		</assert>
     		<assert test="not(@isstdout)">
     		  Workflow parameter "<value-of select="name/text()"/>" cannot be @isstdout, if it is an output please use @isout.
     		</assert>
     		<assert test="//link[(@toParameter=$parameter_id and not(@toTask)) or (@fromParameter=$parameter_id and not(@fromTask))]">
     			The workflow parameter "<value-of select="name/text()"/>" is not used in any link.
     		</assert>
     	</rule>
     	<rule context="workflow//link">
     		<let name="linkString" value="concat(@fromTask,':',@fromParameter,'->',@toTask,':',@toParameter)" />
     		<assert test="@fromTask or //parameter[@id=current()/@fromParameter]">
     			The source parameter id "<value-of select="@fromParameter" />" for the link "<value-of select="$linkString" />" does not exist.
     		</assert>
     		<assert test="@toTask or //parameter[@id=current()/@toParameter]">
     			The target parameter id "<value-of select="@toParameter" />" for the link "<value-of select="$linkString" />" does not exist.
     		</assert>
     	</rule>
     	<rule context="parameter/name">
     		<let name="reservedWords" value="'|acceptCharset|action|autocomplete|elements|encoding|enctype|length|method|name|noValidate|checkValidity|dispatchFormChange|dispatchFormInput|item|namedItem|submit|reset|attributes|baseURI|baseURIObject|childElementCount|childNodes|children|classList|className|clientHeight|clientLeft|clientTop|clientWidth|contentEditable|dataset|dir|firstChild|firstElementChild|id|innerHTML|isContentEditable|lang|lastChild|lastElementChild|localName|name|namespaceURI|nextSibling|nextElementSibling|nodeName|nodePrincipal|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|ownerDocument|parentNode|prefix|previousSibling|previousElementSibling|schemaTypeInfo|scrollHeight|scrollLeft|scrollTop|scrollWidth|spellcheck|style|tabIndex|tagName|textContent|title|addEventListener|appendChild|blur|click|cloneNode|compareDocumentPosition|dispatchEvent|focus|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getElementsByTagName|getElementsByTagNameNS|getFeature|getUserData|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|insertBefore|isDefaultNamespace|isEqualNode|isSameNode|isSupported|lookupNamespaceURI|lookupPrefix|mozMatchesSelector|normalize|querySelector|querySelectorAll|removeAttribute|removeAttributeNode|removeChild|removeEventListener|replaceChild|scrollIntoView|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setCapture|setIdAttribute|setIdAttributeNS|setIdAttributeNode|setUserData|insertAdjacentHTML|onbeforescriptexecute|onafterscriptexecute|oncopy|oncut|onpaste|onbeforeunload|onblur|onchange|onclick|oncontextmenu|ondblclick|onfocus|onkeydown|onkeypress|onkeyup|onmousedown|onmousemove|onmouseout|onmouseover|onmouseup|onresize|onscroll|'"/>     		
     		<assert test="not(contains($reservedWords,concat('|',text(),'|')))">
     			Invalid name for parameter '<value-of select="text()"/>': this name cannot be used.
     		</assert>
     	</rule>          
     	<rule context="parameter">
          	   <let name="parameter" value="."/>
          	   <let name="parameterName" value="$parameter/name"/>
          	   <let name="vdef_value" value="vdef/value/text()" /> 
           	   <assert test="count($parameter//*[@undef='1']) &lt; 2">
          	   Invalid value list for parameter '<value-of select="$parameterName"/>': this parameter has multiple undefined values.
          	   </assert>
               <assert test="not( (not(@issimple) or (@issimple='0')) and (@ismandatory and @ismandatory='1') and not(precond or ancestor::paragraph/precond) and ( not(vdef) or vdef/value/text()=vlist/velem[@undef='1']/value/text() ))">
          	   a mandatory parameter ('<value-of select="$parameterName"/>') without precond nor default value or with an undefined default value must be tag as @issimple
               </assert>
               <assert test="not( (@ishidden and @ishidden='1') and (@issimple and @issimple='1') )">
               a simple parameter('<value-of select="$parameterName"/>') cannot be hidden too.
               </assert>
               <assert test="not( ((@isout and @isout='1') or (@istdout and @istdout='1')) and (@issimple and @issimple='1') )">
               an output parameter('<value-of select="$parameterName"/>') cannot be simple too.
               </assert>
		  </rule>          
          <rule context="parameter/vlist/velem | parameter/flist/felem">
          	   <let name="value" value="value/text()"/>
          	   <let name="label" value="label/text()"/>
          	   <let name="parameter" value="../.."/>
          	   <let name="parameterName" value="$parameter/name"/>
							 <assert test="not(preceding-sibling::*/value[text()=$value])" >
          	   Invalid value list for parameter '<value-of select="$parameterName"/>': duplicate value '<value-of select="$value"/>'.
							 </assert>
							 <assert test="not(preceding-sibling::*/label[text()=$label])" >
          	   Invalid value list for parameter '<value-of select="$parameterName"/>': duplicate label '<value-of select="$label"/>'.
							 </assert>
					</rule>					
          <rule context="parameter[@isout='1']">
          	   <let name="parameterName" value="name"/>
               <assert test="count(filenames) &gt; 0">
               Invalid parameter: <value-of select="$parameterName"/>: an isout parameter must include a filename
               </assert>
          </rule>
          <rule context="parameter[((not(@isout)) or (@isout='0')) and ((not(@isstdout)) or (@isstdout='0')) and ((not(@isstderr)) or (@isstderr='0'))]">
          	   <let name="parameterName" value="name"/>
               <assert test="count(filenames) = 0">
               Invalid parameter: <value-of select="$parameterName"/>: an input parameter cannot include a filename 
               </assert>
          </rule>
          <rule context="parameter/type/datatype/class">
          	   <let name="parameter" value="../../.."/>
          	   <let name="parameterName" value="$parameter/name"/>
          	   <let name="isOut" value="$parameter/@isout='1'"/>
          	   <let name="isStdout" value="$parameter/@isstdout='1'"/>
          	   <let name="isIn" value="not($isOut or $isStdout)"/>          	   
          	   <let name="isHidden" value="$parameter/@ishidden='1'"/>          	   
          	   <let name="class" value="text()"/>          	   
          	   <let name="hasDataFormats" value="count(../..//dataFormat) &gt; 0"/>          	   
          	   <assert test="not(starts-with($class,'Abstract'))">
          	   Invalid parameter datatype class for parameter '<value-of select="$parameterName"/>': no parameter datatype class can be abstract.
          	   </assert>
          	   <!-- 
          	   <assert test="not($class='Text' and not($isIn))">
          	   Invalid parameter datatype class for parameter '<value-of select="$parameterName"/>': no output parameter datatype class can be set to "Text".
          	   </assert>
          	    -->
          	   <assert test="not($class='Text' and $isHidden)">
          	   Invalid parameter datatype class for parameter '<value-of select="$parameterName"/>': no hidden parameter datatype class can be set to "Text".
          	   </assert>
          	   <assert test="$class='MultipleChoice' or count($parameter/vdef/value) &lt; 2">
          	   Invalid parameter datatype class or default value for parameter '<value-of select="$parameterName"/>': this parameter has multiple default values, yet it is not typed as a MultipleChoice.
          	   </assert>
          		<assert test="not(starts-with('Multiple',$class) and $parameter/separator)">
          	   Invalid parameter datatype class or separator for parameter '<value-of select="$parameterName"/>': this parameter has a value separator specified, yet it is typed as a "Multiple" type.
          	   </assert>
          	   <assert test="not(($class='Boolean' or $class='Integer' or $class='Float' or $class='String' or $class='Choice' or $class='MultipleChoice' or $class='FileName') and ($isOut or $isStdout))">
          	   Invalid parameter datatype class for parameter '<value-of select="$parameterName"/>': no output parameter datatype class can be set to <value-of select="$class"/>.
          	   </assert>
          </rule>
          <rule context="parameter/vdef/value">
          	   <let name="value" value="text()"/>
          	   <let name="parameter" value="../.."/>
          	   <let name="parameterName" value="$parameter/name"/>
          	   <let name="class" value="$parameter/type/datatype/class"/>
          	   <let name="list" value="$parameter/vlist | $parameter/flist"/>
          	   <let name="values" value="$list//value"/>
          	   <let name="label" value="$list//label"/>
          	   <assert test="count($list)=0 or count($values[text()=$value])">
          	   Invalid default value for parameter '<value-of select="$parameterName"/>': default value <value-of select="$value"/> is not part of the possible values list.
          	   </assert>
          </rule>
     </pattern>
</schema>