<?php
/**
 * This file is part of FPDI
 *
 * @package   FPDI
 * @copyright Copyright (c) 2017 Setasign - Jan Slabon (https://www.setasign.com)
 * @license   http://opensource.org/licenses/mit-license The MIT License
 * @version   1.6.2
 */

if (!class_exists('FPDF_TPL')) {
    require_once('fpdf_tpl.php');
}



	
	//function hex2dec
//returns an associative array (keys: R,G,B) from
//a hex html code (e.g. #3FE5AA)
function hex2dec($couleur = "#000000"){
    $R = substr($couleur, 1, 2);
    $rouge = hexdec($R);
    $V = substr($couleur, 3, 2);
    $vert = hexdec($V);
    $B = substr($couleur, 5, 2);
    $bleu = hexdec($B);
    $tbl_couleur = array();
    $tbl_couleur['R']=$rouge;
    $tbl_couleur['V']=$vert;
    $tbl_couleur['B']=$bleu;
    return $tbl_couleur;
}

//conversion pixel -> millimeter at 72 dpi
function px2mm($px){
    return $px*25.4/72;
}

function txtentities($html){
    $trans = get_html_translation_table(HTML_ENTITIES);
    $trans = array_flip($trans);
    return strtr($html, $trans);
}

/**
 * Class FPDI
 */
class FPDI extends FPDF_TPL
{
    /**
     * FPDI version
     *
     * @string
     */
    const VERSION = '1.6.2';

    /**
     * Actual filename
     *
     * @var string
     */
    public $currentFilename;

    /**
     * Parser-Objects
     *
     * @var fpdi_pdf_parser[]
     */
    public $parsers = array();
    
    /**
     * Current parser
     *
     * @var fpdi_pdf_parser
     */
    public $currentParser;

    /**
     * The name of the last imported page box
     *
     * @var string
     */
    public $lastUsedPageBox;

    /**
     * Object stack
     *
     * @var array
     */
    protected $_objStack;
    
    /**
     * Done object stack
     *
     * @var array
     */
    protected $_doneObjStack;

    /**
     * Current Object Id.
     *
     * @var integer
     */
    protected $_currentObjId;
    
    /**
     * Cache for imported pages/template ids
     *
     * @var array
     */
    protected $_importedPages = array();
    
    /**
     * Set a source-file.
     *
     * Depending on the PDF version of the used document the PDF version of the resulting document will
     * be adjusted to the higher version.
     *
     * @param string $filename A valid path to the PDF document from which pages should be imported from
     * @return int The number of pages in the document
     * @throws Exception
     */
    public function setSourceFile($filename)
    {
        $_filename = realpath($filename);
        if (false !== $_filename)
            $filename = $_filename;

        $currentFilename = $this->currentFilename;
        $currentParser = $this->currentParser;

        try {
            $this->currentFilename = $filename;

            if (!isset($this->parsers[$filename])) {
                $this->parsers[$filename] = $this->_getPdfParser($filename);
                $this->setPdfVersion(
                    max($this->getPdfVersion(), $this->parsers[$filename]->getPdfVersion())
                );
            }

            $this->currentParser = $this->parsers[$filename];

        } catch (Exception $e) {
            unset($this->parsers[$filename]);
            $this->currentFilename = $currentFilename;
            $this->currentParser = $currentParser;
            throw $e;
        }
        
        return $this->parsers[$filename]->getPageCount();
    }
    
    /**
     * Returns a PDF parser object
     *
     * @param string $filename
     * @return fpdi_pdf_parser
     */
    protected function _getPdfParser($filename)
    {
        if (!class_exists('fpdi_pdf_parser')) {
            require_once('fpdi_pdf_parser.php');
        }
        return new fpdi_pdf_parser($filename);
    }
    
    /**
     * Get the current PDF version.
     *
     * @return string
     */
    public function getPdfVersion()
    {
        return $this->PDFVersion;
    }
    
