<?xml version="1.0" encoding="iso-8859-1"?>

<!-- =========================================================== -->
<!--                                                             -->
<!-- © 2000, RenderX.                                            -->
<!--                                                             -->
<!-- Author: Nikolai Grigoriev <grig@renderx.com>                -->
<!--                                                             -->
<!-- Permission is granted to use this document, copy and        -->
<!-- modify free of charge, provided that every derived work     -->
<!-- bear a reference to the present document.                   -->
<!--                                                             -->
<!-- This document contains a computer program written in        -->
<!-- XSL Transformations Language. It is published with no       -->
<!-- warranty of any kind about its usability, as a mere         -->
<!-- example of XSL technology. RenderX declines every           -->
<!-- responsibility for any damage or loss of data caused by     -->
<!-- use of this program.                                        -->
<!--                                                             -->
<!-- =========================================================== -->

<!-- This stylesheet exports a named template that draw barcodes -->
<!-- using EAN-13, EAN-8, UPC-A, or UPC-E encoding scheme. The   --> 
<!-- stylesheet produces a barcode pattern as an XSL Formatting  -->
<!-- Objects table (<fo:table>). The formatting objects version  -->
<!-- used is WD-1999-04-21. To convert the stylesheet to the     -->
<!-- last version (WD-1999-03-21 on the date of creation of the  -->
<!-- stylesheet), change the namespace declaration (xmlns:fo     -->
<!-- attribute of the xsl:stylesheet element) to the following:  -->
<!--                                                             -->
<!--     xmlns:fo="http://www.w3.org/1999/XSL/Format"            -->
<!--                                                             -->
<!-- and replace all occurrences of the following attributes:    -->
<!--                                                             -->
<!--   n-columns-spanned  by  number-columns-spanned             -->
<!--   n-rows-spanned  by  number-rows-spanned                   -->
<!--   page-break-inside="avoid"  by  keep-together="always"     -->
<!--                                                             -->

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:fo="http://www.w3.org/XSL/Format/1.0">

<!-- ========================================================= -->
<!-- Draw an EAN/UPC barcode. The template provides for check  -->
<!-- digit calculation. It assumes the argument is exactly     -->
<!-- 6,7, 11 or 12 digits long. The barcodes produced are of   -->
<!-- the following type:                                       -->
<!--    6 digits - UPC E, number system 0 (zero is prepended)  -->
<!--    7 digits - UPC E or EAN 8                              -->
<!--   11 digits - UPC A                                       -->
<!--   12 digits - EAN 13                                      -->
<!-- You can override the default barcode treatment and set    -->
<!-- code-type parameter explicitly; this is required to       -->
<!-- distinguish between EAN 8 and UPC E codes when the latter -->
<!-- starts with 1.                                            -->
<!--                                                           -->
<!--  Parameters:                                              -->
<!--  "value" - a string of digits to encode. Digits may be    -->
<!--             separated by spaces, commas, dots, or dashes. -->
<!--  "code-type" - one of 'EAN-13', 'EAN-8', 'UPC-A', 'UPC-E'.-->
<!--             Default depends on $value string length; for  -->
<!--             7-digit sequences, default is EAN-8.          -->
<!--  "module" - width of the elementary unit bar/space.       -->
<!--             Default is 0.33 mm (0.013 in).                -->
<!--  "height" - pattern height (= bar length). Default is     -->
<!--             23 mm for EAN-13 and UPC-A, 18 mm for EAN-8,  -->
<!--             and 14 mm for UPC-E.                          -->
<!--                                                           -->
<!-- IMPORTANT: the $value parameter should not include the    -->
<!-- check digit (the last digit on the barcode patterns) -    -->
<!-- it will be generated automatically by the stylesheet.     -->
<!--                                                           -->
<!-- The topmost template performs length checks and           -->
<!-- calculates defaults for parameters, then calls the        -->
<!-- principal template. If the length of the input string     -->
<!-- does not match the specified barcode type, a fo:block     -->
<!-- with an error message is generated instead.               -->

