<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:powder="http://www.w3.org/2007/05/powder#" xmlns:functx="http://www.functx.com" exclude-result-prefixes="functx xs">

<xsl:template match="/">
	<xsl:apply-templates/> 
</xsl:template>

<!-- 
Match all the POWDER extensions to POWDER-Base IRISet, then handle any white-space separated lists and finally convert everything to regex--> 
<xsl:function name="functx:escape-for-regex" as="xs:string">
	<xsl:param name="arg" as="xs:string?"/>
    <xsl:sequence select=" 
	  replace(normalize-space($arg),
			   '(&amp;amp;|&amp;gt;|!|#|%|,|/|:|;|=|@|_|`|~|\.|\[|\]|\\|\-|\^|\$|\?|\*|\+|\{|\}|\(|\))','\\$1')
	 "/>
</xsl:function> 

<xsl:template match="powder:abouthosts">
	<xsl:element name="aboutregex" namespace="http://www.w3.org/2007/05/powder#">
		<xsl:variable name="escaped-host"><xsl:value-of select="functx:escape-for-regex(.)"/></xsl:variable>
		<xsl:value-of select="concat('\:\/\/(([^\/\?\#]*)\@)?([^\:\/\?\#\@]+\.)?(',replace($escaped-host,' ','|'),')(\:([0-9]+))?\/')"/>
	</xsl:element>	
</xsl:template>

<xsl:template match="powder:includeschemes">
	<xsl:element name="includeregex" namespace="http://www.w3.org/2007/05/powder#">
		<xsl:variable name="escaped-schemes"><xsl:value-of select="functx:escape-for-regex(.)"/></xsl:variable>
		<xsl:value-of select="concat('^(',replace($escaped-schemes,' ','|'),')\:\/\/')"/>
	</xsl:element>	
</xsl:template>

<xsl:template match="powder:excludeschemes">
	<xsl:element name="excluderegex" namespace="http://www.w3.org/2007/05/powder#">
		<xsl:variable name="escaped-schemes"><xsl:value-of select="functx:escape-for-regex(.)"/></xsl:variable>
		<xsl:value-of select="concat('^(',replace($escaped-schemes,' ','|'),')\:\/\/')"/>
	</xsl:element>	
</xsl:template>

<xsl:template match="powder:includehosts">
	<xsl:element name="includeregex" namespace="http://www.w3.org/2007/05/powder#">
		<xsl:variable name="escaped-host"><xsl:value-of select="functx:escape-for-regex(.)"/></xsl:variable>
		<xsl:value-of select="concat('\:\/\/(([^\/\?\#]*)\@)?([^\:\/\?\#\@]+\.)?(',replace($escaped-host,' ','|'),')(\:([0-9]+))?\/')"/>
	</xsl:element>	
</xsl:template>

<xsl:template match="powder:excludehosts">
	<xsl:element name="excluderegex" namespace="http://www.w3.org/2007/05/powder#">
		<xsl:variable name="escaped-host"><xsl:value-of select="functx:escape-for-regex(.)"/></xsl:variable>
		<xsl:value-of select="concat('\:\/\/(([^\/\?\#]*)\@)?([^\:\/\?\#\@]+\.)?(',replace($escaped-host,' ','|'),')(\:([0-9]+))?\/')"/>
	</xsl:element>	
</xsl:template>

<xsl:template match="powder:includeexactpaths">
	<xsl:element name="includeregex" namespace="http://www.w3.org/2007/05/powder#">
		<xsl:variable name="escaped-path"><xsl:value-of select="functx:escape-for-regex(.)"/></xsl:variable>
		<xsl:value-of select="concat('\:\/\/(([^\/\?\#]*)\@)?([^\:\/\?\#\@]*)(\:([0-9]+))?(',replace($escaped-path,' ','|'),')($|\?|\#)')"/>
	</xsl:element>
</xsl:template>

<xsl:template match="powder:excludeexactpaths">
	<xsl:element name="excluderegex" namespace="http://www.w3.org/2007/05/powder#">
		<xsl:variable name="escaped-path"><xsl:value-of select="functx:escape-for-regex(.)"/></xsl:variable>
		<xsl:value-of select="concat('\:\/\/(([^\/\?\#]*)\@)?([^\:\/\?\#\@]*)(\:([0-9]+))?(',replace($escaped-path,' ','|'),')($|\?|\#)')"/>
	</xsl:element>
</xsl:template>

<xsl:template match="powder:includeports">
	<xsl:element name="includeregex" namespace="http://www.w3.org/2007/05/powder#">
		<xsl:variable name="escaped-ports"><xsl:value-of select="functx:escape-for-regex(.)"/></xsl:variable>
		<xsl:value-of select="concat('\:\/\/(([^\/\?\#]*)\@)?([^\:\/\?\#\@]+\.)*[^\:\/\?\#\@]+\:(',replace($escaped-ports,' ','|'),')\/')"/>
	</xsl:element>	
</xsl:template>

