<?php declare(strict_types=1);

use \setasign\Fpdi\Fpdi as FPDI;

require_once __DIR__ . '/../data/QrbPdfData.php';
require_once __DIR__ . '/../data/QrbPdfDataEntry.php';
require_once __DIR__ . '/../data/QrbPdfTextAttribute.php';
require_once __DIR__ . '/../data/QrbPdfPosition.php';
require_once __DIR__ . '/../data/QrbRecipient.php';

// Customizes the PDF using the given $pdfData.
final class QrbPdfCustomizer
{
    private QrbPdfData $qrbPdfData;
    
    public function __construct(QrbPdfData $qrbPdfData)
    {
        $this->qrbPdfData = $qrbPdfData;
    }

    //
    // If you can't use the provided mechanism to fill the PDF with your data, you may 
    // change this method to customize the PDF as you wish.
    //
    // fpdi:     created PDF (with optional QR bill payment slip)
    // pageNo:   current page in PDF that is processed
    public function process(\setasign\Fpdi\Fpdi $fpdi, 
                            int                 $pageNo,
                            QrbRecipient     $recipient,
                            string              $language,
                            string              $currency,
                            ?float              $amount = NULL) : void
    {
        $defaultTextAttribute = $this->qrbPdfData->getTextAttribute(QrbPdfDataEntry::KEY_NAME_DEFAULT);
    
        foreach ($this->qrbPdfData->getPdfDataEntries() as $entry)
        {
            switch ($entry->getName())
            {
            case "address": 
                $addressPosition = $entry->getPosition();
                if ($addressPosition && ($addressPosition->getPage() == $pageNo))
                    // address position is set AND is on current page
                {
                    $addressTextAttribute = $this->createTextAttribute($entry->getTextAttribute(), $defaultTextAttribute);
                    $this->setTextAttributesAndPosXY($fpdi, $addressTextAttribute, $addressPosition);
                    $fpdi->Write($addressTextAttribute->getLineHeight(), 
                                 $this->toIso8859_1(self::buildSalutationForAddress($recipient)));
                    $fpdi->SetXY($addressPosition->getPosX(), 
                                 $fpdi->GetY() + $addressTextAttribute->getLineHeight());
                    $fpdi->Write($addressTextAttribute->getLineHeight(), 
                                 $this->toIso8859_1("{$recipient->getFirstName()} {$recipient->getLastName()}"));
                    $fpdi->SetXY($addressPosition->getPosX(), 
                                 $fpdi->GetY() + $addressTextAttribute->getLineHeight());
                    $fpdi->Write($addressTextAttribute->getLineHeight(), 
                                 $this->toIso8859_1("{$recipient->getStreet()} {$recipient->getBuildingNo()}"));
                    $fpdi->SetXY($addressPosition->getPosX(), 
                                 $fpdi->GetY() + $addressTextAttribute->getLineHeight());
                    $fpdi->Write($addressTextAttribute->getLineHeight(), 
                                 $this->toIso8859_1("{$recipient->getPostalCode()} {$recipient->getCity()}"));
                }
            break;
            
            case "amount":
                $amountPosition = $entry->getPosition();
                if ($amountPosition && ($amountPosition->getPage() == $pageNo) && $amount)
                    // amount position is set AND is on current page AND there is an amount
                {
                    $amountTextAttribute = $this->createTextAttribute($entry->getTextAttribute(), $defaultTextAttribute);
                    $this->setTextAttributesAndPosXY($fpdi, $amountTextAttribute, $amountPosition);
                    $formattedAmount = number_format($amount, 2, '.', '');
                    $fpdi->Write($amountTextAttribute->getLineHeight(), 
                                 $this->toIso8859_1("{$currency} {$formattedAmount}"));
                }
            break;
            
            case "greeting":
                $greetingPosition = $entry->getPosition();
                if ($greetingPosition && ($greetingPosition->getPage() == $pageNo) && ($recipient->getGreeting() != ""))
                    // position is set AND is on current page AND there is a greeting
                {
                    $greetingTextAttribute = $this->createTextAttribute($entry->getTextAttribute(), $defaultTextAttribute);
                    $this->setTextAttributesAndPosXY($fpdi, $greetingTextAttribute, $greetingPosition);
                    $fpdi->Write($greetingTextAttribute->getLineHeight(), 
                                 $this->toIso8859_1($recipient->getGreeting()));
                }
            break;
            
            default:
                $position = $entry->getPosition();
                $mlText   = $entry->getMlText();
                if ($position && ($position->getPage() == $pageNo) && $mlText)
                    // position is set AND is on current page AND text is set
                {
                    $textAttribute = $this->createTextAttribute($entry->getTextAttribute(), $defaultTextAttribute);
                    $this->setTextAttributesAndPosXY($fpdi, $textAttribute, $position);
                    $fpdi->Write($textAttribute->getLineHeight(), 
                                 $this->toIso8859_1($mlText->getText($language)));
                }
            break;
            }
        }
    }
    
    // Builds the salutation for the PDF address (uses company if company is not empty).
    // 
    // recipient: holds company and salutation
    //
    // Returns the salutation.
    //
    // Public for unit test
    public static function buildSalutationForAddress(QrbRecipient $recipient) : string
    {
        return ($recipient->getCompany() != "") ? $recipient->getCompany()
                                                : $recipient->getSalutation();
    }
    
    private function createTextAttribute(?QrbPdfTextAttribute $textAttribute, 
                                          QrbPdfTextAttribute $defaultTextAttribute) : QrbPdfTextAttribute
    {
        return $textAttribute ? $textAttribute : $defaultTextAttribute;
    }
    
    private function setTextAttributesAndPosXY(\setasign\Fpdi\Fpdi    $fpdi, 
                                               QrbPdfTextAttribute $textAttribute,
                                               QrbPdfPosition      $position) : void
    {
        $fpdi->SetTextColor($textAttribute->getTextColor());                                    
        $fpdi->SetFont($textAttribute->getFontFamily(), 
                       $textAttribute->getFontStyle(), 
                       $textAttribute->getFontSize());
        $fpdi->SetXY($position->getPosX(), 
                     $position->getPosY());
    }
    
    private function toIso8859_1(string $input) : string
    {
        return mb_convert_encoding($input, 'ISO-8859-1', mb_detect_encoding($input));
    }
}

?>