<xsl:template name="barcode-EAN">
  <xsl:param name="value"/>
  <xsl:param name="code-type" select="'auto'"/>
  <xsl:param name="module" select="'0.33mm'"/> 
  <xsl:param name="height" select="'auto'"/> 

  <!-- Remove separators -->
  <xsl:variable name="cleaned-value" 
        select="translate ($value, '0123456789 &#x9;&#xA;-,.:;', '0123456789')"/> 

  <!-- Calculate the default code type -->
  <xsl:variable name="real-code-type">    
    <xsl:choose>
      <xsl:when test="$code-type != 'auto'">
        <xsl:value-of select="$code-type"/>
      </xsl:when>
 
      <xsl:when test="string-length($cleaned-value) = 6">UPC-E</xsl:when>
      <xsl:when test="string-length($cleaned-value) = 7">EAN-8</xsl:when>
      <xsl:when test="string-length($cleaned-value) = 11">UPC-A</xsl:when>
      <xsl:when test="string-length($cleaned-value) = 12">EAN-13</xsl:when>
      <xsl:otherwise>ERROR</xsl:otherwise>
    </xsl:choose>
  </xsl:variable>

  <!-- Add a leading zero to 6-digit UPC-E codes -->
  <xsl:variable name="real-value">    
    <xsl:choose> 
      <xsl:when test="$real-code-type = 'UPC-E' and string-length($cleaned-value) = 6">
        <xsl:value-of select="concat('0', $cleaned-value)"/>
      </xsl:when>
      <xsl:otherwise><xsl:value-of select="$cleaned-value"/></xsl:otherwise>
    </xsl:choose>
  </xsl:variable>

  <!-- Calculate the default height for various code types -->
  <xsl:variable name="real-height">    
    <xsl:choose>
      <xsl:when test="$height != 'auto'">
        <xsl:value-of select="$code-type"/>
      </xsl:when>
      <xsl:when test="$real-code-type = 'EAN-13'">23mm</xsl:when>
      <xsl:when test="$real-code-type = 'UPC-A'">23mm</xsl:when>
      <xsl:when test="$real-code-type = 'EAN-8'">18mm</xsl:when>
      <xsl:when test="$real-code-type = 'UPC-E'">14mm</xsl:when>
      <xsl:otherwise>ERROR</xsl:otherwise>
    </xsl:choose>
  </xsl:variable>

  <!-- Check data for consistency and invoke the processing template -->
  <xsl:choose>
    <xsl:when test="(string-length($real-value) = 7 and $real-code-type = 'UPC-E')
                 or (string-length($real-value) = 7 and $real-code-type = 'EAN-8')
                 or (string-length($real-value) = 11 and $real-code-type = 'UPC-A')
                 or (string-length($real-value) = 12 and $real-code-type = 'EAN-13')">
      <xsl:call-template name="draw-barcode-EAN">
        <xsl:with-param name="value" select="$real-value"/>
        <xsl:with-param name="module" select="$module"/>
        <xsl:with-param name="height" select="$real-height"/>
        <xsl:with-param name="code-type" select="$real-code-type"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <!-- Error: print a block with an error message -->
      <fo:block font-weight="bold">WRONG BARCODE PARAMETERS</fo:block>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<!-- ========================================================= -->
<!-- Real processing.                                          -->
<!-- This template has the same parameters as the one before;  -->
<!-- it gets the processed arguments and does not perform any  -->
<!-- error checking.                                           -->