    /**
     * Set the PDF version.
     *
     * @param string $version
     */
    public function setPdfVersion($version = '1.3')
    {
        $this->PDFVersion = sprintf('%.1F', $version);
    }
    
    /**
     * Import a page.
     *
     * The second parameter defines the bounding box that should be used to transform the page into a
     * form XObject.
     *
     * Following values are available: MediaBox, CropBox, BleedBox, TrimBox, ArtBox.
     * If a box is not especially defined its default box will be used:
     *
     * <ul>
     *   <li>CropBox: Default -> MediaBox</li>
     *   <li>BleedBox: Default -> CropBox</li>
     *   <li>TrimBox: Default -> CropBox</li>
     *   <li>ArtBox: Default -> CropBox</li>
     * </ul>
     *
     * It is possible to get the used page box by the {@link getLastUsedPageBox()} method.
     *
     * @param int $pageNo The page number
     * @param string $boxName The boundary box to use when transforming the page into a form XObject
     * @param boolean $groupXObject Define the form XObject as a group XObject to support transparency (if used)
     * @return int An id of the imported page/template to use with e.g. fpdf_tpl::useTemplate()
     * @throws LogicException|InvalidArgumentException
     * @see getLastUsedPageBox()
     */
    public function importPage($pageNo, $boxName = 'CropBox', $groupXObject = true)
    {
        if ($this->_inTpl) {
            throw new LogicException('Please import the desired pages before creating a new template.');
        }
        
        $fn = $this->currentFilename;
        $boxName = '/' . ltrim($boxName, '/');

        // check if page already imported
        $pageKey = $fn . '-' . ((int)$pageNo) . $boxName;
        if (isset($this->_importedPages[$pageKey])) {
            return $this->_importedPages[$pageKey];
        }
        
        $parser = $this->parsers[$fn];
        $parser->setPageNo($pageNo);

        if (!in_array($boxName, $parser->availableBoxes)) {
            throw new InvalidArgumentException(sprintf('Unknown box: %s', $boxName));
        }
            
        $pageBoxes = $parser->getPageBoxes($pageNo, $this->k);
        
        /**
         * MediaBox
         * CropBox: Default -> MediaBox
         * BleedBox: Default -> CropBox
         * TrimBox: Default -> CropBox
         * ArtBox: Default -> CropBox
         */
        if (!isset($pageBoxes[$boxName]) && ($boxName == '/BleedBox' || $boxName == '/TrimBox' || $boxName == '/ArtBox'))
            $boxName = '/CropBox';
        if (!isset($pageBoxes[$boxName]) && $boxName == '/CropBox')
            $boxName = '/MediaBox';
        
        if (!isset($pageBoxes[$boxName]))
            return false;
            
        $this->lastUsedPageBox = $boxName;
        
        $box = $pageBoxes[$boxName];
        
        $this->tpl++;
        $this->_tpls[$this->tpl] = array();
        $tpl =& $this->_tpls[$this->tpl];
        $tpl['parser'] = $parser;
        $tpl['resources'] = $parser->getPageResources();
        $tpl['buffer'] = $parser->getContent();
        $tpl['box'] = $box;
        $tpl['groupXObject'] = $groupXObject;
        if ($groupXObject) {
            $this->setPdfVersion(max($this->getPdfVersion(), 1.4));
        }

        // To build an array that can be used by PDF_TPL::useTemplate()
        $this->_tpls[$this->tpl] = array_merge($this->_tpls[$this->tpl], $box);
        
        // An imported page will start at 0,0 all the time. Translation will be set in _putformxobjects()
        $tpl['x'] = 0;
        $tpl['y'] = 0;
        
        // handle rotated pages
        $rotation = $parser->getPageRotation($pageNo);
        $tpl['_rotationAngle'] = 0;
        if (isset($rotation[1]) && ($angle = $rotation[1] % 360) != 0) {
            $steps = $angle / 90;
                
            $_w = $tpl['w'];
            $_h = $tpl['h'];
            $tpl['w'] = $steps % 2 == 0 ? $_w : $_h;
            $tpl['h'] = $steps % 2 == 0 ? $_h : $_w;
            
            if ($angle < 0)
                $angle += 360;
            
            $tpl['_rotationAngle'] = $angle * -1;
        }
        
        $this->_importedPages[$pageKey] = $this->tpl;
        
        return $this->tpl;
    }
    