<xsl:template match="powder:excludeports">
	<xsl:element name="excluderegex" namespace="http://www.w3.org/2007/05/powder#">
		<xsl:variable name="escaped-ports"><xsl:value-of select="functx:escape-for-regex(.)"/></xsl:variable>
		<xsl:value-of select="concat('\:\/\/(([^\/\?\#]*)\@)?([^\:\/\?\#\@]+\.)*[^\:\/\?\#\@]+\:(',replace($escaped-ports,' ','|'),')\/')"/>
	</xsl:element>	
</xsl:template>

<xsl:template match="powder:includepathstartswith">
	<xsl:element name="includeregex" namespace="http://www.w3.org/2007/05/powder#">
		<xsl:variable name="escaped-path-starts-with"><xsl:value-of select="functx:escape-for-regex(.)"/></xsl:variable>
		<xsl:value-of select="concat('\:\/\/(([^\/\?\#]*)\@)?([^\:\/\?\#\@]*)(\:([0-9]+))?(',replace($escaped-path-starts-with,' ','|'),')')"/>
	</xsl:element>
</xsl:template>

<xsl:template match="powder:excludepathstartswith">
	<xsl:element name="excluderegex" namespace="http://www.w3.org/2007/05/powder#">
		<xsl:variable name="escaped-path-starts-with"><xsl:value-of select="functx:escape-for-regex(.)"/></xsl:variable>
		<xsl:value-of select="concat('\:\/\/(([^\/\?\#]*)\@)?([^\:\/\?\#\@]*)(\:([0-9]+))?(',replace($escaped-path-starts-with,' ','|'),')')"/>
	</xsl:element>
</xsl:template>

<xsl:template match="powder:includepathcontains">
	<xsl:element name="includeregex" namespace="http://www.w3.org/2007/05/powder#">
		<xsl:variable name="escaped-path-contains"><xsl:value-of select="functx:escape-for-regex(.)"/></xsl:variable>
		<xsl:value-of select="concat('\:\/\/(([^\/\?\#]*)\@)?([^\:\/\?\#\@]*)(\:([0-9]+))?\/[^\?\#]*(',replace($escaped-path-contains,' ','|'),')[^\?\#]*[\?\#]?')"/>
	</xsl:element> 	
</xsl:template>

<xsl:template match="powder:excludepathcontains">
	<xsl:element name="excluderegex" namespace="http://www.w3.org/2007/05/powder#">
		<xsl:variable name="escaped-path-contains"><xsl:value-of select="functx:escape-for-regex(.)"/></xsl:variable>
		<xsl:value-of select="concat('\:\/\/(([^\/\?\#]*)\@)?([^\:\/\?\#\@]*)(\:([0-9]+))?\/[^\?\#]*(',replace($escaped-path-contains,' ','|'),')[^\?\#]*[\?\#]?')"/>
	</xsl:element> 
</xsl:template>

<xsl:template match="powder:includepathendswith">
	<xsl:element name="includeregex" namespace="http://www.w3.org/2007/05/powder#">
		<xsl:variable name="escaped-path-ends-with"><xsl:value-of select="functx:escape-for-regex(.)"/></xsl:variable>
		<xsl:value-of select="concat('\:\/\/(([^\/\?\#]*)\@)?([^\:\/\?\#\@]*)(\:([0-9]+))?\/[^\?\#]*(',replace($escaped-path-ends-with,' ','|'),')($|\?|\#)')"/>
	</xsl:element> 
</xsl:template>

<xsl:template match="powder:excludepathendswith">
	<xsl:element name="excluderegex" namespace="http://www.w3.org/2007/05/powder#">
		<xsl:variable name="escaped-path-ends-with"><xsl:value-of select="functx:escape-for-regex(.)"/></xsl:variable>
		<xsl:value-of select="concat('\:\/\/(([^\/\?\#]*)\@)?([^\:\/\?\#\@]*)(\:([0-9]+))?\/[^\?\#]*(',replace($escaped-path-ends-with,' ','|'),')($|\?|\#)')"/>
	</xsl:element> 
</xsl:template>

<xsl:template match="powder:includequerycontains|powder:excludequerycontains">
	<xsl:param name="querystring" select="." as="xs:string"/>	
<!-- this template splits up the querystring according to its delimiter, and calls another template to create an includeregex element for each atomic query (i.e. name=value pair)-->
	<xsl:variable name="delimiter">
		<xsl:choose>
			<xsl:when test="@delimiter"><xsl:value-of select="@delimiter"/></xsl:when>
			<xsl:otherwise>&amp;</xsl:otherwise>
		</xsl:choose>
	</xsl:variable>
	<xsl:call-template name="build-query-regex"><!-- pass the querystring to a template that will split the querystring into its component name-value pairs and create either an include or exclude regex element for each-->
		<xsl:with-param name="delimiter" select="$delimiter"/>
		<xsl:with-param name="querystring" select="$querystring"/>
		<xsl:with-param name="element" select="substring-before(local-name(), 'querycontains')"/>
	</xsl:call-template>
</xsl:template>

