<?php

/**
 * E005_header_footer.php
 *
 * @since       2026-04-19
 * @category    Library
 * @package     Pdf
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2002-2026 Nicola Asuni - Tecnick.com LTD
 * @license     https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
 * @link        https://github.com/tecnickcom/tc-lib-pdf
 *
 * This file is part of tc-lib-pdf software library.
 */

// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
// trusted paths that covers this package tree, so run the examples in place. To read assets
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
// parameter (see E047_remote_resources_security.php).

// NOTE: run make fonts in the project root to generate the dependencies and example fonts.

// autoloader when using Composer
require __DIR__ . '/../vendor/autoload.php';

// define fonts directory
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));

// autoloader when using RPM or DEB package installation
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');

// ----------

/**
 * Custom PDF class with a repeating page header and footer.
 *
 * Extends Tcpdf and overrides defaultPageContent() so that every
 * new page automatically receives a branded header and a numbered footer.
 * The mechanism is activated by calling enableDefaultPageContent(true).
 */
class PdfWithHeaderFooter extends \Com\Tecnick\Pdf\Tcpdf
{
    /** Horizontal margin used by the header and footer bands (mm). */
    private const HF_MARGIN = 10.0;

    /** Height of the header band (mm). */
    private const HEADER_H = 12.0;

    /** Height of the footer band (mm). */
    private const FOOTER_H = 10.0;

    /** Document title shown left-aligned in the header. */
    private string $headerTitle = '';

    /** Subtitle / date shown right-aligned in the header. */
    private string $headerSubtitle = '';

    /**
     * Set the text displayed in the page header.
     *
     * @param string $title    Left-aligned title.
     * @param string $subtitle Right-aligned subtitle (e.g. date or company name).
     */
    public function setHeaderText(string $title, string $subtitle): void
    {
        $this->headerTitle = $title;
        $this->headerSubtitle = $subtitle;
    }

    /**
     * Generates the repeating header and footer for every page.
     *
     * This method is called automatically by setPageContext() whenever a new
     * page is added, provided enableDefaultPageContent(true) has been called.
     *
     * @param int $pid Page index (0-based).
     *
     * @return string Raw PDF stream prepended to the page content.
     */
    public function defaultPageContent(int $pid = -1): string
    {
        if ($pid < 0) {
            $pid = $this->page->getPageId();
        }

        // Insert the default font once and cache it for subsequent pages.
        if ($this->defaultfont === null) {
            $this->defaultfont = $this->font->insert($this->pon, 'helvetica', '', 9);
        }

        $page = $this->page->getPage($pid);
        $pw = $page['width'];
        $ph = $page['height'];

        $lm = self::HF_MARGIN; // left margin x
        $rm = $pw - self::HF_MARGIN; // right margin x
        $tw = $pw - (2 * self::HF_MARGIN); // usable band width

        $lineStyle = [
            'lineWidth' => 0.25,
            'lineCap' => 'butt',
            'lineJoin' => 'miter',
            'dashArray' => [],
            'dashPhase' => 0,
            'lineColor' => '#555555',
        ];

        $out = '';

        // ---- HEADER ------------------------------------------------

        $headerY = self::HF_MARGIN;
        $headerOut = $this->graph->getStartTransform();
        $headerOut .= $this->defaultfont['out'];

        // Title – left-aligned, bold
        if ($this->headerTitle !== '') {
            $bfontBold = $this->font->insert($this->pon, 'helvetica', 'B', 10);
            $headerOut .= $bfontBold['out'];
            $headerOut .= $this->color->getPdfColor('#1a3a6b');
            $headerOut .= $this->getTextCell(
                txt: $this->headerTitle,
                posx: $lm,
                posy: $headerY,
                width: $tw * 0.65,
                height: self::HEADER_H,
                offset: 0,
                linespace: 0,
                valign: \Com\Tecnick\Pdf\TextVAlign::Center,
                halign: \Com\Tecnick\Pdf\TextHAlign::Left,
            );
            $headerOut .= $this->defaultfont['out'];
        }

        // Subtitle – right-aligned
        if ($this->headerSubtitle !== '') {
            $headerOut .= $this->color->getPdfColor('#555555');
            $headerOut .= $this->getTextCell(
                txt: $this->headerSubtitle,
                posx: $lm + ($tw * 0.65),
                posy: $headerY,
                width: $tw * 0.35,
                height: self::HEADER_H,
                offset: 0,
                linespace: 0,
                valign: \Com\Tecnick\Pdf\TextVAlign::Center,
                halign: \Com\Tecnick\Pdf\TextHAlign::Right,
            );
        }

        // Separator line below the header
        $headerLineY = $headerY + self::HEADER_H;
        $headerOut .= $this->graph->getLine($lm, $headerLineY, $rm, $headerLineY, $lineStyle);
        $headerOut .= $this->graph->getStopTransform();

        $out .= $this->beginArtifact('Pagination', 'Header');
        $out .= $headerOut;
        $out .= $this->endArtifact();

        // ---- FOOTER ------------------------------------------------

        $footerLineY = $ph - self::HF_MARGIN - self::FOOTER_H;
        $footerOut = $this->graph->getStartTransform();
        $footerOut .= $this->defaultfont['out'];

        // Separator line above the footer
        $footerOut .= $this->graph->getLine($lm, $footerLineY, $rm, $footerLineY, $lineStyle);

        // Page number – centred
        $footerOut .= $this->color->getPdfColor('#555555');
        $footerOut .= $this->getTextCell(
            txt: 'Page ' . ($pid + 1),
            posx: $lm,
            posy: $footerLineY,
            width: $tw,
            height: self::FOOTER_H,
            offset: 0,
            linespace: 0,
            valign: \Com\Tecnick\Pdf\TextVAlign::Center,
            halign: \Com\Tecnick\Pdf\TextHAlign::Center,
        );
        $footerOut .= $this->graph->getStopTransform();

        $out .= $this->beginArtifact('Pagination', 'Footer');
        $out .= $footerOut;
        $out .= $this->endArtifact();

        return $out;
    }
}