<xsl:template name="draw-barcode-EAN">
  <xsl:param name="value"/>
  <xsl:param name="code-type"/>
  <xsl:param name="module"/> 
  <xsl:param name="height"/> 

  <!-- Parse module width specifier -->
  <xsl:variable name="numeric-value" 
    select="translate ($module, '-0123456789.ptxcinme', '-0123456789.')"/>
  <xsl:variable name="unit" 
    select="translate ($module, 'ptxcinme-0123456789.', 'ptxcinme')"/>

  <!-- Calculate font height (equal to one character pattern) -->
  <xsl:variable name="font-height">
    <xsl:value-of select="$numeric-value * 11"/>
    <xsl:value-of select="$unit"/>
  </xsl:variable>

  <!-- Calculate check digit -->
  <xsl:variable name="check-digit">
    <xsl:call-template name="EAN-check-digit">
      <xsl:with-param name="value" select="$value"/>
      <xsl:with-param name="code-type" select="$code-type"/>
    </xsl:call-template>
  </xsl:variable>

  <!-- Get the left-side pattern corresponding to the first digit -->
  <xsl:variable name="left-pattern">
    <xsl:choose>
      <xsl:when test="$code-type = 'EAN-13'">
        <xsl:call-template name="get-pattern-EAN-13">
          <xsl:with-param name="switch" select="substring($value,1,1)"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:when test="$code-type = 'UPC-A'">AAAAAA</xsl:when>
      <xsl:when test="$code-type = 'EAN-8'">AAAA</xsl:when>
      <xsl:when test="$code-type = 'UPC-E' and substring($value, 1, 1) = '0'">
        <xsl:call-template name="get-pattern-UPC-E0">
          <xsl:with-param name="switch" select="$check-digit"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:when test="$code-type = 'UPC-E' and substring($value, 1, 1) = '1'">
        <xsl:call-template name="get-pattern-UPC-E1">
          <xsl:with-param name="switch" select="$check-digit"/>
        </xsl:call-template>
      </xsl:when>
    </xsl:choose>
  </xsl:variable>

  <!-- Get the right-side pattern. UPC-E has no right side. -->
  <xsl:variable name="right-pattern">
    <xsl:choose>
      <xsl:when test="$code-type = 'EAN-13'">AAAAAA</xsl:when>
      <xsl:when test="$code-type = 'UPC-A'">AAAAAA</xsl:when>
      <xsl:when test="$code-type = 'EAN-8'">AAAA</xsl:when>
    </xsl:choose>
  </xsl:variable>

  <!-- Get the left-side string -->
  <xsl:variable name="left-value">
    <xsl:choose>
      <xsl:when test="$code-type = 'EAN-13'">
        <xsl:value-of select="substring($value, 2, 6)"/>
      </xsl:when>
      <xsl:when test="$code-type = 'UPC-A'">
        <xsl:value-of select="substring($value, 1, 6)"/>
      </xsl:when>
      <xsl:when test="$code-type = 'EAN-8'">
        <xsl:value-of select="substring($value, 1, 4)"/>
      </xsl:when>
      <xsl:when test="$code-type = 'UPC-E'">
        <xsl:value-of select="substring($value, 2, 6)"/>
      </xsl:when>
    </xsl:choose>
  </xsl:variable>

  <!-- Get the right-side string. UPC-E has no right side. -->
  <xsl:variable name="right-value">
    <xsl:choose>
      <xsl:when test="$code-type = 'EAN-13'">
        <xsl:value-of select="concat(substring($value, 8, 5), $check-digit)"/>
      </xsl:when>
      <xsl:when test="$code-type = 'UPC-A'">
        <xsl:value-of select="concat(substring($value, 7, 5), $check-digit)"/>
      </xsl:when>
      <xsl:when test="$code-type = 'EAN-8'">
        <xsl:value-of select="concat(substring($value, 5, 3), $check-digit)"/>
      </xsl:when>
    </xsl:choose>
  </xsl:variable>

  <!-- Useful value - number of short bars/spaces on either side -->
  <xsl:variable name="pattern-length">
    <xsl:choose>
      <xsl:when test="$code-type = 'EAN-13'">24</xsl:when>
      <xsl:when test="$code-type = 'UPC-A'">20</xsl:when>
      <xsl:when test="$code-type = 'EAN-8'">16</xsl:when>
      <xsl:when test="$code-type = 'UPC-E'">24</xsl:when>
    </xsl:choose>
  </xsl:variable>

  <!-- ====================================================== -->
  <!-- Build up a table -->
  <fo:table page-break-inside="avoid">

    <!-- First digit - for EAN 13, UPC A and UPC E -->
    <xsl:if test="$code-type != 'EAN-8'">
      <fo:table-column column-width="{$font-height}"/>
    </xsl:if>

    <!-- Leading guides -->
    <fo:table-column column-width="{$numeric-value}{$unit}"/>
    <fo:table-column column-width="{$numeric-value}{$unit}"/>
    <fo:table-column column-width="{$numeric-value}{$unit}"/>

    <!-- Encoding the left side characters -->
    <xsl:call-template name="emit-EAN-character-patterns">
      <xsl:with-param name="value" select="$left-value"/>
      <xsl:with-param name="pattern" select="$left-pattern"/>
      <xsl:with-param name="numeric-value" select="$numeric-value"/>
      <xsl:with-param name="unit" select="$unit"/>
    </xsl:call-template>

    <!-- Center guides -->
    <fo:table-column column-width="{$numeric-value}{$unit}"/>
    <fo:table-column column-width="{$numeric-value}{$unit}"/>
    <fo:table-column column-width="{$numeric-value}{$unit}"/>
    <fo:table-column column-width="{$numeric-value}{$unit}"/>
    <fo:table-column column-width="{$numeric-value}{$unit}"/>

    <!-- For UPC-E, we should only add one bar; for others, we print the right side -->
    <xsl:choose>
      <xsl:when test="$code-type = 'UPC-E'">
        <fo:table-column column-width="{$numeric-value}{$unit}"/>
      </xsl:when>
      <xsl:otherwise>
        <!-- Encoding the right-side characters, plus the check digit -->
        <xsl:call-template name="emit-EAN-character-patterns">
          <xsl:with-param name="value" select="$right-value"/>
          <xsl:with-param name="pattern" select="$right-pattern"/>
          <xsl:with-param name="numeric-value" select="$numeric-value"/>
          <xsl:with-param name="unit" select="$unit"/>
        </xsl:call-template>

        <!-- Trailing guides -->
        <fo:table-column column-width="{$numeric-value}{$unit}"/> 
        <fo:table-column column-width="{$numeric-value}{$unit}"/> 
        <fo:table-column column-width="{$numeric-value}{$unit}"/> 
      </xsl:otherwise>
    </xsl:choose>

    <!-- Last digit - for UPC-A and UPC-E -->
    <xsl:if test="$code-type = 'UPC-A' or $code-type = 'UPC-E'">
      <fo:table-column column-width="{$font-height}"/>
    </xsl:if>
 
    <!-- Table body -->
    <fo:table-body>
      <fo:table-row row-height="{$height}">

        <!-- First digit - for EAN 13, UPC A and UPC E -->
        <xsl:if test="$code-type != 'EAN-8'">
          <fo:table-cell><fo:block/></fo:table-cell>
        </xsl:if>

        <!-- Leading guides -->
        <fo:table-cell background-color="black" n-rows-spanned="2"><fo:block/></fo:table-cell> 
        <fo:table-cell n-rows-spanned="2"><fo:block/></fo:table-cell>
        <fo:table-cell background-color="black" n-rows-spanned="2"><fo:block/></fo:table-cell>

        <!-- Left-side characters -->

        <!-- In UPC-A, the first character bars are longer -->
        <xsl:if test="$code-type = 'UPC-A'">
          <fo:table-cell n-rows-spanned="2"><fo:block/></fo:table-cell>
          <fo:table-cell background-color="black" n-rows-spanned="2"><fo:block/></fo:table-cell> 
          <fo:table-cell n-rows-spanned="2"><fo:block/></fo:table-cell>
          <fo:table-cell background-color="black" n-rows-spanned="2"><fo:block/></fo:table-cell>
        </xsl:if>

        <xsl:call-template name="repeat-cells">
          <xsl:with-param name="number-of-cells" select="$pattern-length"/>
        </xsl:call-template>

        <!-- Center guides -->
        <fo:table-cell><fo:block/></fo:table-cell>
        <fo:table-cell background-color="black" n-rows-spanned="2"><fo:block/></fo:table-cell> 
        <fo:table-cell n-rows-spanned="2"><fo:block/></fo:table-cell>
        <fo:table-cell background-color="black" n-rows-spanned="2"><fo:block/></fo:table-cell>

        <!-- For UPC-E, add one more space and one more bar -->
        <!-- For others, proceed to the right side          -->
        <xsl:choose>
          <xsl:when test="$code-type = 'UPC-E'">
            <fo:table-cell n-rows-spanned="2"><fo:block/></fo:table-cell>
            <fo:table-cell background-color="black" n-rows-spanned="2"><fo:block/></fo:table-cell>
          </xsl:when>
          <xsl:otherwise>
            <fo:table-cell><fo:block/></fo:table-cell>

            <!-- Right-side characters -->
            <xsl:call-template name="repeat-cells">
              <xsl:with-param name="number-of-cells" select="$pattern-length - 1"/>
            </xsl:call-template>
            <fo:table-cell><fo:block/></fo:table-cell>

            <!-- In UPC-A, the last character bars are longer -->
            <xsl:if test="$code-type = 'UPC-A'">
              <fo:table-cell background-color="black" n-rows-spanned="2"><fo:block/></fo:table-cell>
              <fo:table-cell n-rows-spanned="2"><fo:block/></fo:table-cell>
              <fo:table-cell background-color="black" n-rows-spanned="2"><fo:block/></fo:table-cell> 
              <fo:table-cell n-rows-spanned="2"><fo:block/></fo:table-cell>
            </xsl:if>

            <!-- Trailing guides -->
            <fo:table-cell background-color="black" n-rows-spanned="2"><fo:block/></fo:table-cell> 
            <fo:table-cell n-rows-spanned="2"><fo:block/></fo:table-cell>
            <fo:table-cell background-color="black" n-rows-spanned="2"><fo:block/></fo:table-cell>
          </xsl:otherwise>
        </xsl:choose>

        <!-- Last digit - for UPC-A and UPC-E -->
        <xsl:if test="$code-type = 'UPC-A' or $code-type = 'UPC-E'">
          <fo:table-cell><fo:block/></fo:table-cell>
        </xsl:if>
      </fo:table-row>


      <!-- Digit symbols -->
      <fo:table-row row-height="{$numeric-value * 6}{$unit}"
                    font="{$font-height} Helvetica"
                    text-align="centered">

        <!-- First digit - for EAN 13, UPC A and UPC E -->
        <xsl:if test="$code-type != 'EAN-8'">
          <fo:table-cell n-rows-spanned="2">
            <fo:block padding="{$module}">
              <xsl:value-of select="substring($value, 1, 1)"/>
            </fo:block>
          </fo:table-cell>
        </xsl:if>
         
        <!-- Left side -->
        <fo:table-cell n-columns-spanned="{$pattern-length + 1}"  
                       n-rows-spanned="2">
          <fo:block padding="{$module}">
            <xsl:choose>
              <xsl:when test="$code-type = 'UPC-A'">
                <xsl:value-of select="substring($left-value, 2, 5)"/>
              </xsl:when>
              <xsl:otherwise>
                <xsl:value-of select="$left-value"/>
              </xsl:otherwise>
            </xsl:choose>
          </fo:block>
        </fo:table-cell>

        <!-- Right side - for everything except UPC-E -->
        <xsl:if test="$code-type != 'UPC-E'">
          <fo:table-cell n-columns-spanned="{$pattern-length + 1}" 
                         n-rows-spanned="2">
            <fo:block padding="{$module}">
              <xsl:choose>
                <xsl:when test="$code-type = 'UPC-A'">
                  <xsl:value-of select="substring($right-value, 1, 5)"/>
                </xsl:when>
                <xsl:otherwise>
                  <xsl:value-of select="$right-value"/>
                </xsl:otherwise>
              </xsl:choose>
            </fo:block>
          </fo:table-cell>
        </xsl:if> 

        <!-- Last digit - for UPC-A and UPC-E -->
        <xsl:if test="$code-type = 'UPC-A' or $code-type = 'UPC-E'">
          <fo:table-cell n-rows-spanned="2">
            <fo:block padding="{$module}">
              <xsl:value-of select="$check-digit"/>
            </fo:block>
          </fo:table-cell>
        </xsl:if>
      </fo:table-row>

    </fo:table-body>
  </fo:table>

