<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"    
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >

<!-- (c) 2008, Trimble Navigation Limited. All rights reserved.                                -->
<!-- Permission is hereby granted to use, copy, modify, or distribute this style sheet for any -->
<!-- purpose and without fee, provided that the above copyright notice appears in all copies   -->
<!-- and that both the copyright notice and the limited warranty and restricted rights notice  -->
<!-- below appear in all supporting documentation.                                             -->

<!-- TRIMBLE NAVIGATION LIMITED PROVIDES THIS STYLE SHEET "AS IS" AND WITH ALL FAULTS.         -->
<!-- TRIMBLE NAVIGATION LIMITED SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF MERCHANTABILITY -->
<!-- OR FITNESS FOR A PARTICULAR USE. TRIMBLE NAVIGATION LIMITED DOES NOT WARRANT THAT THE     -->
<!-- OPERATION OF THIS STYLE SHEET WILL BE UNINTERRUPTED OR ERROR FREE.                        -->

<xsl:output method="text" omit-xml-declaration="yes" encoding="ISO-8859-1"/>

<!-- Set the numeric display details i.e. decimal point, thousands separator etc -->
<xsl:variable name="DecPt" select="'.'"/>    <!-- Change as appropriate for US/European -->
<xsl:variable name="GroupSep" select="','"/> <!-- Change as appropriate for US/European -->
<!-- Also change decimal-separator & grouping-separator in decimal-format below 
     as appropriate for US/European output -->
<xsl:decimal-format name="Standard" 
                    decimal-separator="."
                    grouping-separator=","
                    infinity="Infinity"
                    minus-sign="-"
                    NaN="            "
                    percent="%"
                    per-mille="&#2030;"
                    zero-digit="0" 
                    digit="#" 
                    pattern-separator=";" />

<xsl:variable name="DecPl0" select="'#0'"/>
<xsl:variable name="DecPl1" select="concat('#0', $DecPt, '0')"/>
<xsl:variable name="DecPl2" select="concat('#0', $DecPt, '00')"/>
<xsl:variable name="DecPl3" select="concat('#0', $DecPt, '000')"/>
<xsl:variable name="DecPl4" select="concat('#0', $DecPt, '0000')"/>
<xsl:variable name="DecPl5" select="concat('#0', $DecPt, '00000')"/>
<xsl:variable name="DecPl8" select="concat('#0', $DecPt, '00000000')"/>

<xsl:variable name="fileExt" select="'xyz'"/>

<!-- User variable definitions - Appropriate fields are displayed on the       -->
<!-- Survey Controller screen to allow the user to enter specific values       -->
<!-- which can then be used within the style sheet definition to control the   -->
<!-- output data.                                                              -->
<!--                                                                           -->
<!-- All user variables must be identified by a variable element definition    -->
<!-- named starting with 'userField' (case sensitive) followed by one or more  -->
<!-- characters uniquely identifying the user variable definition.             -->
<!--                                                                           -->
<!-- The text within the 'select' field for the user variable description      -->
<!-- references the actual user variable and uses the '|' character to         -->
<!-- separate the definition details into separate fields as follows:          -->
<!-- For all user variables the first field must be the name of the user       -->
<!-- variable itself (this is case sensitive) and the second field is the      -->
<!-- prompt that will appear on the Survey Controller screen.                  -->
<!-- The third field defines the variable type - there are four possible       -->
<!-- variable types: Double, Integer, String and StringMenu.  These variable   -->
<!-- type references are not case sensitive.                                   -->
<!-- The fields that follow the variable type change according to the type of  -->
<!-- variable as follow:                                                       -->
<!-- Double and Integer: Fourth field = optional minimum value                 -->
<!--                     Fifth field = optional maximum value                  -->
<!--   These minimum and maximum values are used by the Survey Controller for  -->
<!--   entry validation.                                                       -->
<!-- String: No further fields are needed or used.                             -->
<!-- StringMenu: Fourth field = number of menu items                           -->
<!--             Remaining fields are the actual menu items - the number of    -->
<!--             items provided must equal the specified number of menu items. -->
<!--                                                                           -->
<!-- The style sheet must also define the variable itself, named according to  -->
<!-- the definition.  The value within the 'select' field will be displayed in -->
<!-- the Survey Controller as the default value for the item.                  -->

