<?php
/**
 * @copyright (c) Kufer Software GmbH, Oderstraße 7, D-84453 Mühldorf
 */

namespace Kufer\Web\Classes\Pdf\Helper;


class Row extends InnerBorderContainer
{
  
  protected $widths = array();

  
  public function addColumn($child, $width = ''): int
  {
    if (\is_array($child)) {
      $area = new TextArea($this->fpdf, $child);

      return $this->addColumn($area, $width);
    }
    if (\is_string($child)) {
      $field = new TextField($this->fpdf, $child);

      return $this->addColumn($field, $width);
    }

    $idx = $this->addChild($child);
    if ($width !== '' && $width !== '%') {
      $this->widths[$idx] = $width;
      $child->setWidth($width);
    } if (isset($this->widths[$idx])) {
      $child->setWidth($this->widths[$idx]);
    }

    return $idx;
  }

  public function setColumn(int $id, RenderObject $column): void
  {
    $this->children = $column;
  }

  public function getColumn(int $id): ?RenderObject
  {
    return $this->children[$id];
  }

  public function addColumns($children): void
  {
    foreach ($children as $child) {
      $this->addColumn($child);
    }
  }

  public function setColumnWidth(int $i, $width = ''): void
  {
    if ($width !== '') {
      $this->widths[$i] = $width;
    } elseif (isset($this->widths[$i])) {
      unset($this->widths[$i]);
    }
  }

  public function getChildComputedWidth(int $idx): float
  {
    if (array_key_exists($idx, $this->widths)) {
      $this->children[$idx]->setWidth($this->widths[$idx]);
    }

    return $this->children[$idx]->getComputedWidth();
  }

  public function render(): void
  {
    $this->context(function() {
      if (static::DEBUG_ALL) {
        $this->drawOutline(255, 100);
      }

      $widths = $this->widths;

      $startX = $this->fpdf->GetX();
      $startY = $this->fpdf->GetY();

      $endX = $startX + $this->getComputedWidth();
      $height = $this->getComputedHeight();
      if (!is_null($height)) {
        $endY = $startY + $height;
      } else {
        $endY = null;
      }

      
      if (!is_null($endY)) {
        $this->fillBackgroundColor($startX, $startY, $endX, $endY);
      }

      foreach ($this->children as $idx => $child) {
        if (isset($widths[$idx])) {
          $child->setWidth($widths[$idx]);
        }
        $child->setHeight($height);
      }

      
      if ($startY + $height > $this->fpdf->getPageBreakTrigger()) {
        $this->fpdf->AddPage();
        $this->fpdf->SetX($startX);
        $startY = $this->fpdf->GetY();
      }

      $xOffset = 0;
      $maxComputedHeight = null;
      foreach ($this->children as $idx => $child) {
        $this->fpdf->SetX($startX + $xOffset);
        $child->render();
        if (is_null($maxComputedHeight) || $this->fpdf->GetY() - $startY > $maxComputedHeight) {
          $maxComputedHeight = $this->fpdf->GetY() - $startY;
        }
        $xOffset += $child->getComputedWidth();

        if (!$this->isLastChild($idx) && $this->hasInnerBorder($idx)) {
          $line = new Line($this->fpdf, $this->fpdf->GetX(), $startY, $this->fpdf->GetX(), $startY + ($height ?? $maxComputedHeight));
          $line->setParent($this);
          $line->render();
        }

        $this->fpdf->SetY($startY, false);
      }

      if (!is_null($endY)) {
        $this->drawBorder($startX, $startY, $endX, $endY);
      }

      
      $this->fpdf->Ln($height ?? $maxComputedHeight);
      $this->fpdf->setX($startX);
    });
  }

  
  public function setMissingHeightToMaxComputedHeight(): void
  {
    $maxComputedHeight = $this->getMaxChildrenHeightIgnoreNull();
    if (is_null($maxComputedHeight)) {
      return;
    }

    foreach ($this->children as $child) {
      if (is_null($child->getComputedHeight())) {
        $child->setHeight($maxComputedHeight);
      }
    }
  }

  private function fillBackgroundColor($startX, $startY, $endX, $endY)
  {
    if ($this->hasBackgroundColor()) {
      $this->fpdf->setX($startX);
      $this->fpdf->setY($startY, false);
      $this->fpdf->Cell($endX - $startX, $endY - $startY, '', 0, 0, '', $this->getBackgroundColor());
    }
  }

  private function isLastChild($idx): bool
  {
    return $idx === \count($this->children) - 1;
  }

  public function getMaxChildrenHeightIgnoreNull(): ?float
  {
    return max(0, ...array_filter(array_map(function(RenderObject $child) {
      return $child->getComputedHeight();
    }, $this->children)));
  }

  public function getMaxChildrenHeight(): ?float
  {
    foreach ($this->children as $child) {
      if (is_null($child->getHeight())) {
        return null;
      }
    }

    return max(0, ...array_filter(array_map(function(RenderObject $child) {
      return $child->getComputedHeight();
    }, $this->children)));
  }

  public function getAutoWidth(): ?float
  {
    return array_sum(array_map(function($idx) {
      return $this->getChildComputedWidth($idx);
    }, array_keys($this->children)));
  }

  public function getAutoHeight(): ?float
  {
    return $this->getMaxChildrenHeight();
  }

  
  public function setAutoEvenlyDistributedWidth(): self
  {
    $this->context(function() {
      assert(!is_null($this->width));
      $w = $this->getComputedWidth();

      $wForChild = $w / count($this->children);
      foreach ($this->children as $child) {
        $child->setWidth($wForChild);
      }
    });

    return $this;
  }

  public function handlesTriggerPageBreak(): bool
  {
    if (empty($this->children)) {
      return false;
    }

    foreach ($this->children as $child) {
      if (!$child->handlesTriggerPageBreak()) {
        return false;
      }
    }

    return true;
  }
}