</xsl:template>

  
<!-- =========================================================== -->
<!-- Recursive template to print out a specified number of cells -->

<xsl:template name="repeat-cells">
  <xsl:param name="number-of-cells"/>

  <xsl:if test="$number-of-cells &gt; 0">
    <fo:table-cell>
      <xsl:if test="$number-of-cells mod 2 = 1">
        <xsl:attribute name="background-color">black</xsl:attribute> 
      </xsl:if>
      <fo:block/>
    </fo:table-cell>  

    <xsl:call-template name="repeat-cells">
      <xsl:with-param name="number-of-cells" 
                      select="$number-of-cells - 1"/>
    </xsl:call-template>

  </xsl:if>
</xsl:template>

<!-- =========================================================== -->
<!-- Get hidden digit pattern for EAN-13                         -->

<xsl:template name="get-pattern-EAN-13">
  <xsl:param name="switch"/>
  <xsl:choose>
    <xsl:when test="$switch='0'">AAAAAA</xsl:when>
    <xsl:when test="$switch='1'">AABABB</xsl:when>
    <xsl:when test="$switch='2'">AABBAB</xsl:when>
    <xsl:when test="$switch='3'">AABBBA</xsl:when>
    <xsl:when test="$switch='4'">ABAABB</xsl:when>
    <xsl:when test="$switch='5'">ABBAAB</xsl:when>
    <xsl:when test="$switch='6'">ABBBAA</xsl:when>
    <xsl:when test="$switch='7'">ABABAB</xsl:when>
    <xsl:when test="$switch='8'">ABABBA</xsl:when>
    <xsl:when test="$switch='9'">ABBABA</xsl:when>
  </xsl:choose>