<xsl:variable name="userField1" select="'codeSep|Kode seperator anvendt|String'"/>
<xsl:variable name="codeSep" select="'.'"/>

<!-- Define search keys to speed up searchs -->
<xsl:key name="obsPt-search" match="//JOBFile/FieldBook/PointRecord" use="@ID"/>

<!-- **************************************************************** -->
<!-- Set global variables from the Environment section of JobXML file -->
<!-- **************************************************************** -->
<xsl:variable name="DistUnit"   select="/JOBFile/Environment/DisplaySettings/DistanceUnits" />
<xsl:variable name="AngleUnit"  select="/JOBFile/Environment/DisplaySettings/AngleUnits" />
<xsl:variable name="CoordOrder" select="/JOBFile/Environment/DisplaySettings/CoordinateOrder" />
<xsl:variable name="TempUnit"   select="/JOBFile/Environment/DisplaySettings/TemperatureUnits" />
<xsl:variable name="PressUnit"  select="/JOBFile/Environment/DisplaySettings/PressureUnits" />

<!-- Setup conversion factor for coordinate and distance values -->
<!-- Dist/coord values in JobXML file are always in metres -->
<xsl:variable name="DistConvFactor">
  <xsl:choose>
    <xsl:when test="$DistUnit='Metres'">1.0</xsl:when>
    <xsl:when test="$DistUnit='InternationalFeet'">3.280839895</xsl:when>
    <xsl:when test="$DistUnit='USSurveyFeet'">3.2808333333357</xsl:when>
    <xsl:otherwise>1.0</xsl:otherwise>
  </xsl:choose>
</xsl:variable>

<!-- Setup conversion factor for angular values -->
<!-- Angular values in JobXML file are always in decimal degrees -->
<xsl:variable name="AngleConvFactor">
  <xsl:choose>
    <xsl:when test="$AngleUnit='DMSDegrees'">1.0</xsl:when>
    <xsl:when test="$AngleUnit='Gons'">1.111111111111</xsl:when>
    <xsl:when test="$AngleUnit='Mils'">17.77777777777</xsl:when>
    <xsl:otherwise>1.0</xsl:otherwise>
  </xsl:choose>
</xsl:variable>

<!-- Setup boolean variable for coordinate order -->
<xsl:variable name="NECoords">
  <xsl:choose>
    <xsl:when test="$CoordOrder='North-East-Elevation'">
      <xsl:value-of select="'True'"/>
    </xsl:when>
    <xsl:when test="$CoordOrder='X-Y-Z'">
      <xsl:value-of select="'True'"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="'False'"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:variable>

<!-- Setup conversion factor for pressure values -->
<!-- Pressure values in JobXML file are always in millibars (hPa) -->
<xsl:variable name="PressConvFactor">
  <xsl:choose>
    <xsl:when test="$PressUnit='MilliBar'">1.0</xsl:when>
    <xsl:when test="$PressUnit='InchHg'">0.029529921</xsl:when>
    <xsl:when test="$PressUnit='mmHg'">0.75006</xsl:when>
    <xsl:otherwise>1.0</xsl:otherwise>
  </xsl:choose>
</xsl:variable>

<!-- **************************************************************** -->
<!-- ************************** Main Loop *************************** -->
<!-- **************************************************************** -->
<xsl:template match="/" >
  <!-- Select Reductions node to process -->
  <xsl:apply-templates select="JOBFile/Reductions" />
</xsl:template>


<!-- **************************************************************** -->
<!-- ***************** Reductions Node Processing ******************* -->
<!-- **************************************************************** -->
<xsl:template match="Reductions">
  <xsl:apply-templates select="Point"/> 
</xsl:template>


