<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
    xmlns:oval-def="http://oval.mitre.org/XMLSchema/oval-definitions-5"
    xmlns:win-def="http://oval.mitre.org/XMLSchema/oval-definitions-5#windows"
    xmlns:cdf="http://checklists.nist.gov/xccdf/1.1" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:oval-res="http://oval.mitre.org/XMLSchema/oval-results-5"
    xmlns:oval-sc="http://oval.mitre.org/XMLSchema/oval-system-characteristics-5"
    xmlns:oval-ind="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent"
    xmlns:ind-sc="http://oval.mitre.org/XMLSchema/oval-system-characteristics-5#independent"
    xmlns:win-sc="http://oval.mitre.org/XMLSchema/oval-system-characteristics-5#windows"
    xmlns:xalan="http://xml.apache.org/xalan"
    xmlns:fnd="http://results.pa.mcafee.com/findings/5.2">

    <!--
        
        This XSLT is used for the definition which want to verify whether some system configuration is not set as 
        expected by the user in the user input. Choice of user input should be available in the external variable with all 
        the posssible value. 
        
        Message id :  Message id is generated by the template getMessageId. 
        
        Message id is generated by the id of the definition.          
        Message id is generated by the concatenation of  "com.mcafee.pa.msg.winconfiguration" 
        and the phrase of the definition id after "oval:com.mcafee." without  "." and ":" . 
        
        This messages are added in the Windows Messages file.
        
        Schema for the definition is : ( It should have only family and registry tests ) 
        
       Criteria ( and )
            criterion : family test 
            criteria (or)                
                criterion              Registry test  to test the existance of the registry (optional)
                criterion              Registry test  to test the proper type of the registry value ((optional ))
            criteria         
            
        **Note that this xslt has not been extended to incorporate 'type check' registry tests
    -->
    <xsl:variable name="Definitions"
        select="/oval-res:oval_results/oval-def:oval_definitions/oval-def:definitions"/>
    <xsl:variable name="Tests"
        select="/oval-res:oval_results/oval-def:oval_definitions/oval-def:tests"/>
    <xsl:variable name="TestedItems"
        select="/oval-res:oval_results/oval-res:results/oval-res:system/oval-res:tests"/>
    <xsl:variable name="CollectedObjects"
        select="/oval-res:oval_results/oval-res:results/oval-res:system/oval-sc:oval_system_characteristics/oval-sc:collected_objects"/>
    <xsl:variable name="SystemData"
        select="/oval-res:oval_results/oval-res:results/oval-res:system/oval-sc:oval_system_characteristics/oval-sc:system_data"/>
    <xsl:variable name="States"
        select="/oval-res:oval_results/oval-def:oval_definitions/oval-def:states"/>
    <xsl:variable name="Objects"
        select="/oval-res:oval_results/oval-def:oval_definitions/oval-def:objects"/>
    <xsl:variable name="Variables"
        select="/oval-res:oval_results/oval-def:oval_definitions/oval-def:variables"/>
    <xsl:variable name="OvalResult"
        select="/oval-res:oval_results/oval-res:results/oval-res:system/oval-res:definitions"/>

    <xsl:template name="toggleBoolean">
        <xsl:param name="value"/>
        <xsl:choose>
            <xsl:when test="$value = 'true'">
                <xsl:value-of select="false()"/>
            </xsl:when>
            <xsl:when test="$value = 'false'">
                <xsl:value-of select="true()"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="true()"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template name="removeColon">
        <xsl:param name="string"/>
        <xsl:param name="count"/>
        <xsl:param name="length"/>

        <xsl:if test="$count  &lt;= $length">

            <xsl:variable name="char">
                <xsl:value-of select="substring($string,$count,1)"/>
            </xsl:variable>

            <xsl:choose>
                <xsl:when test="$char != ':' and $char != '.' ">
                    <xsl:value-of select="$char"/>
                    <xsl:call-template name="removeColon">
                        <xsl:with-param name="string" select="$string"/>
                        <xsl:with-param name="count" select="$count + 1"/>
                        <xsl:with-param name="length" select="$length"/>
                    </xsl:call-template>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:call-template name="removeColon">
                        <xsl:with-param name="string" select="$string"/>
                        <xsl:with-param name="count" select="$count + 1"/>
                        <xsl:with-param name="length" select="$length"/>
                    </xsl:call-template>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:if>
    </xsl:template>

    <xsl:template name="getSuffixForMessageId">
        <xsl:param name="id"/>

        <xsl:variable name="suffix">
            <xsl:value-of select="substring-after($id,'oval:com.mcafee.')"/>
        </xsl:variable>

        <xsl:variable name="suffix1">
            <xsl:call-template name="removeColon">
                <xsl:with-param name="string" select="$suffix"/>
                <xsl:with-param name="length" select="string-length($suffix)"/>
                <xsl:with-param name="count" select="1 + 0"/>
            </xsl:call-template>
        </xsl:variable>
        <xsl:value-of select="$suffix1"/>
    </xsl:template>

    <xsl:template name="getVariableSuffix">
        <xsl:param name="test_id"/>
        <xsl:variable name="suffix">
            <xsl:value-of select="substring-after($test_id,'tst:')"/>
        </xsl:variable>
        <xsl:value-of select="$suffix"/>
    </xsl:template>

    <xsl:template name="getMessageId">
        <xsl:param name="id"/>
        <xsl:param name="status"/>

        <xsl:variable name="suffiex">
            <xsl:call-template name="getSuffixForMessageId">
                <xsl:with-param name="id" select="$id"/>
            </xsl:call-template>
        </xsl:variable>

        <xsl:if test="$suffiex != '' ">
            <xsl:choose>
                <xsl:when test="$status = 'does not exist' ">
                    <xsl:value-of select="concat('com.mcafee.pa.msg.winnoconfiguration',$suffiex)"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="concat('com.mcafee.pa.msg.winconfiguration',$suffiex)"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:if>
    </xsl:template>


    <xsl:template name="getPrintableValue">
        <xsl:param name="numaricValue"/>

        <xsl:variable name="formattedNumaricValue">
            <xsl:choose>
                <xsl:when test="$numaricValue != '' ">
                    <xsl:value-of select="$numaricValue"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:text>Not Configured</xsl:text>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:variable>

        <xsl:value-of select="$formattedNumaricValue"/>

    </xsl:template>

    <xsl:template name="getFindings">
        <xsl:param name="definitionId"/>

        <xsl:variable name="result"
            select="/oval-res:oval_results/oval-res:results/oval-res:system/oval-res:definitions/oval-res:definition[@definition_id=$definitionId]/@result"/>

        <xsl:variable name="unorderedFindings">
            <xsl:call-template name="winConfigurationCheck">
            <xsl:with-param name="definitionId" select="$definitionId"/>
            <xsl:with-param name="def_result" select="$result"/>
        </xsl:call-template>
        </xsl:variable>
        
        <!-- Now arrange all the nodes to fit the schema. All <inputValue/> nodes must come first, followed by all <finding/> nodes-->
        
            <findings id="{xalan:nodeset($unorderedFindings)/descendant::fnd:findings/@id}"  xmlns="http://results.pa.mcafee.com/findings/5.2">
                <xsl:copy>
                    <xsl:copy-of select="xalan:nodeset($unorderedFindings)/descendant::fnd:inputValue"/>
                    <xsl:copy-of select="xalan:nodeset($unorderedFindings)/descendant::fnd:finding"/>
                </xsl:copy>
            </findings>
    </xsl:template>

    <xsl:template name="winConfigurationCheck">
        <xsl:param name="definitionId"/>
        <xsl:param name="def_result"/>

        <xsl:variable name="tests">
            <xsl:for-each
                select="$OvalResult/oval-res:definition[ @definition_id = $definitionId ]/oval-res:criteria/descendant::oval-res:criterion">

                <xsl:variable name="test" select="@test_ref"/>
                <xsl:if test="$Tests/win-def:registry_test[@id=$test]">
                    <xsl:variable name="object"
                        select="$Tests/win-def:registry_test[@id=$test]/win-def:object/@object_ref"/>
                    <xsl:variable name="state"
                        select="$Tests/win-def:registry_test[@id=$test]/win-def:state/@state_ref"/>

                    <xsl:variable name="keyref"
                        select="$States/win-def:registry_state[@id=$state]/win-def:key/@var_ref"/>
                    <xsl:variable name="key"
                        select="$Variables/oval-def:constant_variable[@id=$keyref]/oval-def:value"/>

                    <xsl:variable name="name_ref"
                        select="$States/win-def:registry_state[@id=$state]/win-def:name/@var_ref"/>
                    <xsl:variable name="name"
                        select="$Variables/oval-def:constant_variable[@id=$name_ref]/oval-def:value"/>
     
                    <xsl:element name="test">
                        <xsl:attribute name="id">
                            <xsl:value-of select="$test"/>
                        </xsl:attribute>

                        <xsl:attribute name="key">
                            <xsl:value-of select="$key"/>
                        </xsl:attribute>

                        <xsl:attribute name="state">
                            <xsl:value-of select="$state"/>
                        </xsl:attribute>

                        <xsl:attribute name="name">
                            <xsl:value-of select="$name"/>
                        </xsl:attribute>

                        <xsl:if test="$States/win-def:registry_state[@id=$state]/win-def:value or $state = '' ">
                            <xsl:attribute name="type">
                                <xsl:text>primarytest</xsl:text>
                            </xsl:attribute>
                            <xsl:variable name="value_ref" select="$States/win-def:registry_state[@id=$state]/win-def:value/@var_ref"/>
                            <xsl:variable name="expectedValue">
                                <xsl:choose>
                                    <xsl:when test="$value_ref = ''">
                                        <xsl:value-of select="$States/win-def:registry_state[@id=$state]/win-def:value"/>                      
                                    </xsl:when>
                                    <xsl:when test="$Variables/oval-def:constant_variable[@id=$value_ref]/oval-def:value != ''">
                                        <xsl:value-of select="$Variables/oval-def:constant_variable[@id=$value_ref]/oval-def:value"/>
                                    </xsl:when>
                                    <xsl:otherwise>
                                        <xsl:value-of select="$TestedItems/oval-res:test[@test_id=$test ]/oval-res:tested_variable[@variable_id = $value_ref]"/>
                                    </xsl:otherwise>
                                </xsl:choose>                                
                            </xsl:variable>
                            
                            <xsl:attribute name="expectedValue">
                                <xsl:value-of select="$expectedValue"/>
                            </xsl:attribute>
                        </xsl:if>

                        <!--Note that this xslt currently DOES NOT cover typechecking tests.-->
                        <xsl:if
                            test="$States/win-def:registry_state[@id=$state]/win-def:type and not($States/win-def:registry_state[@id=$state]/win-def:value)">
                            <xsl:attribute name="type">
                                <xsl:text>typecheckingtest</xsl:text>
                            </xsl:attribute>
                            <xsl:variable name="type_ref"
                                select="$States/win-def:registry_state[@id=$state]/win-def:type/@var_ref"/>
                            <xsl:variable name="typeName"
                                select="$Variables/oval-def:constant_variable[@id=$type_ref]/oval-def:value"/>
                            <xsl:attribute name="typeName">
                                <xsl:value-of select="$typeName"/>
                            </xsl:attribute>
                        </xsl:if>
                    </xsl:element>
                </xsl:if>

                <xsl:if test="$Tests/oval-ind:family_test[@id=$test]">
                    <xsl:element name="test">
                        <xsl:attribute name="id">
                            <xsl:value-of select="$test"/>
                        </xsl:attribute>
                        <xsl:attribute name="type">
                            <xsl:text>family</xsl:text>
                        </xsl:attribute>
                    </xsl:element>
                </xsl:if>
            </xsl:for-each>

        </xsl:variable>

        <xsl:variable name="exDefinitionId">
            <xsl:for-each
                select="/oval-res:oval_results/oval-res:results/oval-res:system/oval-res:definitions/oval-res:definition[ @definition_id = $definitionId ]/oval-res:criteria/descendant::oval-res:extend_definition[@result = 'false'] ">
                <xsl:if test="./parent::node()/@result = 'false' ">
                    <xsl:element name="extend_definition">
                        <xsl:attribute name="id">
                            <xsl:value-of select="@definition_ref"/>
                        </xsl:attribute>
                        <xsl:attribute name="result">
                            <xsl:value-of select="@result"/>
                        </xsl:attribute>
                    </xsl:element>
                </xsl:if>
            </xsl:for-each>
        </xsl:variable>

        <xsl:variable name="rs_exDefinition">
            <xsl:value-of
                select="xalan:nodeset($exDefinitionId)/descendant::extend_definition/@result"/>
        </xsl:variable>

        <xsl:variable name="pre_test_result">
            <xsl:choose>
                <xsl:when
                    test="xalan:nodeset($tests)/descendant::test[@type ='family' ]/@id != '' ">
                    <xsl:variable name="test"
                        select="xalan:nodeset($tests)/descendant::test[@type ='family' ]/@id"/>
                    <xsl:value-of select="$TestedItems/oval-res:test[@test_id=$test ]/@result"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:text>true</xsl:text>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:variable>


        <xsl:if test=" $pre_test_result = 'true' and $def_result = 'false' ">
            
            <findings id="{$definitionId}" xmlns="http://results.pa.mcafee.com/findings/5.2">
                <!-- Create an inputValue node for each expectedValue -->
                <xsl:for-each select="xalan:nodeset($tests)/descendant::test[ @type ='primarytest' ]">
                    <xsl:variable name="test" select="@id"/>
                    <xsl:variable name="state" select="@state"/>
                    <xsl:variable name="key" select="@key"/>
                    <xsl:variable name="name" select="@name"/>
                    <xsl:variable name="expectedValue" select="@expectedValue"/>
                    <xsl:variable name="variableSuffix">
                        <xsl:call-template name="getVariableSuffix">
                            <xsl:with-param name="test_id" select="normalize-space($test)"/>
                        </xsl:call-template>
                    </xsl:variable>

                    <xsl:if test="$expectedValue != '' ">

                        <xsl:variable name="inputRegistryParameterValue">
                            <xsl:call-template name="getPrintableValue">
                                <xsl:with-param name="numaricValue" select="$expectedValue"/>
                            </xsl:call-template>
                        </xsl:variable>

                        <inputValue key="{concat('expectedValue_',$variableSuffix)}">
                            <xsl:value-of select="$inputRegistryParameterValue"/>
                        </inputValue>                                                
                    </xsl:if>
                </xsl:for-each>
                
                <!-- There is only a single message. Hence, there should only be a single finding. Create that finding with multiple actualValues-->
                <xsl:variable name="actualParameterStatus" select="$SystemData/win-sc:registry_item[1]/win-sc:name/@status"/>
				
                <xsl:variable name="message_id">
                    <xsl:call-template name="getMessageId">
                        <xsl:with-param name="id" select="normalize-space($definitionId)"/>
						<xsl:with-param name="status" select="normalize-space($actualParameterStatus)"/>
                    </xsl:call-template>
                </xsl:variable>
                <finding messageId="{$message_id}" isViolation="true">
                    
                    <xsl:for-each select="xalan:nodeset($tests)/descendant::test[ @type ='primarytest' ]">
                        <xsl:variable name="test" select="@id"/>
                        <xsl:variable name="variableSuffix">
                            <xsl:call-template name="getVariableSuffix">
                                <xsl:with-param name="test_id" select="normalize-space($test)"/>
                            </xsl:call-template>
                        </xsl:variable>
                        <xsl:for-each
                            select="$TestedItems/oval-res:test[@test_id=$test ]/oval-res:tested_item[ @result = 'false'  or @result = 'error'  or  @result='not evaluated' ] ">
                            
                            <xsl:variable name="itemRef" select="@item_id"/>
                            <xsl:variable name="result" select="@result"/>
                            
                            <xsl:variable name="actualParameterValue"
                                select="$SystemData/win-sc:registry_item[@id=$itemRef]/win-sc:value"/>                            
                            
                            <xsl:variable name="actualParameterPrintableValue">
                                <xsl:call-template name="getPrintableValue">
                                    <xsl:with-param name="numaricValue"
                                        select="$actualParameterValue"/>
                                </xsl:call-template>
                            </xsl:variable>             
                            
                            <actualValue key="{concat('actualValue_',$variableSuffix)}">
                                <xsl:value-of select="$actualParameterPrintableValue"/>
                            </actualValue>                            
                        </xsl:for-each>
                    </xsl:for-each>
                </finding>
            </findings>
        </xsl:if>

        <xsl:if test=" $def_result = 'true' ">
            <findings id="{$definitionId}" xmlns="http://results.pa.mcafee.com/findings/5.2">
                <xsl:for-each
                    select="xalan:nodeset($tests)/descendant::test[@type ='primarytest' ]">
                    <xsl:variable name="test" select="@id"/>
                    <xsl:variable name="state" select="@state"/>
                    <xsl:variable name="key" select="@key"/>
                    <xsl:variable name="name" select="@name"/>
                    <xsl:variable name="expectedValue" select="@expectedValue"/>
                    <xsl:variable name="variableSuffix">
                        <xsl:call-template name="getVariableSuffix">
                            <xsl:with-param name="test_id" select="normalize-space($test)"/>
                        </xsl:call-template>
                    </xsl:variable>

                    <xsl:if test="$expectedValue != '' ">

                        <xsl:variable name="inputRegistryParameterValue">
                            <xsl:call-template name="getPrintableValue">
                                <xsl:with-param name="numaricValue" select="$expectedValue"/>
                            </xsl:call-template>
                        </xsl:variable>

                        <inputValue key="{concat('expectedValue_',$variableSuffix)}">
                            <xsl:value-of select="$inputRegistryParameterValue"/>
                        </inputValue>

                        <xsl:for-each
                            select="$TestedItems/oval-res:test[@test_id=$test ]/oval-res:tested_item[@result='not evaluated' or @result='true']">

                            <xsl:variable name="itemRef" select="@item_id"/>
                            <xsl:variable name="result" select="@result"/>

                            <xsl:variable name="actualParameterValue"
                                select="$SystemData/win-sc:registry_item[@id=$itemRef]/win-sc:value"/>

                            <xsl:variable name="actualParameterPrintableValue">
                                <xsl:call-template name="getPrintableValue">
                                    <xsl:with-param name="numaricValue"
                                        select="$actualParameterValue"/>
                                </xsl:call-template>
                            </xsl:variable>

                            <xsl:variable name="message_id">
                                <xsl:call-template name="getMessageId">
                                    <xsl:with-param name="id" select="$definitionId"/>
                                </xsl:call-template>
                            </xsl:variable>

                            <finding messageId="{concat($message_id,'_',$variableSuffix)}"
                                isViolation="false">
                                <actualValue key="{concat('actualValue_',$variableSuffix)}">
                                    <xsl:value-of select="$actualParameterPrintableValue"/>
                                </actualValue>
                            </finding>
                        </xsl:for-each>
                    </xsl:if>
                </xsl:for-each>
            </findings>
        </xsl:if>

        <xsl:if test="$pre_test_result = 'false'  and $def_result = 'false' ">
            <xsl:variable name="getIE7InstallationResult">
                <xsl:value-of
                    select="xalan:nodeset($exDefinitionId)/descendant::extend_definition[@id = 'oval:com.mcafee.oval.ie7:def:627']/@result"
                />
            </xsl:variable>
            <xsl:if test="$getIE7InstallationResult = 'false' ">
                <findings id="{$definitionId}" xmlns="http://results.pa.mcafee.com/findings/5.2">
                    <finding messageId="com.mcafee.pa.msg.ie7isnotinstalled" isViolation="true"/>
                </findings>
            </xsl:if>
        </xsl:if>

    </xsl:template>

</xsl:stylesheet>