</xsl:template>

<!-- =========================================================== -->
<!-- Get hidden digit pattern for UPC-E, number system 0         -->

<xsl:template name="get-pattern-UPC-E0">
  <xsl:param name="switch"/>
  <xsl:choose>
    <xsl:when test="$switch='0'">BBBAAA</xsl:when>
    <xsl:when test="$switch='1'">BBABAA</xsl:when>
    <xsl:when test="$switch='2'">BBAABA</xsl:when>
    <xsl:when test="$switch='3'">BBAAAB</xsl:when>
    <xsl:when test="$switch='4'">BABBAA</xsl:when>
    <xsl:when test="$switch='5'">BAABBA</xsl:when>
    <xsl:when test="$switch='6'">BAAABB</xsl:when>
    <xsl:when test="$switch='7'">BABABA</xsl:when>
    <xsl:when test="$switch='8'">BABAAB</xsl:when>
    <xsl:when test="$switch='9'">BAABAB</xsl:when>
  </xsl:choose>
</xsl:template>

<!-- =========================================================== -->
<!-- Get hidden digit pattern for UPC-E, number system 1         -->

<xsl:template name="get-pattern-UPC-E1">
  <xsl:param name="switch"/>
  <xsl:choose>
    <xsl:when test="$switch='0'">AAABBB</xsl:when>
    <xsl:when test="$switch='1'">AABABB</xsl:when>
    <xsl:when test="$switch='2'">AABBAB</xsl:when>
    <xsl:when test="$switch='3'">AABBBA</xsl:when>
    <xsl:when test="$switch='4'">ABAABB</xsl:when>
    <xsl:when test="$switch='5'">ABBAAB</xsl:when>
    <xsl:when test="$switch='6'">ABBBAA</xsl:when>
    <xsl:when test="$switch='7'">ABABAB</xsl:when>
    <xsl:when test="$switch='8'">ABABBA</xsl:when>
    <xsl:when test="$switch='9'">ABBABA</xsl:when>
  </xsl:choose>