<!-- **************************************************************** -->
<!-- **************** Grid Point Details Output ********************* -->
<!-- **************************************************************** -->
<xsl:template match="Point">
  <xsl:variable name="NameStr">
    <xsl:call-template name="PadRight">
      <xsl:with-param name="StringWidth" select="14"/>
      <xsl:with-param name="TheString">
        <xsl:value-of select="Name" />
      </xsl:with-param>
    </xsl:call-template>
  </xsl:variable>

  <xsl:variable name="NthStr">
    <xsl:call-template name="PadLeft">
      <xsl:with-param name="StringWidth" select="12"/>
      <xsl:with-param name="TheString">
        <xsl:value-of select="format-number(Grid/North * $DistConvFactor, $DecPl3, 'Standard')" />
      </xsl:with-param>
    </xsl:call-template>
  </xsl:variable>

  <xsl:variable name="EastStr">
    <xsl:call-template name="PadLeft">
      <xsl:with-param name="StringWidth" select="12"/>
      <xsl:with-param name="TheString">
        <xsl:value-of select="format-number(Grid/East * $DistConvFactor, $DecPl3, 'Standard')" />
      </xsl:with-param>
    </xsl:call-template>
  </xsl:variable>

  <xsl:variable name="ElevStr">
    <xsl:call-template name="PadLeft">
      <xsl:with-param name="StringWidth" select="12"/>
      <xsl:with-param name="TheString">
        <xsl:value-of select="format-number(Grid/Elevation * $DistConvFactor, $DecPl3, 'Standard')"/>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:variable>

  <xsl:variable name="stdCode">
    <xsl:call-template name="PadRight">
      <xsl:with-param name="StringWidth" select="8"/>
      <xsl:with-param name="TheString">
        <xsl:choose>
          <xsl:when test="contains(Code, $codeSep)">
            <xsl:value-of select="substring-before(Code, $codeSep)"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="Code"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:variable>

  <xsl:variable name="lineCode">
    <xsl:call-template name="PadRight">
      <xsl:with-param name="StringWidth" select="2"/>
      <xsl:with-param name="TheString">
        <xsl:choose>
          <xsl:when test="contains(Code, $codeSep)">
          <xsl:value-of select="substring-after(Code, $codeSep)"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="''"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:variable>

  <xsl:value-of select="concat($NameStr, $NthStr, $EastStr, $ElevStr)"/>
  <xsl:call-template name="NewLine"/>

</xsl:template>


<!-- **************************************************************** -->
<!-- ************ Output Angle in Appropriate Format **************** -->
<!-- **************************************************************** -->
<xsl:template name="AngleValue">
  <xsl:param name="TheAngle"/>
  <xsl:choose>
    <!-- Null angle value -->
    <xsl:when test="string(number($TheAngle))='NaN'">
      <xsl:value-of select="'?'"/>
    </xsl:when>
    <!-- There is an angle value -->
    <xsl:otherwise>
      <xsl:choose>
        <xsl:when test="$AngleUnit='DMSDegrees'">
          <xsl:variable name="Sign">
            <xsl:choose>
              <xsl:when test="$TheAngle &lt; '0.0'">
                -1
              </xsl:when>
              <xsl:otherwise>
                1
              </xsl:otherwise>
            </xsl:choose> 
          </xsl:variable>
          <!-- Convert to a positive angle before changing to DMS format -->
          <xsl:variable name="PosAngle" select="$TheAngle * $Sign"/>

          <xsl:variable name="rawDeg" select="floor($PosAngle)"/>
          <xsl:variable name="MinDec" select="($PosAngle - $rawDeg)*60"/>
          <xsl:variable name="rawMin" select="floor($MinDec)"/>
          <xsl:variable name="SecDec" select="($MinDec - $rawMin)*60"/>
          <xsl:variable name="rawSec" select="format-number($SecDec, $DecPl0, 'Standard')"/>

          <xsl:variable name="Sec">
            <xsl:call-template name="correctedSeconds">
              <xsl:with-param name="rawSec" select="$rawSec"/>
            </xsl:call-template>
          </xsl:variable>

          <xsl:variable name="Min">
            <xsl:call-template name="correctedMinutes">
              <xsl:with-param name="rawMin" select="$rawMin"/>
              <xsl:with-param name="rawSec" select="$rawSec"/>
            </xsl:call-template>
          </xsl:variable>

          <xsl:variable name="Deg">
            <xsl:call-template name="correctedDegrees">
              <xsl:with-param name="rawDeg" select="$rawDeg"/>
              <xsl:with-param name="rawMin" select="$rawMin"/>
              <xsl:with-param name="rawSec" select="$rawSec"/>
            </xsl:call-template>
          </xsl:variable>

          <xsl:variable name="SignStr">
            <xsl:if test="$Sign &lt; '0'">-</xsl:if>
          </xsl:variable>
          <xsl:variable name="MinPrefix">
            <xsl:if test="string-length(string($Min)) = '1'">0</xsl:if>
          </xsl:variable>
          <xsl:variable name="SecPrefix">
            <xsl:if test="string-length(string($Sec)) = '1'">0</xsl:if>
          </xsl:variable>

          <xsl:value-of select="concat($SignStr, $Deg, '&#0176;', $MinPrefix, $Min, '&#8217;', $SecPrefix, $Sec, '&#8221;')"/>
        </xsl:when>

        <xsl:when test="$AngleUnit='Gons'">
          <xsl:value-of select="format-number($TheAngle * $AngleConvFactor, $DecPl5, 'Standard')"/>
        </xsl:when>

        <xsl:when test="$AngleUnit='Mils'">
          <xsl:value-of select="format-number($TheAngle * $AngleConvFactor, $DecPl4, 'Standard')"/>
        </xsl:when>

        <xsl:when test="$AngleUnit='DecimalDegrees'">
          <xsl:value-of select="format-number($TheAngle * $AngleConvFactor, $DecPl5, 'Standard')"/>
        </xsl:when>
      </xsl:choose>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>