<xsl:template name="build-query-regex">
<xsl:param name="delimiter"/>
<xsl:param name="querystring"/>
<xsl:param name="element"/>
<xsl:choose>
	<xsl:when test="contains($querystring, $delimiter)">
		<xsl:variable name="name-value-pair">
			<xsl:value-of select="substring-before($querystring, $delimiter)"/>
		</xsl:variable>
		<xsl:element name="{$element}regex" namespace="http://www.w3.org/2007/05/powder#">\:\/\/(([^\/\?\#]*)\@)?([^\:\/\?\#\@]*)(\:([0-9]+))?\/[^\?\#]*\?([^\#]*\&amp;)?<xsl:value-of select="$name-value-pair"/>(\&amp;|$)</xsl:element>	
		<xsl:call-template name="build-query-regex">
			<xsl:with-param name="querystring" select="substring-after($querystring,$delimiter)"/>
			<xsl:with-param name="delimiter" select="$delimiter"/>
			<xsl:with-param name="element" select="$element"/>
		</xsl:call-template>	
	</xsl:when>
	<xsl:otherwise><!-- this is for the final name-value pair which will not be followed by a delimiter. After creating this the template is exited.-->
		<xsl:element name="{$element}regex" namespace="http://www.w3.org/2007/05/powder#">\:\/\/(([^\/\?\#]*)\@)?([^\:\/\?\#\@]*)(\:([0-9]+))?\/[^\?\#]*\?([^\#]*\&amp;)?<xsl:value-of select="$querystring"/>(\&amp;|$)</xsl:element>		
	</xsl:otherwise>
</xsl:choose>
</xsl:template>

<xsl:template match="powder:includeresources">
	<xsl:element name="includeregex" namespace="http://www.w3.org/2007/05/powder#">	
		<xsl:variable name="resources"><xsl:value-of select="functx:escape-for-regex(.)"/></xsl:variable>
		<xsl:value-of select="concat('^(',replace($resources,' ','|'),')$')"/>
	</xsl:element>
</xsl:template>

<xsl:template match="powder:excluderesources">
	<xsl:element name="excluderegex" namespace="http://www.w3.org/2007/05/powder#">	
		<xsl:variable name="resources"><xsl:value-of select="functx:escape-for-regex(.)"/></xsl:variable>
		<xsl:value-of select="concat('^(',replace($resources,' ','|'),')$')"/>
	</xsl:element>
</xsl:template>

<xsl:template match="powder:includeiripattern | powder:excludeiripattern">
	<xsl:variable name="element" select="substring-before(local-name(), 'iripattern')"/>
	<!-- Create some regex scalers to match the scheme, host and port. See the formal semantics doc for details.-->
	<xsl:variable name="iripattern" select="normalize-space(.)"/>
	<xsl:analyze-string select="$iripattern" regex="(([^:/\?\.]+):)?(//)?([^:/\?#@]+)(:([0-9]+))?">
		<xsl:matching-substring>
			<xsl:variable name="scheme" select="regex-group(2)"/>
			<xsl:variable name="host" select="regex-group(4)"/>
			<xsl:variable name="port" select="regex-group(6)"/>
			<!-- Next, action the rules in the formal semantics doc (iripattern section)-->
			<xsl:variable name="s">
				 <xsl:choose>
					<xsl:when test="string-length($scheme) = 0">[A-Za-z]+</xsl:when>
					<xsl:otherwise><xsl:value-of select="$scheme"/></xsl:otherwise>
				</xsl:choose>
			</xsl:variable>
			<xsl:variable name="h">
			<xsl:choose>
				<xsl:when test="$host='*'">([^:/\?#@]+\.)*[^:/\?#@]+</xsl:when>
				<xsl:when test="matches($host,'^\*\.(.*)')">
					<xsl:analyze-string select="$host" regex="^\*\.(.*)">
						<xsl:matching-substring>
							<xsl:value-of select="concat('([^:/\?#@]+\.)+',regex-group(1))"/>
						</xsl:matching-substring>
					</xsl:analyze-string>
				</xsl:when>
				<xsl:otherwise>
					<xsl:value-of select="concat('([^:/\?#@]+\.)*)',$host)"/>
				</xsl:otherwise>
			</xsl:choose>
			</xsl:variable>
			<xsl:variable name="p">
				 <xsl:choose>
					<xsl:when test="string-length($scheme) = 0">(\:[0-9]+)?</xsl:when>
					<xsl:otherwise><xsl:value-of select="concat(':',$port)"/></xsl:otherwise>
				</xsl:choose>
			</xsl:variable>
			<!-- finally add them all together with the additional anchors and escapes-->
			<xsl:element name="{$element}regex" namespace="http://www.w3.org/2007/05/powder#">
				<xsl:value-of select="concat('^',$s,':\/\/',$h,$p)"/>
			</xsl:element>
		</xsl:matching-substring>
		<xsl:non-matching-substring><powder:error>iripattern does not conform to the IRI regex (see POWDER Formal document for details) </powder:error></xsl:non-matching-substring>
	</xsl:analyze-string>
</xsl:template>

<!-- copy everything else in the document -->

<xsl:template match="@*|node()">
   <xsl:copy inherit-namespaces="yes">
      <xsl:apply-templates select="@*|node()" />
   </xsl:copy>
</xsl:template>

</xsl:stylesheet>

