<?php

class PageGraph extends Page
{
  public int $FontSize;
  public string $FontFileName;
  public float $ValueToImageHeigthCoefficient;
  public int $DefaultWidth;
  public int $DefaultHeight;

  function __construct(System $System)
  {
    parent::__construct($System);
    $this->FontSize = 10;
    $this->FontFileName = 'Arial.ttf';
    $this->ValueToImageHeigthCoefficient = 0.9;
  }

  function Show(): string
  {
    $this->RawPage = true;
    $this->Render();
    return '';
  }

  function Render(): void
  {
    $PrefixMultiplier = new PrefixMultiplier();

    if (array_key_exists('Debug', $_GET)) $Debug = $_GET['Debug'];
      else $Debug = 0;

    if (!array_key_exists('From', $_GET)) die('Musíte zadat čas počátku');
    $StartTime = addslashes($_GET['From']);
    if (!array_key_exists('To', $_GET)) die('Musíte zadat čas konce');
    $EndTime = addslashes($_GET['To']);
    if ($EndTime < $StartTime) $EndTime = $StartTime + 60;
    $TimeDifference = $EndTime - $StartTime;
    if (!array_key_exists('Measure', $_GET)) die('Musíte zadat měřenou veličinu');
    $MeasureId = addslashes($_GET['Measure']);
    if (!array_key_exists('Width', $_GET)) $Width = $this->DefaultWidth;
      else $Width = addslashes($_GET['Width']);
    if (!array_key_exists('Height', $_GET)) $Height = $this->DefaultHeight;
      else $Height = addslashes($_GET['Height']);
    if (!array_key_exists('Differential', $_GET)) $Differential = $this->Config['Application']['DefaultVariables']['Differential'];
      else $Differential = addslashes($_GET['Differential']);
    $VerticalLinesCount = round($Height / ($this->FontSize + 4));

    $StopWatchStart = GetMicrotime();

    $Measure = new Measure($this->System);
    $Measure->Load($MeasureId);
    //$Measure->LevelReducing = $this->LevelReducing;
    //$Measure->ReferenceTime = $this->Config['Application']['ReferenceTime'];
    //$Measure->MaxLevel = $this->Config['Application']['MaxLevel'];
    //$Measure->DivisionCount = $this->Config['Application']['DivisionCount'];
    //$Measure->Differential = $this->Config['Application']['DefaultVariables']['Differential'];
    $Measure->Debug = $Debug;
    $DbResult2 = $this->Database->select('MeasureMethod', '*', 'Id='.$Measure->Data['Method']);
    $MeasureMethod = $DbResult2->fetch_assoc();

    $FontSize = $this->FontSize;
    $FontFile = dirname(__FILE__).'/../../style/'.$this->System->Config['Web']['Style'].'/'.$this->FontFileName;

    $Level = floor(log(($EndTime - $StartTime) / $Measure->DivisionCount / 60) / log($Measure->LevelReducing)) - 1;
    if ($Level < 0) $Level = 0;
    if ($Level > $Measure->MaxLevel) $Level = $Measure->MaxLevel;
    //$Level = 0;

    $Points = $Measure->GetValues($StartTime, $EndTime, $Level);

    if ($Debug) echo('Points count: '.count($Points).'<br/>');    

    // Calculate total max, avg, min value
    $MaxValue = -1000000000000000000;
    $AvgValue = 0;
    $MinValue = 1000000000000000000;
    foreach ($Points as $Index => $Item)
    {
      //$Points[$Index]['min'] =  $Points[$Index]['min'] / $Measure['Divider'];
      //$Points[$Index]['avg'] =  $Points[$Index]['avg'] / $Measure['Divider'];
      //$Points[$Index]['max'] =  $Points[$Index]['max'] / $Measure['Divider'];
      if ($Points[$Index]['Avg'] > $MaxValue) $MaxValue = $Points[$Index]['Avg'];
      if ($Points[$Index]['Avg'] < $MinValue) $MinValue = $Points[$Index]['Avg'];
      if ($Points[$Index]['Max'] > $MaxValue) $MaxValue = $Points[$Index]['Max'];
      if ($Points[$Index]['Min'] < $MinValue) $MinValue = $Points[$Index]['Min'];
      $AvgValue = $AvgValue + $Points[$Index]['Avg'];
    }
    //$MinValue = round($MinValue * $Measure['Divider']) / $Measure['Divider'];
    //$MaxValue = round($MaxValue * $Measure['Divider']) / $Measure['Divider'];
    $AvgValue = $AvgValue / count($Points); //round( * $Measure['Divider']) / $Measure['Divider'];

    // Generate polygon and recalculate y values to fit graph height
    $PointsMin = array(0, $Height - 1);
    $PointsAvg = array(0, $Height - 1);
    $PointsMax = array(0, $Height - 1);
    if (($MaxValue - $MinValue) == 0) $MaxValue = $MinValue + 1;
    {
      foreach ($Points as $Index => $Item)
      {
        $PointsMin[] = $Index * $Width / $Measure->DivisionCount;
        $PointsMin[] = $Height - 1 - ($Points[$Index]['Min'] - $MinValue) / ($MaxValue - $MinValue) * $Height * $this->ValueToImageHeigthCoefficient;
        $PointsAvg[] = $Index * $Width / $Measure->DivisionCount;
        $PointsAvg[] = $Height - 1 - ($Points[$Index]['Avg'] - $MinValue) / ($MaxValue - $MinValue) * $Height * $this->ValueToImageHeigthCoefficient;
        $PointsMax[] = $Index * $Width / $Measure->DivisionCount;
        $PointsMax[] = $Height - 1 - ($Points[$Index]['Max'] - $MinValue) / ($MaxValue - $MinValue) * $Height * $this->ValueToImageHeigthCoefficient;
      }
    }
    $PointsMin[] = $Width - 1;
    $PointsMin[] = $Height - 1;
    $PointsAvg[] = $Width - 1;
    $PointsAvg[] = $Height - 1;
    $PointsMax[] = $Width - 1;
    $PointsMax[] = $Height - 1;
    $PointsMin[] = $Width - 1;
    $PointsMin[] = $Height - 1;
    $PointsAvg[] = $Width - 1;
    $PointsAvg[] = $Height - 1;
    $PointsMax[] = $Width - 1;
    $PointsMax[] = $Height - 1;


    //array_unshift($Points, $Height - 1);
    //array_unshift($Points, 0);
    //$Points[] = $Width - 1;
    //$Points[] = $Height - 1;

    // Generate image
    if (!$Debug)
    {
      Header('Content-type: image/png');
      Header('Cache-Control: no-cache');  // Dynamic graph - no cache
      $Image = @imagecreate($Width, $Height);
      $BackgroundColor = imagecolorallocate($Image, 255, 255, 255);
      $Black = imagecolorallocate($Image, 0, 0, 0);
      $White = imagecolorallocate($Image, 255, 255, 255);
      $Gray = imagecolorallocate($Image, 200, 200, 200);
      $DarkGray = imagecolorallocate($Image, 100, 100, 100);
      $LightBlue = imagecolorallocate($Image, 150, 150, 255);
      $Blue = imagecolorallocate($Image, 0, 0, 255);
      $LightRed = imagecolorallocate($Image, 255, 150, 150);
      $Red = imagecolorallocate($Image, 255, 0, 0);
      $Green = imagecolorallocate($Image, 0, 200, 0);
      $LightGreen = imagecolorallocate($Image, 150, 255, 150);

      imagefilledpolygon($Image, $PointsMax, count($PointsMax) / 2, $LightRed);
      imagefilledpolygon($Image, $PointsAvg, count($PointsAvg) / 2, $LightGreen);
      imagefilledpolygon($Image, $PointsMin, count($PointsMin) / 2, $LightBlue);

      $TimeMarks = array(1, 60, 60*60, 60*60*24, 60*60*24*7, 60*60*24*30, 60*60*24*365, 60*60*24*365*10);

      $TimeRange = $EndTime - $StartTime;
      $TimeMarksIndex = 0;
      while (($TimeRange / $TimeMarks[$TimeMarksIndex]) > 1) $TimeMarksIndex += 1;
      if ($TimeMarksIndex < 2) $TimeMarksIndex = 2;
      $MajorTimeMarks = $TimeMarks[$TimeMarksIndex - 1];
      $MinorTimeMarks = $TimeMarks[$TimeMarksIndex - 2];

      $TimeShift = $Measure->AlignTime($StartTime, $MajorTimeMarks) - $StartTime;
      //imagestring($Image, 10, 40, 50, $TimeShift, $Black);

      // Zobraz měřítko Y
      $VerticalLinesDistance = $Height / $VerticalLinesCount;
      for ($I = 1; $I <= $VerticalLinesCount; $I++)
      {
        $Y = $Height - 1 - ($VerticalLinesDistance * $I);
        for ($X = 1; $X < $Width; $X = $X + 3) imagesetpixel($Image, $X, $Y, $Gray);
        //imageline($Image, 30, $Y, $Width-1, $Y, IMG_COLOR_STYLED);
      }

      $TimeShift = $Measure->AlignTime($StartTime, $MinorTimeMarks) - $StartTime;

      // Zobraz měřítko X
      $LastTextEnd = 0;
      for ($Time = $StartTime; $Time < $EndTime; $Time += $MajorTimeMarks)
      {
        $X = round(($Time - $StartTime + $TimeShift) / $TimeRange * $Width) % $Width;
        //imageline($Image, 30, $Y, $Width-1, $Y, IMG_COLOR_STYLED);
        if (($MajorTimeMarks > 60 * 60 * 24)) $Text = date('j.n.Y', $Time + $TimeShift);
          else $Text = date('j.n.Y G:i', $Time + $TimeShift);
        $BoundBox = imagettfbbox($FontSize, 0, $FontFile, $Text);
        if ($LastTextEnd < ($X - ($BoundBox[2] - $BoundBox[0] + 20) / 2))
        {
          for ($Y = 0; $Y < $Height; $Y = $Y + 1) imagesetpixel($Image, $X, $Y, $Gray);
          imagettftext($Image, $FontSize, 0, $X - ($BoundBox[2] - $BoundBox[0]) / 2,  $Height - 2, $Black, $FontFile, $Text);
          $LastTextEnd = $X + ($BoundBox[2] - $BoundBox[0]) / 2;
        }
        else for ($Y = 0; $Y < $Height; $Y = $Y + 3) imagesetpixel($Image, $X, $Y, $Gray);
      }

      // Popisky osy Y
      for ($I = 1; $I <= $VerticalLinesCount; $I++)
      {
        $Y = $Height - 1 - ($VerticalLinesDistance * $I);
        //$Y = $Height - 1 - ($VerticalLinesDistance * $I / ($MaxValue - $MinValue) *
        //  $this->ValueToImageHeigthCoefficient * $Height);
        $Text = $PrefixMultiplier->Add(round(($I * $VerticalLinesDistance / $Height /
          $this->ValueToImageHeigthCoefficient * ($MaxValue - $MinValue) + $MinValue)), $MeasureMethod['Unit'], 3);
        $BoundBox = imagettfbbox($FontSize, 0, $FontFile, $Text);
        if (($Y - ($BoundBox[5] - $BoundBox[1]) / 2) > 10)
          imagettftext($Image, $FontSize, 0, 2,  $Y - ($BoundBox[5] - $BoundBox[1]) / 2, $Black, $FontFile, $Text);
      }
      $GenerationTime = floor((GetMicrotime() - $StopWatchStart) * 1000  ) / 1000;

      $Left = $Width - 10;
      $Text = '    Max. '.$PrefixMultiplier->Add($MaxValue, $MeasureMethod['Unit']);
      $BoundingBox = imagettfbbox($FontSize, 0, $FontFile, $Text);
      $Left -= ($BoundingBox[2] - $BoundingBox[0]);
      imagettftext($Image, $FontSize, 0, $Left, 14, $Red, $FontFile, $Text);

      $Text = '    Avg.  '.$PrefixMultiplier->Add($AvgValue, $MeasureMethod['Unit']);
      $BoundingBox = imagettfbbox($FontSize, 0, $FontFile, $Text);
      $Left -= ($BoundingBox[2] - $BoundingBox[0]);
      imagettftext($Image, $FontSize, 0, $Left, 14, $Green, $FontFile, $Text);

      $Text = '    Min.  '.$PrefixMultiplier->Add($MinValue, $MeasureMethod['Unit']);
      $BoundingBox = imagettfbbox($FontSize, 0, $FontFile, $Text);
      $Left -= ($BoundingBox[2] - $BoundingBox[0]);
      imagettftext($Image, $FontSize, 0, $Left, 14, $Blue, $FontFile, $Text);
      //imagestring($Image, 2, 70, 20, 'Vygenerováno za '.$GenerationTime.' sekund', $Black);
      //imagestring($Image, 2, 50, 30, 'Level: '.$Level, $Black);

      imagettftext($Image, $FontSize, 0, 70, 14, $Black, $FontFile, $Measure->Data['Description']);
      imagerectangle($Image, 0, 0, $Width - 1, $Height - 1, $Black);   // Frame border
      imagepng($Image);
      imagedestroy($Image);
    }
  }
}