<!-- **************************************************************** -->
<!-- ********** Correct the Seconds Value When Seconds = 60 ********* -->
<!-- **************************************************************** -->
<xsl:template name="correctedSeconds">
  <xsl:param name="rawSec"/>

  <xsl:choose>
    <xsl:when test="floor($rawSec) = 60">
      <xsl:value-of select="$rawSec - 60"/>  <!-- Remove the extraneous 60 seconds -->
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$rawSec"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>


<!-- **************************************************************** -->
<!-- ********** Correct the Minutes Value When Seconds = 60 ********* -->
<!-- **************************************************************** -->
<xsl:template name="correctedMinutes">
  <xsl:param name="rawMin"/>
  <xsl:param name="rawSec"/>

  <xsl:choose>
    <xsl:when test="floor($rawSec) = 60">
      <xsl:variable name="newMin" select="$rawMin + 1"/>  <!-- Need to add an extra minute -->
      <xsl:choose>
        <xsl:when test="$newMin = 60">     <!-- Now have 60 minutes - need to return zero minutes -->
          <xsl:value-of select="0"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$newMin"/> <!-- Just return incremented minutes value -->
        </xsl:otherwise>
      </xsl:choose>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$rawMin"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>


<!-- **************************************************************** -->
<!-- ********** Correct the Degrees Value When Seconds = 60 ********* -->
<!-- **************************************************************** -->
<xsl:template name="correctedDegrees">
  <xsl:param name="rawDeg"/>
  <xsl:param name="rawMin"/>
  <xsl:param name="rawSec"/>

  <xsl:choose>
    <xsl:when test="floor($rawSec) = 60">
      <xsl:variable name="newMin" select="$rawMin + 1"/>  <!-- Need to add an extra minute -->
      <xsl:choose>
        <xsl:when test="$newMin = 60">     <!-- Now have 60 minutes - need to return add 1 degree -->
          <xsl:variable name="newDeg" select="$rawDeg + 1"/>  <!-- Add an extra degree -->
            <xsl:choose>
              <xsl:when test="$newDeg = 360">
                <xsl:value-of select="0"/> <!-- Return 0 degrees rather than 360 degrees -->
              </xsl:when>
              <xsl:otherwise>
                <xsl:value-of select="$newDeg"/> <!-- Just return incremented degrees value -->
              </xsl:otherwise>
            </xsl:choose>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$rawDeg"/> <!-- Just return original degrees value -->
        </xsl:otherwise>
      </xsl:choose>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$rawDeg"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>


