<?php

// SPDX-FileCopyrightText: 2018 Icinga GmbH <https://icinga.com>
// SPDX-License-Identifier: GPL-3.0-or-later

namespace Icinga\Chart\Graph;

use DOMElement;
use Icinga\Chart\Primitive\Animation;
use Icinga\Chart\Primitive\Drawable;
use Icinga\Chart\Primitive\Rect;
use Icinga\Chart\Primitive\Styleable;
use Icinga\Chart\Render\RenderContext;

/**
 * Bar graph implementation
 */
class BarGraph extends Styleable implements Drawable
{
    /**
     * The dataset order
     *
     * @var int
     */
    private $order = 0;

    /**
     * The width of the bars.
     *
     * @var int
     */
    private $barWidth = 3;

    /**
     * The dataset to use for this bar graph
     *
     * @var array
     */
    private $dataSet;

    /**
     * The tooltips
     *
     * @var
     */
    private $tooltips;

    /**
     * All graphs
     *
     * @var
     */
    private $graphs;

    /**
     * Create a new BarGraph with the given dataset
     *
     * @param array $dataSet An array of data points
     * @param int $order The graph number displayed by this BarGraph
     * @param ?array $tooltips The tooltips to display for each value
     */
    public function __construct(
        array $dataSet,
        array &$graphs,
        $order,
        ?array $tooltips = null
    ) {
        $this->order = $order;
        $this->dataSet = $dataSet;

        $this->tooltips = $tooltips;
        $ts = [];
        foreach ($this->tooltips as $value) {
            $ts[] = $value;
        }
        $this->tooltips = $ts;

        $this->graphs = $graphs;
    }

    /**
     * Apply configuration styles from the $cfg
     *
     * @param array $cfg        The configuration as given in the drawBars call
     */
    public function setStyleFromConfig(array $cfg)
    {
        foreach ($cfg as $elem => $value) {
            if ($elem === 'color') {
                $this->setFill($value);
            } elseif ($elem === 'width') {
                $this->setStrokeWidth($value);
            }
        }
    }

    /**
     * Draw a single rectangle
     *
     * @param array     $point          The
     * @param string    $fill           The fill color to use
     * @param           $strokeWidth
     * @param ?int      $index
     *
     * @return Rect
     */
    private function drawSingleBar($point, $fill, $strokeWidth, $index = null)
    {
        $rect = new Rect($point[0] - ($this->barWidth / 2), $point[1], $this->barWidth, 100 - $point[1]);
        $rect->setFill($fill);
        $rect->setStrokeWidth($strokeWidth);
        $rect->setStrokeColor('black');
        if (isset($index)) {
            $rect->setAttribute('data-icinga-graph-index', $index);
        }
        $rect->setAttribute('data-icinga-graph-type', 'bar');
        $rect->setAdditionalStyle(['clip-path' => 'url(#clip)']);
        return $rect;
    }

    /**
     * Render this BarChart
     *
     * @param   RenderContext   $ctx    The rendering context to use for drawing
     *
     * @return  DOMElement      $dom    Element
     */
    public function toSvg(RenderContext $ctx)
    {
        $doc = $ctx->getDocument();
        $group = $doc->createElement('g');
        $idx = 0;

        if (count($this->dataSet) > 15) {
            $this->barWidth = 2;
        }
        if (count($this->dataSet) > 25) {
            $this->barWidth = 1;
        }

        foreach ($this->dataSet as $x => $point) {
            // add white background bar, to prevent other bars from altering transparency effects
            $bar = $this->drawSingleBar($point, 'white', $this->strokeWidth, $idx++)->toSvg($ctx);
            $group->appendChild($bar);

            // draw actual bar
            $bar = $this->drawSingleBar($point, $this->fill, $this->strokeWidth)->toSvg($ctx);
            if (isset($this->tooltips[$x])) {
                $data = array(
                    'label' => isset($this->graphs[$this->order]['label']) ?
                            strtolower($this->graphs[$this->order]['label']) : '',
                    'color' => isset($this->graphs[$this->order]['color']) ?
                            strtolower($this->graphs[$this->order]['color']) : '#fff'
                );
                $format = isset($this->graphs[$this->order]['tooltip'])
                    ? $this->graphs[$this->order]['tooltip'] : null;
                $title = $ctx->getDocument()->createElement('title');
                $title->textContent = $this->tooltips[$x]->renderNoHtml($this->order, $data, $format);
                $bar->appendChild($title);
            }
            $group->appendChild($bar);
        }
        return $group;
    }
}
