<?php

/* * *************************************************************
 *  Copyright notice
 *
 *  (c) 2007 Thomas Waggershauser <waggershauser@airware.de>
 *  (c) 2018 Stefan Beyer SEDAT GmbH <stefan@sedat.de>
 *  All rights reserved
 *
 *  This script is part of Cy4Marktzeitung. The Cy4Marktzeitung project is
 *  free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  The GNU General Public License can be found at
 *  http://www.gnu.org/copyleft/gpl.html.
 *
 *  This script is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  This copyright notice MUST APPEAR in all copies of the script!
 * ************************************************************* */
if (!defined('ENTRY_POINT'))
  die('Falscher Aufruf');


//require_once(K_PATH_MAIN . 'config/lang/eng.php');
require_once(K_PATH_MAIN . 'tcpdf.php');

/**
 * Class pdf
 *
 */
class AdsPDF extends TCPDF {

  static $extract_custom_value = null;
  var $current_col;
  var $current_x;
  var $current_y;
  var $left;
  var $top;
  var $initialized = false;
  var $act_category;
  var $act_tradeType;
  var $tradetypeTop = NULL;
  var $buffer;
  var $temp;
  var $config;
  var $adscount = 0;
  var $cleaner = null;

  var $printHeader = true;
  
  var $categories;

