<?php

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

namespace Piwik\Plugins\ImageGraph\StaticGraph;

use Piwik\Piwik;

class HorizontalBar extends GridGraph
{
    public const INTERLEAVE = 0.30;
    public const PADDING_CHARS = ' ';
    public const LEGEND_SQUARE_WIDTH = 11;
    public const MIN_SPACE_BETWEEN_HORIZONTAL_VALUES = 5;
    public const LOGO_MIN_RIGHT_MARGIN = 3;

    public function renderGraph()
    {
        $verticalLegend = false;

        // create resized copies of logo to match maximum width / height
        foreach ($this->abscissaLogos as &$logoPath) {
            $logoPath = $this->createResizedImageCopyIfNeeded($logoPath);
            list($logoWidth, $logoHeight) = self::getLogoSize($logoPath);
            $logoPathToHeight[$logoPath] = $logoHeight;
        }

        // determine the maximum logo width & height
        list($maxLogoWidth, $maxLogoHeight) = self::getMaxLogoSize($this->abscissaLogos);

        // truncate report
        $graphHeight = $this->getGraphBottom($horizontalGraph = true) - $this->getGridTopMargin($horizontalGraph = true, $verticalLegend);

        list($abscissaMaxWidth, $abscissaMaxHeight) = $this->getMaximumTextWidthHeight($this->abscissaSeries);
        list($ordinateMaxWidth, $ordinateMaxHeight) = $this->getMaximumTextWidthHeight($this->ordinateSeries);

        $numberOfSeries = count($this->ordinateSeries);
        $ordinateMaxHeight = $ordinateMaxHeight * $numberOfSeries;

        $textMaxHeight = $abscissaMaxHeight > $ordinateMaxHeight ? $abscissaMaxHeight : $ordinateMaxHeight;

        $minLineWidth = ($textMaxHeight > $maxLogoHeight ? $textMaxHeight : $maxLogoHeight) + (self::MIN_SPACE_BETWEEN_HORIZONTAL_VALUES * $numberOfSeries);
        $maxNumOfValues = floor($graphHeight / $minLineWidth);
        $abscissaSeriesCount = count($this->abscissaSeries);

        if ($maxNumOfValues < $abscissaSeriesCount - 1) {
            $sumOfOthers = array();
            $truncatedOrdinateSeries = array();
            $truncatedAbscissaLogos = array();
            $truncatedAbscissaSeries = array();
            foreach ($this->ordinateSeries as $column => $data) {
                $truncatedOrdinateSeries[$column] = array();
                $sumOfOthers[$column] = 0;
            }

            $i = 0;
            for (; $i < $maxNumOfValues; $i++) {
                foreach ($this->ordinateSeries as $column => $data) {
                    $truncatedOrdinateSeries[$column][] = $data[$i];
                }

                $truncatedAbscissaLogos[] = isset($this->abscissaLogos[$i]) ? $this->abscissaLogos[$i] : null;
                $truncatedAbscissaSeries[] = $this->abscissaSeries[$i];
            }

            for (; $i < $abscissaSeriesCount; $i++) {
                foreach ($this->ordinateSeries as $column => $data) {
                    $sumOfOthers[$column] += $data[$i];
                }
            }

            foreach ($this->ordinateSeries as $column => $data) {
                $truncatedOrdinateSeries[$column][] = $sumOfOthers[$column];
            }

            $truncatedAbscissaSeries[] = Piwik::translate('General_Others');
            $this->abscissaSeries = $truncatedAbscissaSeries;
            $this->ordinateSeries = $truncatedOrdinateSeries;
            $this->abscissaLogos = $truncatedAbscissaLogos;
        }

        // blank characters are used to pad labels so the logo can be displayed
        $paddingText = '';
        $paddingWidth = 0;
        if ($maxLogoWidth > 0) {
            while ($paddingWidth < $maxLogoWidth + self::LOGO_MIN_RIGHT_MARGIN) {
                $paddingText .= self::PADDING_CHARS;
                list($paddingWidth, $paddingHeight) = $this->getTextWidthHeight($paddingText);
            }
        }

        // determine the maximum label width according to the minimum comfortable graph size
        $gridRightMargin = $this->getGridRightMargin($horizontalGraph = true);
        $minGraphSize = ($this->width - $gridRightMargin) / 2;

        $metricLegendWidth = 0;
        foreach ($this->ordinateLabels as $column => $label) {
            list($textWidth, $textHeight) = $this->getTextWidthHeight($label);
            $metricLegendWidth += $textWidth;
        }

        $legendWidth = $metricLegendWidth + ((self::HORIZONTAL_LEGEND_LEFT_MARGIN + self::LEGEND_SQUARE_WIDTH) * $numberOfSeries);
        if ($this->showLegend) {
            if ($legendWidth > $minGraphSize) {
                $minGraphSize = $legendWidth;
            }
        }

        $gridLeftMarginWithoutLabels = $this->getGridLeftMargin($horizontalGraph = true, $withLabel = false);
        $labelWidthLimit =
            $this->width
            - $gridLeftMarginWithoutLabels
            - $gridRightMargin
            - $paddingWidth
            - $minGraphSize;

        // truncate labels if needed
        foreach ($this->abscissaSeries as &$label) {
            $label = $this->truncateLabel($label, $labelWidthLimit);
        }

        $gridLeftMarginBeforePadding = $this->getGridLeftMargin($horizontalGraph = true, $withLabel = true);

        // pad labels for logo space
        foreach ($this->abscissaSeries as &$label) {
            $label .= $paddingText;
        }

        $this->initGridChart(
            $displayVerticalGridLines = false,
            $bulletType = LEGEND_FAMILY_BOX,
            $horizontalGraph = true,
            $showTicks = false,
            $verticalLegend
        );

        $valueColor = $this->textColor;
        $this->pImage->drawBarChart(
            array(
                 'DisplayValues' => true,
                 'Interleave'    => self::INTERLEAVE,
                 'DisplayR'      => $valueColor['R'],
                 'DisplayG'      => $valueColor['G'],
                 'DisplayB'      => $valueColor['B'],
            )
        );

//        // display icons
        $graphData = $this->pData->getData();
        $numberOfRows = count($this->abscissaSeries);
        $logoInterleave = $this->getGraphHeight(true, $verticalLegend) / $numberOfRows;
        for ($i = 0; $i < $numberOfRows; $i++) {
            if (isset($this->abscissaLogos[$i])) {
                $currentLogoPath = $this->abscissaLogos[$i];

                if (isset($logoPathToHeight[$currentLogoPath])) {
                    $logoHeight = $logoPathToHeight[$currentLogoPath];

                    $pathInfo = pathinfo($currentLogoPath);
                    $logoExtension = strtoupper($pathInfo['extension']);
                    $drawingFunction = 'drawFrom' . $logoExtension;

                    $logoYPosition =
                        ($logoInterleave * $i)
                        + $this->getGridTopMargin(true, $verticalLegend)
                        + $graphData['Axis'][1]['Margin']
                        - $logoHeight / 2
                        + 1;

                    if (method_exists($this->pImage, $drawingFunction)) {
                        $this->pImage->$drawingFunction(
                            $gridLeftMarginBeforePadding,
                            $logoYPosition,
                            $currentLogoPath
                        );
                    }
                }
            }
        }
    }
}
