<?php declare(strict_types=1);

require_once __DIR__ . '/QrbMultiLanguageText.php';
require_once __DIR__ . '/QrbPdfDataEntry.php';
require_once __DIR__ . '/QrbPdfPosition.php';
require_once __DIR__ . '/QrbPdfTextAttribute.php';
require_once __DIR__ . '/../common/QrbException.php';

// Holds the QR bills PDF data.
final class QrbPdfData
{
    // key constants
    public const KEY_PDF_DATA = "PdfData";
    
    private array                $entries = [];      // array of QrbPdfDataEntry
    private QrbMultiLanguageText $template;
    
    // Validates PDF data in the given associative array.
    //
    // Checks:
    // - The surrounding key must be "PdfData".
    // - There must be a key with name "default" inside the surrounding key.
    // - Other checks done by QrbPdfDataEntry::validate(), see there.
    public static function validate(array $pdfData, array $additionalLanguages)
    {
        if (! array_key_exists(self::KEY_PDF_DATA, $pdfData))
            throw new QrbException(
                static::class . " - surrounding key 'PdfData' of PDF data does not exist",
                "exception.pdfData.surroundingKeyDoesNotExist");

        $pdfDataContents = $pdfData[self::KEY_PDF_DATA];

        if (empty($pdfDataContents))
        {
            return;    // nothing to check
        }

        $defaultKeyFound = false;

        foreach ( $pdfDataContents as $entry )
        {
            QrbPdfDataEntry::validate($entry, $additionalLanguages, self::KEY_PDF_DATA);
        
            if ($entry[QrbPdfDataEntry::KEY_NAME] === QrbPdfDataEntry::KEY_NAME_DEFAULT)
            {    
                $defaultKeyFound = true;
            }
        }
        
        if (! $defaultKeyFound)
            throw new QrbException(
                static::class . " - no entry with name 'default'",
                "exception.pdfData.defaultEntryDoesNotExist");
    }

    // Creates a PDF data instance from the given template and associative array.
    //
    // Checks:
    // - Checks if pdfTemplate is non-NULL
    // - Other checks done by validate().
    //
    // The array pdfData inside of the surrounding key "PdfData" contains entries that are 
    // parsed by QrbPdfDataEntry. 
    public function __construct(?QrbMultiLanguageText $pdfTemplate, 
                                array                 $pdfData, 
                                array                 $supportedLanguages,
                                array                 $additionalLanguages)
    {
        if (! $pdfTemplate)
        {
            throw new QrbException(
                static::class . " - PDF template does not exist.",
                "exception.pdfData.pdfTemplateDoesNotExist");
        }

        $this->template = $pdfTemplate;

        foreach ($additionalLanguages as $language)
        {
            if (! $this->existsLocalizedTemplate($language))
                throw new QrbException(
                    static::class . " - PDF template does not exist for language {$language}.",
                    "exception.pdfData.pdfTemplateLangDoesNotExist",
                    "{$language}");
        }
        
        self::validate($pdfData, $additionalLanguages);
        $pdfDataContents = $pdfData[self::KEY_PDF_DATA];
        if (empty($pdfDataContents))    return;    // no data

        foreach ( $pdfDataContents as $entry )
        {
            $name = $entry[QrbPdfDataEntry::KEY_NAME];
            $pdEntry = new QrbPdfDataEntry($entry, $supportedLanguages, $additionalLanguages, $name);
            $this->entries[$pdEntry->getName()] = $pdEntry;
         }
    }
    
    // Checks whether localized data for the given language exists.
    // If some data is missing then the given missingKeys is updated.
    public function existsLocalizedData(string $language, array &$missingKeys) : void
    {
        if (! $this->existsLocalizedTemplate($language))
        {
            $missingKeys["PdfTemplate_" . $language . ".pdf"] = true;
        }

        if (empty($this->entries))
        {
            return;
        }

        foreach ($this->entries as $entry)
        {
            if ( ! $entry->getMlText() )
            {
                continue;
            }
            
            if ( ! $entry->getMlText()->existsLocalizedText($language) )
            {
                $missingKeys[self::KEY_PDF_DATA . ".json"][$entry->getName()] = true;
            }
        }
    }

    // checks whether the template supports the given language
    private function existsLocalizedTemplate(string $language) : bool
    {
        return $this->template->existsLocalizedText($language);
    }
    
    // returns the template in the given language (or the default language)
    public function getTemplate($language) : string
    {
        return $this->template->getText($language);
    }
    
    // Returns the PDF data entries (QrbPdfDataEntry).
    public function getPdfDataEntries() : array // of QrbPdfDataEntry
    {
        return $this->entries;
    }

    // Returns the position of the text of the entry with the given key.    
    // If the key is not set then this method returns NULL.
    public function getPosition(string $key) : ?QrbPdfPosition
    {
        if (empty($this->entries))                       return NULL;
        if (! array_key_exists($key, $this->entries))    return NULL;
        
        return $this->entries[$key]->getPosition();
    }

    // Returns the text attribute of the text of the entry with the given key.    
    // If the optional text attribute is not set then this method returns the default text attribute.
    public function getTextAttribute(string $key) : ?QrbPdfTextAttribute
    {
        $textAttribute = NULL;
        
        if  (  (! empty($this->entries))
            && (array_key_exists($key, $this->entries)) 
            )
            $textAttribute = $this->entries[$key]->getTextAttribute();
        
        if (!$textAttribute)
            $textAttribute = $this->entries[QrbPdfDataEntry::KEY_NAME_DEFAULT]->getTextAttribute();;
        
        return $textAttribute;
    }

    // Checks whether the text of the entry with the given key supports the given language.
    // If the entry or the text is not present then this method returns true.
    private function existsLocalizedText(string $key, string $language) : bool
    {
        if (empty($this->entries))                      return true;
        if (! array_key_exists($key, $this->entries))   return true;
        if (! $this->entries[$key]->getMlText())        return true;
    
        return $this->entries[$key]->getMlText()->existsLocalizedText($language);
    }
    
    // Returns the text of the entry with the given key in the given language.
    // If the optional text is not set then this method returns NULL.
    public function getText(string $key, string $language) : ?string
    {
        if (empty($this->entries))                      return NULL;
        if (! array_key_exists($key, $this->entries))   return NULL;
        if (! $this->entries[$key]->getMlText())        return NULL;
    
        return $this->entries[$key]->getMlText()->getText($language);
    }

    public function __toString()
    {
        // PDF is not so nice to print, so just print "available"
        $result = "\n\ttemplate = '" . ( $this->template ? "available" : "NULL" ) . "'";

        // entries are too much data, just print number of entries
//         result .= "\n\tentries:";
//         foreach ($this->entries as $entry)
//         {
//             $result .= $entry;
//             $result .= "\n----";
//         }
        $result .= "\n\tentries (count) = " . count($this->entries);
        
        return $result;
    }
}

?>