    /**
     * Returns the last used page boundary box.
     *
     * @return string The used boundary box: MediaBox, CropBox, BleedBox, TrimBox or ArtBox
     */
    public function getLastUsedPageBox()
    {
        return $this->lastUsedPageBox;
    }

    /**
     * Use a template or imported page in current page or other template.
     *
     * You can use a template in a page or in another template.
     * You can give the used template a new size. All parameters are optional.
     * The width or height is calculated automatically if one is given. If no
     * parameter is given the origin size as defined in beginTemplate() or of
     * the imported page is used.
     *
     * The calculated or used width and height are returned as an array.
     *
     * @param int $tplIdx A valid template-id
     * @param int $x The x-position
     * @param int $y The y-position
     * @param int $w The new width of the template
     * @param int $h The new height of the template
     * @param boolean $adjustPageSize If set to true the current page will be resized to fit the dimensions
     *                                of the template
     *
     * @return array The height and width of the template (array('w' => ..., 'h' => ...))
     * @throws LogicException|InvalidArgumentException
     */
    public function useTemplate($tplIdx, $x = null, $y = null, $w = 0, $h = 0, $adjustPageSize = false)
    {
        if ($adjustPageSize == true && is_null($x) && is_null($y)) {
            $size = $this->getTemplateSize($tplIdx, $w, $h);
            $orientation = $size['w'] > $size['h'] ? 'L' : 'P';
            $size = array($size['w'], $size['h']);
            
            if (is_subclass_of($this, 'TCPDF')) {
                $this->setPageFormat($size, $orientation);
            } else {
                $size = $this->_getpagesize($size);
                
                if($orientation != $this->CurOrientation ||
                    $size[0] != $this->CurPageSize[0] ||
                    $size[1] != $this->CurPageSize[1]
                ) {
                    // New size or orientation
                    if ($orientation=='P') {
                        $this->w = $size[0];
                        $this->h = $size[1];
                    } else {
                        $this->w = $size[1];
                        $this->h = $size[0];
                    }
                    $this->wPt = $this->w * $this->k;
                    $this->hPt = $this->h * $this->k;
                    $this->PageBreakTrigger = $this->h - $this->bMargin;
                    $this->CurOrientation = $orientation;
                    $this->CurPageSize = $size;
                    if (FPDF_VERSION >= 1.8) {
                        $this->PageInfo[$this->page]['size'] = array($this->wPt, $this->hPt);
                    } else {
                        $this->PageSizes[$this->page] = array($this->wPt, $this->hPt);
                    }
                }
            } 
        }
        
        $this->_out('q 0 J 1 w 0 j 0 G 0 g'); // reset standard values
        $size = parent::useTemplate($tplIdx, $x, $y, $w, $h);
        $this->_out('Q');
        
        return $size;
    }
    
    /**
     * Copy all imported objects to the resulting document.
     */
    protected function _putimportedobjects()
    {
        foreach($this->parsers AS $filename => $p) {
            $this->currentParser = $p;
            if (!isset($this->_objStack[$filename]) || !is_array($this->_objStack[$filename])) {
                continue;
            }
            while(($n = key($this->_objStack[$filename])) !== null) {
                try {
                    $nObj = $this->currentParser->resolveObject($this->_objStack[$filename][$n][1]);
                } catch (Exception $e) {
                    $nObj = array(pdf_parser::TYPE_OBJECT, pdf_parser::TYPE_NULL);
                }

                $this->_newobj($this->_objStack[$filename][$n][0]);

                if ($nObj[0] == pdf_parser::TYPE_STREAM) {
                    $this->_writeValue($nObj);
                } else {
                    $this->_writeValue($nObj[1]);
                }

                $this->_out("\nendobj");
                $this->_objStack[$filename][$n] = null; // free memory
                unset($this->_objStack[$filename][$n]);
                reset($this->_objStack[$filename]);
            }
        }
    }