  /**
   * Construct
   *
   * es wird ein temporaeres Object (PDF) und ein 'normales' erzeugt
   * das temporaere ($temp) dient zur Seitenberechnung fuer die Umbrueche (Seite/Spalte)
   *
   * 	__construct($orientation='P', $unit='mm', $format='A4', $unicode=true, $encoding='UTF-8', $diskcache=false)
   * 	  encoding: UTF-8, ISO-8859-1
   *
   *
   * @param bool $temp falls dies ein tempor�res objekt sein soll. vermeiden von rekursionen..
   * @return pdf
   *
   */
  function __construct($temp = NULL) {
    parent::__construct(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true);

    if (!defined('USE_HTML_CLEANER') || USE_HTML_CLEANER) {
      $this->cleaner = new HTMLCleaner(HTMLCleaner::FLAGS_ALL);
    }


    parent::setFontSubsetting(false);
    $this->config = get_pdf_config();

    if (is_null($temp)) {
      // set document information
      $this->SetCreator(PDF_CREATOR);
      $this->SetAuthor(PDF_AUTHOR);
      //$this->SetTitle($doc_title);
      //$this->SetSubject($doc_subject);
      //$this->SetKeywords($doc_keywords);

      $this->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE, PDF_HEADER_STRING);

      $mTop = PDF_MARGIN_TOP;
      if (CATALOG_TYPE === 2) {
        $mTop += $this->config["tradeType"]["top"]["height"] + $this->config["tradeType"]["top"]["margin-bottom"];
      }
      //set margins
      $this->SetMargins(PDF_MARGIN_LEFT, $mTop, PDF_MARGIN_RIGHT);
      //set auto page breaks
      $this->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
      $this->SetHeaderMargin(PDF_MARGIN_HEADER);
      $this->SetFooterMargin(PDF_MARGIN_FOOTER);
      // Temp
      $this->temp = new self(true);
    } else {
      $this->temp = false;
    }
    $this->setImageScale(PDF_IMAGE_SCALE_RATIO); //set image scale factor
  }

  /**
   * Function initialize
   *
   */
  public function initialize() {
    $htitle = replaceTemplate(PDF_HEADER_TITLE, 'count', $this->adscount);
    $hstring = replaceTemplate(PDF_HEADER_STRING, 'count', $this->adscount);
    $this->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, $htitle, $hstring);
    $this->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));
    $this->setFooterFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));

    if ($this->initialized)
      return;

    $this->left = $this->GetX();
    $this->top = $this->GetY();

    $this->current_x = $this->left;
    $this->current_col = 1;
    $this->initialized = true;
  }

  public function setCount($count) {
    $this->adscount = $count;
  }

  public function getCount() {
    return $this->adscount;
  }
  
  public function SetFillColor2($color) {
    if (is_numeric($color)) {
      $this->SetFillColor($color);
    } else if (is_array($color)) {
      $this->SetFillColorArray($color);
    } else if (is_string($color)) {
      $this->SetFillColorArray(html2rgb($color));
    }
  }
  
  public function SetTextColor2($color) {
    if (is_numeric($color)) {
      $this->SetTextColor($color);
    } else if (is_array($color)) {
      $this->SetTextColorArray($color);
    } else if (is_string($color)) {
      $this->SetTextColorArray(html2rgb($color));
    }
  }
  

  /**
   * Page-Break
   * es kann ein Seitenumbruch erzwungen werden
   */
  /* function new_page() {
    $this->add_col(true);
    } */

  // TODO besserer Platz dafür: von außen übergeben?
  function extract_custom_value(&$field) {
    if (!self::$extract_custom_value)
      die('pdf::$extract_custom_value must be set.');
    return (self::$extract_custom_value)($field);
  }


  /**
   * Anzeige in PDF zeichnen
   */
  function print_ad($ad) {
    $config = $this->config["ad"];

    //template
    $buffer = PDF_AD_TEMPLATE;


    //Description ev. kuerzen
    $description = property_exists($ad, 'description') ? $ad->description : '';
    if ($this->cleaner) {
      $description = $this->cleaner->clean($description);
    }

    //console($description);
    //owner-data
    if (property_exists($ad, 'publicationPeriod')) {
      $start = $ad->publicationPeriod->begin;
      $end = $ad->publicationPeriod->end;
    } else {
      $start = null;
      $end = null;
    }
    if ($start)
      $start = new \DateTime($start);
    if ($end)
      $end = new \DateTime($end);

    if (property_exists($ad, 'name')) {
      $buffer = replaceTemplate($buffer, "title", $ad->name);
      //Titel für e-mail Link
      $buffer = replaceTemplate($buffer, "etitle", rawurlencode($ad->name));
    }
    $buffer = replaceTemplate($buffer, "description", $description);
    $buffer = replaceTemplate($buffer, "date", $start ? $start->format('d.m.Y') : '');
    $buffer = replaceTemplate($buffer, "publication_end", $end ? $end->format('d.m.Y') : '');
    //o($ad);
    if (property_exists($ad, 'owner') && $ad->owner) {
      if (property_exists($ad->owner, 'username')) {
        $buffer = replaceTemplate($buffer, "username", $ad->owner->username);
      }
      if (property_exists($ad->owner, 'display')) {
        $buffer = replaceTemplate($buffer, "name", $ad->owner->display);
      }
      if (property_exists($ad->owner, 'email')) {
        $buffer = replaceTemplate($buffer, "email", $ad->owner->email);
      }

      //owner-memberfields
      if (!empty($ad->owner->customValues)) {
        foreach ($ad->owner->customValues as $field) {
          if (!property_exists($field->field, 'internalName')) {
            console('customValue without internalName:');
            co($field->field);
            continue;
          }
          $key = $field->field->internalName;
          $value = $this->extract_custom_value($field);
          if (!is_scalar($value)) {
            $value = "[The Value for ownerfield.$key is not scalar]";
          }
          $buffer = replaceTemplate($buffer, "ownerfield.$key", $value);
        }
      }
    }


    //ad-fields
    if (!empty($ad->customValues)) {
      foreach ($ad->customValues as $field) {
        if (!property_exists($field->field, 'internalName')) {
          console('customValue without internalName:');
          co($field->field);
          continue;
        }
        $key = $field->field->internalName;
        $value = $this->extract_custom_value($field);
        if (!is_scalar($value)) {
          $value = "[The Value for field.$key is not scalar]";
        }
        $buffer = replaceTemplate($buffer, "field.$key", $value);
      }
    }

    foreach (ExtraFieldManager::$fields as $ef => $callback) {
      if (!is_callable($callback)) {
        // console('Die extra field callback for '.$ef.' is.');
        continue;
      }
      $value = $callback($ad, $ef);
      $buffer = replaceTemplate($buffer, $ef, $value);
    }


    $minusOneWeek = new \DateTime("-1 week");
    $minusTwoWeeks = new \DateTime("-2 week");
    $minusFourWeeks = new \DateTime("-4 week");

    // Farbe f�r neue und alte inserate ermitteln
    $inseratColor = null;
    if ($start > $minusFourWeeks) {
      #$on = 'color_1Month';
      $inseratColor = $config['color_1Month'];
    } else {
      #$on = 'color_old';
      $inseratColor = $config['color_old'];
    }


    // Farbe 1-Wochen alte Inserate
    if ($start > $minusOneWeek) {
      $inseratColor = $config['color_1Week'];
      // Farbe 2-Wochen alte Inserate
    } elseif ($start > $minusTwoWeeks) {
      $inseratColor = $config['color_2Week'];
    }

    $this->SetTextColor2($inseratColor);

    $buffer = replaceALL($buffer, "###.[^#]+###", '');

    $oldFontSize = $this->FontSizePt;
    $this->SetFont(PDF_FONT_NAME_DATA, '', $config["fontSize"]);


    $this->writeHTML($buffer, true, false, true, true);
    //$this->writeHTMLCell(PDF_COLUMN_WIDTH, 0, $this->current_x, $this->GetY(), $buffer, $config['border'], 2, 0, true, 'J'); # 'B', 2 , 0);
    //$this->bMargin = $bMargin;
    //console("printing ad " . $ad->name);
    $this->SetTextColor2(0);
    $this->SetFontSize($oldFontSize);

    // margin-bottom
    $this->SetY($this->GetY() + $config["margin-bottom"]);
  }

  function getYSpaceLeft() {
    return $this->PageBreakTrigger - $this->GetY();
    //return $this->config['maxY'] - $this->GetY();
  }

  function GetPageBreakTrigger() {
    return $this->PageBreakTrigger;
  }

  public function JumpToNextCol() {
    if ($this->num_columns > 1) {
      // multi column mode
      if ($this->current_column < ($this->num_columns - 1)) {
        // go to next column
        $this->selectColumn($this->current_column + 1);
        //$this->SetY($this->top + $this->config["tradeType"]["top"]["height"] + $this->config["tradeType"]["top"]["margin-bottom"]);
      } else {
        // add a new page
        $this->AddPage();
        // set first column
        $this->selectColumn(0);
        return true;
      }
      return false;
    }
    $this->AddPage();
    return true;
  }


  /**
   * TradeType in PDF zeichnen
   *
   * @param $tradeType
   * @see add_tradeType()
   */
  function print_tradeType($tradeType = NULL) {
    $conf = $this->config["tradeType"];

    if (is_null($tradeType) && $this->act_tradeType) {   // deprecated
      // falls nichts �bergeben, aber einer gesetzt
      $tradeType = $this->act_tradeType;
    } elseif (is_null($tradeType)) {
      return;
    }

    $tradeType = constant('TRADE_TYPE_' . $tradeType . '_TITLE');

    if (CATALOG_TYPE === 1) {
      $this->Bookmark(trim($tradeType), 1);
    }

    $oldFontSize = $this->FontSizePt;
    $this->SetFont(PDF_FONT_NAME_MAIN, 'B', $conf["fontSize"]);
    //sperren wenn disabled:true
    if (!$conf["disabled"]) {
      $this->cell(0/* PDF_COLUMN_WIDTH */, $conf["height"], trim($tradeType), $conf["border"], 2, 'C');
    }

    $this->SetFontSize($oldFontSize);

    // Padding-bottom
    $this->SetY($this->GetY() + $conf["margin-bottom"]);
  }


  /**
   * Kategorie in PDF zeichnen
   *
   * @param $category ... the category
   */
  function print_category($category = NULL) {
    $conf = $this->config["category"];
    $oldFontSize = $this->FontSizePt;

    $category = $category ? $category : $this->act_category; // deprecated
    #$catArr = explode( $conf['splitChar'], $category );
    $mainCat = isset($category[0]) ? $category[0] : "";
    $subCat = isset($category[1]) ? $category[1] : "";

    // category k�rzen
    //$category = substr($category, 0, 16);

    $this->Bookmark(trim($mainCat), CATALOG_TYPE === 1 ? 0 : 1 );
    
    $this->SetFillColor2($conf["main"]["bgColor"]);
    $this->SetFont(PDF_FONT_NAME_MAIN, 'B', $conf["main"]["fontSize"]);
    //sperren wenn disabled:true
    if (!$conf["disabled"]) {
      $this->cell(0/* F_COLUMN_WIDTH */, $conf["main"]["height"], trim($mainCat), $conf["main"]["border"], 2, $conf["main"]["align"], 1);

      if ($subCat) {
        $this->SetFillColor2($conf["sub"]["bgColor"]);
        $this->SetFont(PDF_FONT_NAME_MAIN, 'B', $conf["sub"]["fontSize"]);
        $this->cell(0/* PDF_COLUMN_WIDTH */, $conf["sub"]["height"], trim($subCat), $conf["sub"]["border"], 2, $conf["sub"]["align"], 1);
      }
    }
    //$this->debug("printing category $category");

    $this->SetFontSize($oldFontSize);
    
    // Padding-bottom
    $this->SetY($this->GetY() + $conf["margin-bottom"]);
  }


  private $tradeTypeTopBookmarksSet = [];

  /**
   * TradeType in PDF zeichnen
   * Tradetype Überschriften für  CATALOG_TYPE === 2
   *
   * @param $tradeType
   * @see add_tradeType()
   */
  public function print_tradeTypeTop() {
    $conf = $this->config["tradeType"];
    #    print_ra($this->tradetypeTop,"tt");
    //
    //if (is_null($this->tradetypeTop) || count($this->tradetypeTop) != 1) {
    //  return;
    //}

    $y = $this->tMargin - $this->config["tradeType"]["top"]["height"] - $this->config["tradeType"]["top"]["margin-bottom"];
    $this->SetY($y);

    $tradeType = $this->tradetypeTop[0];
    $tradeType = constant('TRADE_TYPE_' . $tradeType . '_TITLE');

    // tradetop wird für mode 2 benutzt und da es im header gerendert wird, müssen wir schauen, dass jeder bookmark nur einmal gesetzt wird
    if (!in_array($tradeType, $this->tradeTypeTopBookmarksSet)) {
      $this->Bookmark($tradeType, 0);
      $this->tradeTypeTopBookmarksSet[] = $tradeType;
    }

    $oldFontSize = $this->FontSizePt;
    $this->SetFont(PDF_FONT_NAME_MAIN, 'B', $conf["top"]["fontSize"]);

    $ttwidth = (PDF_COLUMN_WIDTH * PDF_ANZ_COLS) + ((PDF_ANZ_COLS - 1) * PDF_COLUMN_SPACE);

    //Fill-Color
    $this->SetFillColor2($conf["top"]["bgColor"]);

    $this->cell($ttwidth, $conf["top"]["height"], trim($tradeType), 0, 2, $conf["top"]["align"], 1);

    $this->debug("&nbsp;&nbsp;&nbsp;printing tradeType $tradeType");

    $this->SetFontSize($oldFontSize);

    // Padding-bottom
    $this->SetY($this->GetY() + $conf["top"]["margin-bottom"]);
  }

  function debug($x) {
    if ($this->temp) {
      //print_r("<p>$x</p>");
    }
  }

  /**
   * This method is used to render the page header.
   * It is automatically called by AddPage() and could be overwritten in your own inherited class.
   * @public
   * überschrieben um header formatierbar zu machen
   */
  public function Header() {
    if (!$this->printHeader) return;
    
    if ($this->header_xobjid === false) {
      // start a new XObject Template
      $this->header_xobjid = $this->startTemplate($this->w, $this->tMargin);
      $headerfont = $this->getHeaderFont();
      $headerdata = $this->getHeaderData();
      $this->y = $this->header_margin;
      if ($this->rtl) {
        $this->x = $this->w - $this->original_rMargin;
      } else {
        $this->x = $this->original_lMargin;
      }
      if (($headerdata['logo']) AND ( $headerdata['logo'] != K_BLANK_IMAGE)) {
        $imgtype = TCPDF_IMAGES::getImageFileType(K_PATH_IMAGES . $headerdata['logo']);
        if (($imgtype == 'eps') OR ( $imgtype == 'ai')) {
          $this->ImageEps(K_PATH_IMAGES . $headerdata['logo'], '', '', $headerdata['logo_width']);
        } elseif ($imgtype == 'svg') {
          $this->ImageSVG(K_PATH_IMAGES . $headerdata['logo'], '', '', $headerdata['logo_width']);
        } else {
          $this->Image(K_PATH_IMAGES . $headerdata['logo'], '', '', $headerdata['logo_width']);
        }
        $imgy = $this->getImageRBY();
      } else {
        $imgy = $this->y;
      }
      $cell_height = $this->getCellHeight($headerfont[2] / $this->k);
      // set starting margin for text data cell
      if ($this->getRTL()) {
        $header_x = $this->original_rMargin + ($headerdata['logo_width'] * 1.1);
      } else {
        $header_x = $this->original_lMargin + ($headerdata['logo_width'] * 1.1);
      }
      $cw = $this->w - $this->original_lMargin - $this->original_rMargin - ($headerdata['logo_width'] * 1.1);
      $this->SetTextColor2($this->header_text_color);
      // header title
      $this->SetFont($headerfont[0], 'B', $headerfont[2] + 1);
      $this->SetX($header_x);
      $this->Cell($cw, $cell_height, $headerdata['title'], 0, 1, '', 0, '', 0);
      // header string
      $this->SetFont($headerfont[0], $headerfont[1], $headerfont[2]);
      $this->SetX($header_x);


      $this->MultiCell(
              $cw, $cell_height, $headerdata['string'], 0, '', 0, 1, '', '', true, 0, true, // html erlauben
              true, 0, 'T', false);



      // print an ending header line
      $this->SetLineStyle(array('width' => 0.85 / $this->k, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => $headerdata['line_color']));
      $this->SetY((2.835 / $this->k) + max($imgy, $this->y));
      if ($this->rtl) {
        $this->SetX($this->original_rMargin);
      } else {
        $this->SetX($this->original_lMargin);
      }
      $this->Cell(($this->w - $this->original_lMargin - $this->original_rMargin), 0, '', 'T', 0, 'C');
      $this->endTemplate();
    }
    // print header template
    $x = 0;
    $dx = 0;
    if (!$this->header_xobj_autoreset AND $this->booklet AND ( ($this->page % 2) == 0)) {
      // adjust margins for booklet mode
      $dx = ($this->original_lMargin - $this->original_rMargin);
    }
    if ($this->rtl) {
      $x = $this->w + $dx;
    } else {
      $x = 0 + $dx;
    }
    $this->printTemplate($this->header_xobjid, $x, 0, 0, 0, '', '', false);
    if ($this->header_xobj_autoreset) {
      // reset header xobject template at each page
      $this->header_xobjid = false;
    }
    
    // TODO
    // Probleme: 1. Seite, Positionierung
    if (CATALOG_TYPE === 2) {
      $this->print_tradeTypeTop();
    }


  }

  /**
   * Komplette Seite rendern
   *
   * @return String Content
   */
  function render($catalog) {

    if (!is_array($catalog)) {
      return;
    }

    $startY = $this->GetY();

    $this->SetAutoPageBreak(true, 10); // TODO bottom margin?  use maxy from config?

    $colsConfig = array_fill(0, PDF_ANZ_COLS, ['w' => PDF_COLUMN_WIDTH, 's' => PDF_COLUMN_SPACE, 'y' => $startY]);
    $this->setColumnsArray($colsConfig);

    //$this->setCellPaddings(0,0,0,0);
    if (defined('TAG_VS')) {
      $tagvs = TAG_VS;
    } else {
      $tagvs = array(
          'div' => array(0 => array('h' => 0, 'n' => 0), 1 => array('h' => 0, 'n' => 0)),
          'img' => array(0 => array('h' => 0, 'n' => 0), 1 => array('h' => 0, 'n' => 0)),
          //'p'   => array(0 => array('h' => 0,   'n' => 0),   1 => array('h' => 1, 'n' => 0)),
          'ul' => array(0 => array('h' => 0, 'n' => 0), 1 => array('h' => 1, 'n' => 0)),
              //'ol'   => array(0 => array('h' => 0,   'n' => 0),   1 => array('h' => 1, 'n' => 0)),
      );
    }
    $this->setHtmlVSpace($tagvs);

    //$this->commitTransaction();

    $atColStart = true;
    $colHasAds = false;
    foreach ($catalog as $id => $cat) {
      $catNames = $this->categories[$id];
      //add_category
      foreach ($cat as $type => $ads) {
        //add_tradeType
        $adcCount = count($ads);
        for ($n = 0; $n < $adcCount;) {
          $ad = $ads[$n];

          //console('print_ad ' . $ad->name);


          $nochmal = 0;
          do {
            $this->startTransaction();

            if ($n == 0) {
              $this->print_category($catNames);
              if (CATALOG_TYPE === 1) {
                $this->print_tradeType($type);
              }
            }

            $spaceLeft = $this->getYSpaceLeft();
            $page0 = $this->getPage();
            $col0 = $this->getColumn();
            $y0 = $this->GetY();


            $this->print_ad($ad);

            $page1 = $this->getPage();
            $col1 = $this->getColumn();
            $y1 = $this->GetY();

            $pageDif = $page1 - $page0;
            if ($pageDif === 0) {
              $colDif = $col1 - $col0;
            } else {
              $pageDif--;
              $colDif = (PDF_ANZ_COLS - $col0) + ($col1) + ($pageDif * PDF_ANZ_COLS);
            }
            //console('y0='.$y0.' y1='.$y1.' p0='.$page0.' p1='.$page1.' c0='.$col0.' c1='.$col1.' colDif='.$colDif);

            if ($colDif > 0) {
              $colDif--;
              $height = ($this->GetPageBreakTrigger() - $y0) + ($y1 - $startY) + ($colDif * ($this->GetPageBreakTrigger() - $startY));
            } else {
              $height = $y1 - $y0;
            }

            //console(' space='.$spaceLeft.' h='.$height);

            if ($spaceLeft < ($this->GetPageBreakTrigger() - $startY) / 2 && $height > $spaceLeft && $nochmal === 0) {
              $this->rollbackTransaction(true);
              //$this->add_col();
              $wasPageBreak = $this->JumpToNextCol();

              //if ($wasPageBreak) {
              //   $this->print_tradeTypeTop();
              //   $wasPageBreak = false;
              //}
              //console('Nochmal: '.$ad->name);
              $nochmal = 1;
            } else {
              $nochmal = 0;
            }
          } while ($nochmal > 0);

          $this->commitTransaction();

          $atColStart = false;
          $colHasAds = true;
          $n++;
        }
      }
    }
  }

  function outputPDF($name = '', $dest = '') {
    $this->Output($name, $dest);
    //$this->stream($name, ['Attachment' => 0]);
  }

}