// ----------

// main PDF object using the custom subclass
$pdf = new PdfWithHeaderFooter(
    'mm', // string $unit = 'mm',
    true, // bool $isunicode = true,
    false, // bool $subsetfont = false,
    true, // bool $compress = true,
    'pdfua1', // string $mode = 'pdfua1',
    null, // ?ObjEncrypt $objEncrypt = null,
);

// ----------

$pdf->setCreator('tc-lib-pdf');
$pdf->setAuthor('Nicola Asuni');
$pdf->setSubject('tc-lib-pdf example: 005');
$pdf->setTitle('Header & Footer Example');
$pdf->setKeywords('TCPDF tc-lib-pdf example header footer');
$pdf->setPDFFilename('005_header_footer.pdf');

$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
$pdf->setLanguageArray(['a_meta_language' => 'en-US']);

// Set the text that will appear in the header on every page.
$pdf->setHeaderText('My Document Title', \date('Y-m-d'));

// Enable automatic header/footer: calls defaultPageContent() for every new page.
$pdf->enableDefaultPageContent();

// ----------
// Insert fonts

$bfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 11);
$bfontB = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 13);

// ----------
// Add first page

$page01 = $pdf->addPage();
$pdf->setBookmark(name: 'Page 1', link: '', level: 0, page: -1, posx: 0, posy: 0, fstyle: 'B', color: 'blue');

// Page content starts below the header band (HF_MARGIN + HEADER_H + separator ≈ 25 mm).
$contentY = 28.0;

$pdf->page->addContent($bfontB['out']);

$title1 = $pdf->getTextCell(
    txt: 'Page 1 — Custom Repeating Header & Footer',
    posx: 10,
    posy: $contentY,
    width: 190,
    height: 0,
    offset: 0,
    linespace: 0,
    valign: \Com\Tecnick\Pdf\TextVAlign::Top,
    halign: \Com\Tecnick\Pdf\TextHAlign::Left,
);
$pdf->page->addContent($title1);

$pdf->page->addContent($bfont['out']);

$body1 = 'This is the first page of a document that demonstrates how to add a custom page header and footer that automatically repeats on every new page using tc-lib-pdf.

The header displays the document title (left) and the date (right), separated from the page content by a thin horizontal rule. The footer shows the page number centred at the bottom, also separated by a horizontal rule.

This is achieved by subclassing \Com\Tecnick\Pdf\Tcpdf and overriding the public defaultPageContent() method, then activating the mechanism once with enableDefaultPageContent(true) before adding any pages.

Because setPageContext() calls defaultPageContent() automatically every time addPage() is used, the header and footer appear on every page without any additional code in the page-building section.';

$txt1 = $pdf->getTextCell(
    txt: $body1,
    posx: 10,
    posy: $contentY + 10,
    width: 190,
    height: 0,
    offset: 15,
    linespace: 2,
    valign: \Com\Tecnick\Pdf\TextVAlign::Top,
    halign: \Com\Tecnick\Pdf\TextHAlign::Justify,
);
$pdf->page->addContent($txt1);

// ----------
// Add second page

$page02 = $pdf->addPage();
$pdf->setBookmark(name: 'Page 2', link: '', level: 0, page: -1, posx: 0, posy: 0, fstyle: 'B', color: 'green');

$pdf->page->addContent($bfontB['out']);

$title2 = $pdf->getTextCell(
    txt: 'Page 2 — Continued Content',
    posx: 10,
    posy: $contentY,
    width: 190,
    height: 0,
    offset: 0,
    linespace: 0,
    valign: \Com\Tecnick\Pdf\TextVAlign::Top,
    halign: \Com\Tecnick\Pdf\TextHAlign::Left,
);
$pdf->page->addContent($title2);

$pdf->page->addContent($bfont['out']);

$body2 = 'This is the second page. The header and footer are present here too without any manual intervention — the overridden defaultPageContent() method takes care of them automatically.

Any further pages added with addPage() would also receive the same header and footer, making the approach suitable for multi-page reports, invoices, or any document type that requires consistent page decoration.';

$txt2 = $pdf->getTextCell(
    txt: $body2,
    posx: 10,
    posy: $contentY + 10,
    width: 190,
    height: 0,
    offset: 15,
    linespace: 2,
    valign: \Com\Tecnick\Pdf\TextVAlign::Top,
    halign: \Com\Tecnick\Pdf\TextHAlign::Justify,
);
$pdf->page->addContent($txt2);

// ----------
// Output the PDF

$rawpdf = $pdf->getOutPDFString();

$pdf->renderPDF(rawpdf: $rawpdf);