    /**
     * Writes the form XObjects to the PDF document.
     */
    protected function _putformxobjects()
    {
        $filter = ($this->compress) ? '/Filter /FlateDecode ' : '';
        reset($this->_tpls);
        foreach($this->_tpls AS $tplIdx => $tpl) {
            $this->_newobj();
            $currentN = $this->n; // TCPDF/Protection: rem current "n"
            
            $this->_tpls[$tplIdx]['n'] = $this->n;
            $this->_out('<<' . $filter . '/Type /XObject');
            $this->_out('/Subtype /Form');
            $this->_out('/FormType 1');
            
            $this->_out(sprintf('/BBox [%.2F %.2F %.2F %.2F]', 
                (isset($tpl['box']['llx']) ? $tpl['box']['llx'] : $tpl['x']) * $this->k,
                (isset($tpl['box']['lly']) ? $tpl['box']['lly'] : -$tpl['y']) * $this->k,
                (isset($tpl['box']['urx']) ? $tpl['box']['urx'] : $tpl['w'] + $tpl['x']) * $this->k,
                (isset($tpl['box']['ury']) ? $tpl['box']['ury'] : $tpl['h'] - $tpl['y']) * $this->k
            ));
            
            $c = 1;
            $s = 0;
            $tx = 0;
            $ty = 0;
            
            if (isset($tpl['box'])) {
                $tx = -$tpl['box']['llx'];
                $ty = -$tpl['box']['lly']; 
                
                if ($tpl['_rotationAngle'] <> 0) {
                    $angle = $tpl['_rotationAngle'] * M_PI/180;
                    $c = cos($angle);
                    $s = sin($angle);
                    
                    switch($tpl['_rotationAngle']) {
                        case -90:
                            $tx = -$tpl['box']['lly'];
                            $ty = $tpl['box']['urx'];
                            break;
                        case -180:
                            $tx = $tpl['box']['urx'];
                            $ty = $tpl['box']['ury'];
                            break;
                        case -270:
                            $tx = $tpl['box']['ury'];
                            $ty = -$tpl['box']['llx'];
                            break;
                    }
                }
            } else if ($tpl['x'] != 0 || $tpl['y'] != 0) {
                $tx = -$tpl['x'] * 2;
                $ty = $tpl['y'] * 2;
            }
            
            $tx *= $this->k;
            $ty *= $this->k;
            
            if ($c != 1 || $s != 0 || $tx != 0 || $ty != 0) {
                $this->_out(sprintf('/Matrix [%.5F %.5F %.5F %.5F %.5F %.5F]',
                    $c, $s, -$s, $c, $tx, $ty
                ));
            }
            
            $this->_out('/Resources ');

            if (isset($tpl['resources'])) {
                $this->currentParser = $tpl['parser'];
                $this->_writeValue($tpl['resources']); // "n" will be changed
            } else {

                $this->_out('<</ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
                if (isset($this->_res['tpl'][$tplIdx])) {
                    $res = $this->_res['tpl'][$tplIdx];

                    if (isset($res['fonts']) && count($res['fonts'])) {
                        $this->_out('/Font <<');
                        foreach ($res['fonts'] as $font)
                            $this->_out('/F' . $font['i'] . ' ' . $font['n'] . ' 0 R');
                        $this->_out('>>');
                    }
                    if (isset($res['images']) && count($res['images']) ||
                       isset($res['tpls']) && count($res['tpls']))
                    {
                        $this->_out('/XObject <<');
                        if (isset($res['images'])) {
                            foreach ($res['images'] as $image)
                                $this->_out('/I' . $image['i'] . ' ' . $image['n'] . ' 0 R');
                        }
                        if (isset($res['tpls'])) {
                            foreach ($res['tpls'] as $i => $_tpl)
                                $this->_out($this->tplPrefix . $i . ' ' . $_tpl['n'] . ' 0 R');
                        }
                        $this->_out('>>');
                    }
                    $this->_out('>>');
                }
            }

            if (isset($tpl['groupXObject']) && $tpl['groupXObject']) {
                $this->_out('/Group <</Type/Group/S/Transparency>>');
            }

            $newN = $this->n; // TCPDF: rem new "n"
            $this->n = $currentN; // TCPDF: reset to current "n"

            $buffer = ($this->compress) ? gzcompress($tpl['buffer']) : $tpl['buffer'];

            if (is_subclass_of($this, 'TCPDF')) {
                $buffer = $this->_getrawstream($buffer);
                $this->_out('/Length ' . strlen($buffer) . ' >>');
                $this->_out("stream\n" . $buffer . "\nendstream");
            } else {
                $this->_out('/Length ' . strlen($buffer) . ' >>');
                $this->_putstream($buffer);
            }
            $this->_out('endobj');
            $this->n = $newN; // TCPDF: reset to new "n"
        }
        
        $this->_putimportedobjects();
    }

    /**
     * Creates and optionally write the object definition to the document.
     *
     * Rewritten to handle existing own defined objects
     *
     * @param bool $objId
     * @param bool $onlyNewObj
     * @return bool|int
     */
    public function _newobj($objId = false, $onlyNewObj = false)
    {
        if (!$objId) {
            $objId = ++$this->n;
        }

        // Begin a new object
        if (!$onlyNewObj) {
            $this->offsets[$objId] = is_subclass_of($this, 'TCPDF') ? $this->bufferlen : strlen($this->buffer);
            $this->_out($objId . ' 0 obj');
            $this->_currentObjId = $objId; // for later use with encryption
        }
        
        return $objId;
    }

    /**
     * Writes a PDF value to the resulting document.
     *
     * Needed to rebuild the source document
     *
     * @param mixed $value A PDF-Value. Structure of values see cases in this method
     */
    protected function _writeValue(&$value)
    {
        if (is_subclass_of($this, 'TCPDF')) {
            parent::_prepareValue($value);
        }
        
        switch ($value[0]) {

            case pdf_parser::TYPE_TOKEN:
                $this->_straightOut($value[1] . ' ');
                break;
            case pdf_parser::TYPE_NUMERIC:
            case pdf_parser::TYPE_REAL:
                if (is_float($value[1]) && $value[1] != 0) {
                    $this->_straightOut(rtrim(rtrim(sprintf('%F', $value[1]), '0'), '.') . ' ');
                } else {
                    $this->_straightOut($value[1] . ' ');
                }
                break;
                
            case pdf_parser::TYPE_ARRAY:

                // An array. Output the proper
                // structure and move on.

                $this->_straightOut('[');
                for ($i = 0; $i < count($value[1]); $i++) {
                    $this->_writeValue($value[1][$i]);
                }

                $this->_out(']');
                break;

            case pdf_parser::TYPE_DICTIONARY:

                // A dictionary.
                $this->_straightOut('<<');

                reset ($value[1]);

                while (list($k, $v) = each($value[1])) {
                    $this->_straightOut($k . ' ');
                    $this->_writeValue($v);
                }

                $this->_straightOut('>>');
                break;

            case pdf_parser::TYPE_OBJREF:

                // An indirect object reference
                // Fill the object stack if needed
                $cpfn =& $this->currentParser->filename;
                if (!isset($this->_doneObjStack[$cpfn][$value[1]])) {
                    $this->_newobj(false, true);
                    $this->_objStack[$cpfn][$value[1]] = array($this->n, $value);
                    $this->_doneObjStack[$cpfn][$value[1]] = array($this->n, $value);
                }
                $objId = $this->_doneObjStack[$cpfn][$value[1]][0];

                $this->_out($objId . ' 0 R');
                break;

            case pdf_parser::TYPE_STRING:

                // A string.
                $this->_straightOut('(' . $value[1] . ')');

                break;

            case pdf_parser::TYPE_STREAM:

                // A stream. First, output the
                // stream dictionary, then the
                // stream data itself.
                $this->_writeValue($value[1]);
                $this->_out('stream');
                $this->_out($value[2][1]);
                $this->_straightOut("endstream");
                break;
                
            case pdf_parser::TYPE_HEX:
                $this->_straightOut('<' . $value[1] . '>');
                break;

            case pdf_parser::TYPE_BOOLEAN:
                $this->_straightOut($value[1] ? 'true ' : 'false ');
                break;
            
            case pdf_parser::TYPE_NULL:
                // The null object.
                $this->_straightOut('null ');
                break;
        }
    }
    
    
    /**
     * Modified _out() method so not each call will add a newline to the output.
     */
    protected function _straightOut($s)
    {
        if (!is_subclass_of($this, 'TCPDF')) {
            if ($this->state == 2) {
                $this->pages[$this->page] .= $s;
            } else {
                $this->buffer .= $s;
            }

        } else {
            if ($this->state == 2) {
                if ($this->inxobj) {
                    // we are inside an XObject template
                    $this->xobjects[$this->xobjid]['outdata'] .= $s;
                } else if ((!$this->InFooter) AND isset($this->footerlen[$this->page]) AND ($this->footerlen[$this->page] > 0)) {
                    // puts data before page footer
                    $pagebuff = $this->getPageBuffer($this->page);
                    $page = substr($pagebuff, 0, -$this->footerlen[$this->page]);
                    $footer = substr($pagebuff, -$this->footerlen[$this->page]);
                    $this->setPageBuffer($this->page, $page . $s . $footer);
                    // update footer position
                    $this->footerpos[$this->page] += strlen($s);
                } else {
                    // set page data
                    $this->setPageBuffer($this->page, $s, true);
                }
            } else if ($this->state > 0) {
                // set general data
                $this->setBuffer($s);
            }
        }
    }

    /**
     * Ends the document
     *
     * Overwritten to close opened parsers
     */
    public function _enddoc()
    {
        parent::_enddoc();
        $this->_closeParsers();
    }
    
    /**
     * Close all files opened by parsers.
     *
     * @return boolean
     */
    protected function _closeParsers()
    {
        if ($this->state > 2) {
            $this->cleanUp();
            return true;
        }

        return false;
    }
    
    /**
     * Removes cycled references and closes the file handles of the parser objects.
     */
    public function cleanUp()
    {
        while (($parser = array_pop($this->parsers)) !== null) {
            /**
             * @var fpdi_pdf_parser $parser
             */
            $parser->closeFile();
        }
    }
	
	
	
	var $legends;
    var $wLegend;
    var $sum;
    var $NbVal;

    function PieChart($w, $h, $data, $format, $colors=null)
    {
        $this->SetFont('Courier', '', 10);
        $this->SetLegends($data,$format);

        $XPage = $this->GetX();
        $YPage = $this->GetY();
        $margin = 2;
        $hLegend = 5;
        $radius = min($w - $margin * 4 - $hLegend - $this->wLegend, $h - $margin * 2);
        $radius = floor($radius / 2);
        $XDiag = $XPage + $margin + $radius;
        $YDiag = $YPage + $margin + $radius;
        if($colors == null) {
            for($i = 0; $i < $this->NbVal; $i++) {
                $gray = $i * intval(255 / $this->NbVal);
                $colors[$i] = array($gray,$gray,$gray);
            }
        }

        //Sectors
        $this->SetLineWidth(0.2);
        $angleStart = 0;
        $angleEnd = 0;
        $i = 0;
        foreach($data as $val) {
            $angle = ($val * 360) / doubleval($this->sum);
            if ($angle != 0) {
                $angleEnd = $angleStart + $angle;
                $this->SetFillColor($colors[$i][0],$colors[$i][1],$colors[$i][2]);
                $this->Sector($XDiag, $YDiag, $radius, $angleStart, $angleEnd);
                $angleStart += $angle;
            }
            $i++;
        }

        //Legends
        $this->SetFont('Courier', '', 10);
        $x1 = $XPage + 2 * $radius + 4 * $margin;
        $x2 = $x1 + $hLegend + $margin;
        $y1 = $YDiag - $radius + (2 * $radius - $this->NbVal*($hLegend + $margin)) / 2;
        for($i=0; $i<$this->NbVal; $i++) {
            $this->SetFillColor($colors[$i][0],$colors[$i][1],$colors[$i][2]);
            $this->Rect($x1, $y1, $hLegend, $hLegend, 'DF');
            $this->SetXY($x2,$y1);
            $this->Cell(0,$hLegend,$this->legends[$i]);
            $y1+=$hLegend + $margin;
        }
    }

    function BarDiagram($w, $h, $data, $format, $color=null, $maxVal=0, $nbDiv=4)
    {
        $this->SetFont('Courier', '', 10);
      $this->SetLegends($data,$format);

        $XPage = $this->GetX();
        $YPage = $this->GetY();
        $margin = 2;
        $YDiag = $YPage + $margin;
        $hDiag = floor($h - $margin * 2);
        $XDiag = $XPage + $margin * 2 + $this->wLegend;
        $lDiag = floor($w - $margin * 3 - $this->wLegend);
        if($color == null)
            $color=array(155,155,155);
        if ($maxVal == 0) {
            $maxVal = max($data);
        }
        $valIndRepere = ceil($maxVal / $nbDiv);
        $maxVal = $valIndRepere * $nbDiv;
        $lRepere = floor($lDiag / $nbDiv);
        $lDiag = $lRepere * $nbDiv;
        $unit = $lDiag / $maxVal;
        $hBar = floor($hDiag / ($this->NbVal + 1));
        $hDiag = $hBar * ($this->NbVal + 2);
        $eBaton = floor($hBar * 80 / 100);

        $this->SetLineWidth(0.5);
        $this->Rect($XDiag, $YDiag, $lDiag, $hDiag);

        $this->SetFont('Courier', '', 10);
        $this->SetFillColor($color[0],$color[1],$color[2]);
        $i=0;
        foreach($data as $val) {
            //Bar
            $xval = $XDiag;
            $lval = (int)($val * $unit);
            $yval = $YDiag + ($i + 1) * $hBar - $eBaton / 2;
            $hval = $eBaton;
            $this->Rect($xval, $yval, $lval, $hval, 'DF');
            //Legend
            $this->SetXY(0, $yval);
            $this->Cell($xval - $margin, $hval, $this->legends[$i],0,0,'R');
            $i++;
        }

        //Scales
        for ($i = 0; $i <= $nbDiv; $i++) {
            $xpos = $XDiag + $lRepere * $i;
           // $this->Line($xpos, $YDiag, $xpos, $YDiag + $hDiag); // Ths Place Vertcal Lnes On The Graph
            $val = $i * $valIndRepere;
            $xpos = $XDiag + $lRepere * $i - $this->GetStringWidth($val) / 2;
            $ypos = $YDiag + $hDiag - $margin;
            $this->Text($xpos, $ypos, $val);
        }
    }

    function SetLegends($data, $format)
    {
        $this->legends=array();
        $this->wLegend=0;
        $this->sum=array_sum($data);
        $this->NbVal=count($data);
        foreach($data as $l=>$val)
        {
            $p=sprintf('%.2f',$val/$this->sum*100).'%';
            $legend=str_replace(array('%l','%v','%p'),array($l,$val,$p),$format);
            $this->legends[]=$legend;
            $this->wLegend=max($this->GetStringWidth($legend),$this->wLegend);
        }
    }
	

////////////////////////////////////


//variables of html parser
protected $B;
protected $I;
protected $U;
protected $HREF;
protected $fontList;
protected $issetfont;
protected $issetcolor;
 
function WriteHTML($html)
{
    //HTML parser
    $html=strip_tags($html,"<b><u><i><a><img><p><br><strong><em><font><tr><blockquote>"); //supprime tous les tags sauf ceux reconnus
    $html=str_replace("\n",' ',$html); //remplace retour à la ligne par un espace
    $a=preg_split('/<(.*)>/U',$html,-1,PREG_SPLIT_DELIM_CAPTURE); //éclate la chaîne avec les balises
    foreach($a as $i=>$e)
    {
        if($i%2==0)
        {
            //Text
            if($this->HREF)
                $this->PutLink($this->HREF,$e);
            else
                $this->Write(5,stripslashes(txtentities($e)));
        }
        else
        {
            //Tag
            if($e[0]=='/')
                $this->CloseTag(strtoupper(substr($e,1)));
            else
            {
                //Extract attributes
                $a2=explode(' ',$e);
                $tag=strtoupper(array_shift($a2));
                $attr=array();
                foreach($a2 as $v)
                {
                    if(preg_match('/([^=]*)=["\']?([^"\']*)/',$v,$a3))
                        $attr[strtoupper($a3[1])]=$a3[2];
                }
                $this->OpenTag($tag,$attr);
            }
        }
    }
}

function OpenTag($tag, $attr)
{
    //Opening tag
    switch($tag){
        case 'STRONG':
            $this->SetStyle('B',true);
            break;
        case 'EM':
            $this->SetStyle('I',true);
            break;
        case 'B':
        case 'I':
        case 'U':
            $this->SetStyle($tag,true);
            break;
        case 'A':
            $this->HREF=$attr['HREF'];
            break;
        case 'IMG':
            if(isset($attr['SRC']) && (isset($attr['WIDTH']) || isset($attr['HEIGHT']))) {
                if(!isset($attr['WIDTH']))
                    $attr['WIDTH'] = 0;
                if(!isset($attr['HEIGHT']))
                    $attr['HEIGHT'] = 0;
                $this->Image($attr['SRC'], $this->GetX(), $this->GetY(), px2mm($attr['WIDTH']), px2mm($attr['HEIGHT']));
            }
            break;
        case 'TR':
        case 'BLOCKQUOTE':
        case 'BR':
            $this->Ln(5);
            break;
        case 'P':
            $this->Ln(10);
            break;
        case 'FONT':
            if (isset($attr['COLOR']) && $attr['COLOR']!='') {
                $coul=hex2dec($attr['COLOR']);
                $this->SetTextColor($coul['R'],$coul['V'],$coul['B']);
                $this->issetcolor=true;
            }
            if (isset($attr['FACE']) && in_array(strtolower($attr['FACE']), $this->fontlist)) {
                $this->SetFont(strtolower($attr['FACE']));
                $this->issetfont=true;
            }
            break;
    }
}

function CloseTag($tag)
{
    //Closing tag
    if($tag=='STRONG')
        $tag='B';
    if($tag=='EM')
        $tag='I';
    if($tag=='B' || $tag=='I' || $tag=='U')
        $this->SetStyle($tag,false);
    if($tag=='A')
        $this->HREF='';
    if($tag=='FONT'){
        if ($this->issetcolor==true) {
            $this->SetTextColor(0);
        }
        if ($this->issetfont) {
            $this->SetFont('arial');
            $this->issetfont=false;
        }
    }
}

function SetStyle($tag, $enable)
{
    //Modify style and select corresponding font
    $this->$tag+=($enable ? 1 : -1);
    $style='';
    foreach(array('B','I','U') as $s)
    {
        if($this->$s>0)
            $style.=$s;
    }
    $this->SetFont('',$style);
}

function PutLink($URL, $txt)
{
    //Put a hyperlink
    $this->SetTextColor(0,0,255);
    $this->SetStyle('U',true);
    $this->Write(5,$txt,$URL);
    $this->SetStyle('U',false);
    $this->SetTextColor(0);
}
	
	
	
}