</xsl:template>

<!-- =========================================================== -->
<!-- Calculate EAN/UPC checksum. Note that "odds" and "evens"    -->
<!-- are counted from the end of the sequence.                   -->

<xsl:template name="EAN-check-digit">
  <xsl:param name="value"/>
  <xsl:param name="code-type"/>

  <!-- Expand UPC-E code to full 11-digit UPC-A -->
  <xsl:variable name="real-value">
    <xsl:choose>
      <xsl:when test="$code-type = 'UPC-E'">
        <xsl:variable name="last-digit" select="substring($value, 7, 1)"/>
        <xsl:choose>
          <xsl:when test="$last-digit='0' or $last-digit='1' or $last-digit='2'">
            <xsl:value-of select="concat(substring($value, 1, 3),
                                         $last-digit, '0000',
                                         substring($value, 4, 3))"/>
          </xsl:when>
          <xsl:when test="$last-digit='3'">
            <xsl:value-of select="concat(substring($value, 1, 4),
                                         '00000',
                                         substring($value, 5, 2))"/>
          </xsl:when>
          <xsl:when test="$last-digit='4'">
            <xsl:value-of select="concat(substring($value, 1, 5),
                                         '00000',
                                         substring($value, 6, 1))"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="concat(substring($value, 1, 6),
                                         '0000',
                                         substring($value, 7, 1))"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:when>
      <xsl:otherwise><xsl:value-of select="$value"/></xsl:otherwise>
    </xsl:choose>
  </xsl:variable>

  <xsl:variable name="sum-odds">
    <xsl:choose>
      <xsl:when test="$code-type = 'EAN-13'">
        <xsl:variable name="d2"  select="number(substring($real-value, 2, 1))"/>
        <xsl:variable name="d4"  select="number(substring($real-value, 4, 1))"/>
        <xsl:variable name="d6"  select="number(substring($real-value, 6, 1))"/>
        <xsl:variable name="d8"  select="number(substring($real-value, 8, 1))"/>
        <xsl:variable name="d10" select="number(substring($real-value, 10, 1))"/>
        <xsl:variable name="d12" select="number(substring($real-value, 12, 1))"/>
        <xsl:value-of select="$d2 + $d4 + $d6 + $d8 + $d10 + $d12" />
      </xsl:when>
      <xsl:when test="$code-type = 'UPC-A' or $code-type = 'UPC-E'">
        <xsl:variable name="d1"  select="number(substring($real-value, 1, 1))"/>
        <xsl:variable name="d3"  select="number(substring($real-value, 3, 1))"/>
        <xsl:variable name="d5"  select="number(substring($real-value, 5, 1))"/>
        <xsl:variable name="d7"  select="number(substring($real-value, 7, 1))"/>
        <xsl:variable name="d9"  select="number(substring($real-value, 9, 1))"/>
        <xsl:variable name="d11" select="number(substring($real-value, 11, 1))"/>
        <xsl:value-of select="$d1 + $d3 + $d5 + $d7 + $d9 + $d11" />
      </xsl:when>
      <xsl:when test="$code-type = 'EAN-8'">
        <xsl:variable name="d1"  select="number(substring($real-value, 1, 1))"/>
        <xsl:variable name="d3"  select="number(substring($real-value, 3, 1))"/>
        <xsl:variable name="d5"  select="number(substring($real-value, 5, 1))"/>
        <xsl:variable name="d7"  select="number(substring($real-value, 7, 1))"/>
        <xsl:value-of select="$d1 + $d3 + $d5 + $d7" />
      </xsl:when>
    </xsl:choose>
  </xsl:variable>      

  <xsl:variable name="sum-evens">
    <xsl:choose>
      <xsl:when test="$code-type = 'EAN-13'">
        <xsl:variable name="d1"  select="number(substring($real-value, 1, 1))"/>
        <xsl:variable name="d3"  select="number(substring($real-value, 3, 1))"/>
        <xsl:variable name="d5"  select="number(substring($real-value, 5, 1))"/>
        <xsl:variable name="d7"  select="number(substring($real-value, 7, 1))"/>
        <xsl:variable name="d9"  select="number(substring($real-value, 9, 1))"/>
        <xsl:variable name="d11" select="number(substring($real-value, 11, 1))"/>
        <xsl:value-of select="$d1 + $d3 + $d5 + $d7 + $d9 + $d11" />
      </xsl:when>
      <xsl:when test="$code-type = 'UPC-A' or $code-type = 'UPC-E'">
        <xsl:variable name="d2"  select="number(substring($real-value, 2, 1))"/>
        <xsl:variable name="d4"  select="number(substring($real-value, 4, 1))"/>
        <xsl:variable name="d6"  select="number(substring($real-value, 6, 1))"/>
        <xsl:variable name="d8"  select="number(substring($real-value, 8, 1))"/>
        <xsl:variable name="d10" select="number(substring($real-value, 10, 1))"/>
        <xsl:value-of select="$d2 + $d4 + $d6 + $d8 + $d10" />
      </xsl:when>
      <xsl:when test="$code-type = 'EAN-8'">
        <xsl:variable name="d2"  select="number(substring($real-value, 2, 1))"/>
        <xsl:variable name="d4"  select="number(substring($real-value, 4, 1))"/>
        <xsl:variable name="d6"  select="number(substring($real-value, 6, 1))"/>
        <xsl:value-of select="$d2 + $d4 + $d6" />
      </xsl:when>
    </xsl:choose>
  </xsl:variable>      

  <!-- Multiply $sum-odds by 3 and add to $sum-evens -->
  <xsl:variable name="total-sum" 
                select="($sum-odds * 3) + $sum-evens" />

  <!-- Get complement of $total-sum to the nearest multiple of 10 -->
  <xsl:value-of select="(10 - ($total-sum mod 10)) mod 10"/>