<!-- **************************************************************** -->
<!-- *************** Feature and Attributes Output ****************** -->
<!-- **************************************************************** -->
<xsl:template name="OutputAttributes">
  <xsl:param name="PtID"/>
  <xsl:for-each select="//JOBFile/FieldBook/*">
    <xsl:if test="@ID=$PtID">
      <xsl:if test="FeaturesRecord">
        <xsl:for-each select="FeaturesRecord/Feature">
          <xsl:value-of select="'Feature: '"/>
          <xsl:value-of select="@Name"/>
          <xsl:value-of select="' '"/>
          <xsl:for-each select="Attribute">
            <xsl:if test="position() &gt; 1"><xsl:value-of select="','"/></xsl:if>
            <xsl:value-of select="Name"/>
            <xsl:value-of select="','"/>
            <xsl:value-of select="Value"/>
          </xsl:for-each>
        <xsl:call-template name="NewLine"/>
        </xsl:for-each>
      </xsl:if>
    </xsl:if>
  </xsl:for-each>

</xsl:template>


<!-- **************************************************************** -->
<!-- ****************** Separating Line Output ********************** -->
<!-- **************************************************************** -->
<xsl:template name="SeparatingLine">
  <hr/>
</xsl:template>


<!-- **************************************************************** -->
<!-- ********************* Blank Line Output ************************ -->
<!-- **************************************************************** -->
<xsl:template name="BlankLine">
  <xsl:call-template name="NewLine"/>
  <xsl:call-template name="NewLine"/>
</xsl:template>


<!-- **************************************************************** -->
<!-- ********************** New Line Output ************************* -->
<!-- **************************************************************** -->
<xsl:template name="NewLine">
<xsl:text>&#10;</xsl:text>
</xsl:template>


<!-- **************************************************************** -->
<!-- *********** Pad a string to the right with spaces ************** -->
<!-- **************************************************************** -->
<xsl:template name="PadRight">
  <xsl:param name="StringWidth"/>
  <xsl:param name="TheString"/>
  <xsl:choose>
    <xsl:when test="$StringWidth = '0'">
      <xsl:value-of select="normalize-space($TheString)"/> <!-- Function return value -->
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="PaddedStr" select="concat($TheString, '                                       ')"/>
      <xsl:value-of select="substring($PaddedStr, 1, $StringWidth)"/> <!-- Function return value -->
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>


<!-- **************************************************************** -->
<!-- *********** Pad a string to the left with spaces *************** -->
<!-- **************************************************************** -->
<xsl:template name="PadLeft">
  <xsl:param name="StringWidth"/>
  <xsl:param name="TheString"/>
  <xsl:choose>
    <xsl:when test="$StringWidth = '0'">
      <xsl:value-of select="normalize-space($TheString)"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="PaddedStr" select="concat('                                       ', $TheString)"/>
      <xsl:value-of select="substring($PaddedStr, string-length($PaddedStr) - $StringWidth + 1)"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>


<!-- **************************************************************** -->
<!-- ****************** Return the absolute value ******************* -->
<!-- **************************************************************** -->
<xsl:template name="Abs">
  <xsl:param name="TheValue"/>
  <xsl:variable name="Sign">
    <xsl:choose>
      <xsl:when test="$TheValue &lt; '0.0'">
        -1
      </xsl:when>
      <xsl:otherwise>
        1
      </xsl:otherwise>
    </xsl:choose> 
  </xsl:variable>

  <xsl:value-of select="number($Sign * $TheValue)"/>
</xsl:template>


<!-- **************************************************************** -->
<!-- *************** Return the square root of a value ************** -->
<!-- **************************************************************** -->
<xsl:template name="Sqrt">
  <xsl:param name="num" select="0"/>       <!-- The number you want to find the square root of -->
  <xsl:param name="try" select="1"/>       <!-- The current 'try'.  This is used internally. -->
  <xsl:param name="iter" select="1"/>      <!-- The current iteration, checked against maxiter to limit loop count - used internally -->
  <xsl:param name="maxiter" select="10"/>  <!-- Set this up to insure against infinite loops - used internally -->

  <!-- This template uses Sir Isaac Newton's method of finding roots -->

  <xsl:choose>
    <xsl:when test="$try * $try = $num or $iter &gt; $maxiter">
      <xsl:value-of select="$try"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:call-template name="Sqrt">
        <xsl:with-param name="num" select="$num"/>
        <xsl:with-param name="try" select="$try - (($try * $try - $num) div (2 * $try))"/>
        <xsl:with-param name="iter" select="$iter + 1"/>
        <xsl:with-param name="maxiter" select="$maxiter"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>


</xsl:stylesheet>