<?php
/**
 * Piwik - free/libre analytics platform
 *
 * @link https://matomo.org
 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
 *
 */

namespace Piwik\Visualization;

use Piwik\Common;
use Piwik\Piwik;
use Piwik\View\ViewInterface;

/**
 * Renders a sparkline image given a PHP data array.
 * Using the Sparkline PHP Graphing Library sparkline.org
 */
class Sparkline implements ViewInterface
{
    const DEFAULT_WIDTH = 200;
    const DEFAULT_HEIGHT = 50;
    const MAX_WIDTH = 1000;
    const MAX_HEIGHT = 1000;


    /**
     * Width of the sparkline
     * @var int
     */
    protected $_width = self::DEFAULT_WIDTH;
    /**
     * Height of sparkline
     * @var int
     */
    protected $_height = self::DEFAULT_HEIGHT;
    private $values = array();
    /**
     * @var \Davaxi\Sparkline
     */
    private $sparkline;

    /**
     * Array with format: array( x, y, z, ... )
     * @param array $data
     */
    public function setValues($data) {
        $this->values = $data;
    }

    public function main() {

        $sparkline = new \Davaxi\Sparkline();

        $seconds = Piwik::translate('Intl_NSecondsShort');
        $percent = Piwik::translate('Intl_NumberSymbolPercent');
        $thousandSeparator = Piwik::translate('Intl_NumberSymbolGroup');
        $decimalSeparator = Piwik::translate('Intl_NumberSymbolGroup');
        $toRemove = array('%', $percent, str_replace('%s', '', $seconds));
        $values = [];
        foreach ($this->values as $value) {
            // 50% and 50s should be plotted as 50
            $value = str_replace($toRemove, '', $value);
            // replace localized decimal separator
            $value = str_replace($thousandSeparator, '', $value);
            $value = str_replace($decimalSeparator, '.', $value);
            if ($value == '') {
                $value = 0;
            }
            $values[] = $value;
        }

        $hasFloat = false;
        foreach ($values as $value) {
            if (is_numeric($value)
                && is_float($value + 0) // coerce to int/float type before checking
            ) {
                $hasFloat = true;
                break;
            }
        }

        // the sparkline lib used converts everything to integers (see the FormatTrait.php file) which means float
        // numbers that are close to 1.0 or 0.0 will get floored. this can happen in the average page generation time
        // report, and cause some values which are, eg, around ~.9 to appear as 0 in the sparkline. to workaround this, we
        // scale the values.
        if ($hasFloat) {
            $values = array_map(function ($x) {
                return $x * 1000.0;
            }, $values);
        }

        $sparkline->setData($values);
        $sparkline->setWidth($this->getWidth());
        $sparkline->setHeight($this->getHeight());
        $this->setSparklineColors($sparkline);
        $sparkline->setLineThickness(1);
        $sparkline->setPadding('5');

        $this->sparkline = $sparkline;
    }

    /**
     * Returns the width of the sparkline
     * @return int
     */
    public function getWidth() {
        return $this->_width;
    }

    /**
     * Sets the width of the sparkline
     * @param int $width
     */
    public function setWidth($width) {
        if (!is_numeric($width) || $width <= 0) {
            return;
        }
        if ($width > self::MAX_WIDTH) {
            $this->_width = self::MAX_WIDTH;
        } else {
            $this->_width = (int)$width;
        }
    }

    /**
     * Returns the height of the sparkline
     * @return int
     */
    public function getHeight() {
        return $this->_height;
    }

    /**
     * Sets the height of the sparkline
     * @param int $height
     */
    public function setHeight($height) {
        if (!is_numeric($height) || $height <= 0) {
            return;
        }
        if ($height > self::MAX_HEIGHT) {
            $this->_height = self::MAX_HEIGHT;
        } else {
            $this->_height = (int)$height;
        }
    }

    /**
     * Sets the sparkline colors
     *
     * @param \Davaxi\Sparkline $sparkline
     */
    private function setSparklineColors($sparkline) {
        $colors = Common::getRequestVar('colors', false, 'json');

        if (empty($colors)) { // quick fix so row evolution sparklines will have color in widgetize's iframes
            $colors = array(
                'backgroundColor' => '#ffffff',
                'lineColor' => '#162C4A',
                'minPointColor' => '#ff7f7f',
                'maxPointColor' => '#75BF7C',
                'lastPointColor' => '#55AAFF',
                'fillColor' => '#ffffff'
            );
        }

        if (strtolower($colors['backgroundColor']) !== '#ffffff') {
            $sparkline->setBackgroundColorHex($colors['backgroundColor']);
        } else {
            $sparkline->deactivateBackgroundColor();
        }
        $sparkline->setLineColorHex($colors['lineColor']);
        if (strtolower($colors['fillColor'] !== "#ffffff")) {
            $sparkline->setFillColorHex($colors['fillColor']);
        } else {
            $sparkline->deactivateFillColor();
        }
        if (strtolower($colors['minPointColor'] !== "#ffffff")) {
            $sparkline->addPoint("minimum", 5, $colors['minPointColor']);
        }
        if (strtolower($colors['maxPointColor'] !== "#ffffff")) {
            $sparkline->addPoint("maximum", 5, $colors['maxPointColor']);
        }
        if (strtolower($colors['lastPointColor'] !== "#ffffff")) {
            $sparkline->addPoint("last", 5, $colors['lastPointColor']);
        }
    }

    public function render() {
        $this->sparkline->display();
        $this->sparkline->destroy();
    }
}