</xsl:template>


<!-- ========================================================= -->
<!-- Produce patterns for one digit in EAN, then recurse.      -->

<xsl:template name="emit-EAN-character-patterns">
  <xsl:param name="value"/>
  <xsl:param name="numeric-value"/>
  <xsl:param name="unit"/>
  <xsl:param name="pattern"/>

  <xsl:if test="string-length($pattern) &gt; 0">

    <xsl:call-template name="process-single-digit-EAN">
      <xsl:with-param name="digit" select="substring($value, 1,1)"/>
      <xsl:with-param name="pattern-type" select="substring($pattern, 1,1)"/>
      <xsl:with-param name="numeric-value" select="$numeric-value"/>
      <xsl:with-param name="unit" select="$unit"/>
    </xsl:call-template>

    <xsl:call-template name="emit-EAN-character-patterns">
      <xsl:with-param name="value" select="substring($value, 2)"/>
      <xsl:with-param name="pattern" select="substring($pattern, 2)"/>
      <xsl:with-param name="numeric-value" select="$numeric-value"/>
      <xsl:with-param name="unit" select="$unit"/>
    </xsl:call-template>
  </xsl:if>
</xsl:template>


<!-- ========================================================= -->
<!-- Print out a specific pattern for EAN: calls one of two    -->
<!-- subtemplates according to the value of $pattern-type      -->

<xsl:template name="process-single-digit-EAN">
  <xsl:param name="digit"/>
  <xsl:param name="pattern-type"/>
  <xsl:param name="numeric-value"/>
  <xsl:param name="unit"/>

  <xsl:choose>
    <xsl:when test="$pattern-type = 'B'">
      <xsl:call-template name="EAN-digit-B">
        <xsl:with-param name="digit" select="$digit"/>
        <xsl:with-param name="numeric-value" select="$numeric-value"/>
        <xsl:with-param name="unit" select="$unit"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:call-template name="EAN-digit-A">
        <xsl:with-param name="digit" select="$digit"/>
        <xsl:with-param name="numeric-value" select="$numeric-value"/>
        <xsl:with-param name="unit" select="$unit"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>       
</xsl:template>


<!-- ========================================================= -->
<!-- Print out a specific pattern for EAN/UPC.                 -->
<!-- Split to 2 separate templates for readability.            -->

<!-- Type A -->

<xsl:template name="EAN-digit-A">
  <xsl:param name="digit"/>
  <xsl:param name="numeric-value"/>
  <xsl:param name="unit"/>

  <xsl:choose>
    <xsl:when test="$digit='0'">
      <fo:table-column column-width="{$numeric-value * 3}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 2}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
    </xsl:when>
    <xsl:when test="$digit='1'">
      <fo:table-column column-width="{$numeric-value * 2}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 2}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 2}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
    </xsl:when>
    <xsl:when test="$digit='2'">
      <fo:table-column column-width="{$numeric-value * 2}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 2}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 2}{$unit}"/>
    </xsl:when>
    <xsl:when test="$digit='3'">
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 4}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
    </xsl:when>
    <xsl:when test="$digit='4'">
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 3}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 2}{$unit}"/>
    </xsl:when>
    <xsl:when test="$digit='5'">
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 2}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 3}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
    </xsl:when>
    <xsl:when test="$digit='6'">
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 4}{$unit}"/>
    </xsl:when>
    <xsl:when test="$digit='7'">
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 3}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 2}{$unit}"/>
    </xsl:when>
    <xsl:when test="$digit='8'">
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 2}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 3}{$unit}"/>
    </xsl:when>
    <xsl:when test="$digit='9'">
      <fo:table-column column-width="{$numeric-value * 3}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 2}{$unit}"/>
    </xsl:when>
    <xsl:otherwise>
      <fo:table-column column-width="{$numeric-value * 3}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 2}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>


<!-- Type B is the reverse of type A; used in EAN 13 and UPC E -->

<xsl:template name="EAN-digit-B">
  <xsl:param name="digit"/>
  <xsl:param name="numeric-value"/>
  <xsl:param name="unit"/>

  <xsl:choose>
    <xsl:when test="$digit='0'">
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 2}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 3}{$unit}"/>
    </xsl:when>
    <xsl:when test="$digit='1'">
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 2}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 2}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 2}{$unit}"/>
    </xsl:when>
    <xsl:when test="$digit='2'">
      <fo:table-column column-width="{$numeric-value * 2}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 2}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 2}{$unit}"/>
    </xsl:when>
    <xsl:when test="$digit='3'">
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 4}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
    </xsl:when>
    <xsl:when test="$digit='4'">
      <fo:table-column column-width="{$numeric-value * 2}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 3}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
    </xsl:when>
    <xsl:when test="$digit='5'">
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 3}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 2}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
    </xsl:when>
    <xsl:when test="$digit='6'">
      <fo:table-column column-width="{$numeric-value * 4}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
    </xsl:when>
    <xsl:when test="$digit='7'">
      <fo:table-column column-width="{$numeric-value * 2}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 3}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
    </xsl:when>
    <xsl:when test="$digit='8'">
      <fo:table-column column-width="{$numeric-value * 3}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 2}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
    </xsl:when>
    <xsl:when test="$digit='9'">
      <fo:table-column column-width="{$numeric-value * 2}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 3}{$unit}"/>
    </xsl:when>
    <xsl:otherwise>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 2}{$unit}"/>
      <fo:table-column column-width="{$numeric-value * 3}{$unit}"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

</xsl:stylesheet>



