// SPDX-FileCopyrightText: 2021 Francesco Pretto <ceztko@gmail.com>
// SPDX-License-Identifier: LGPL-2.0-or-later OR MPL-2.0

#ifndef PDF_METADATA
#define PDF_METADATA

#include "PdfInfo.h"
#include "PdfXMPPacket.h"

namespace PoDoFo
{
    class PdfMetadataStore;
    class PdfDocument;

    class PODOFO_API PdfMetadata final
    {
        friend class PdfDocument;
        friend class PdfCatalog;

    private:
        PdfMetadata(PdfDocument& doc);
        PdfMetadata(PdfMetadata&) = delete;

    public:
        ~PdfMetadata();

        /** Set the title of the document.
         * \param title title
         */
        void SetTitle(nullable<const PdfString&> title);

        /** Get the title of the document
         *  \returns the title
         */
        nullable<const PdfString&> GetTitle() const;

        /** Set the author of the document.
         * \param author author
         */
        void SetAuthor(nullable<const PdfString&> author);

        /** Get the author of the document
         *  \returns the author
         */
        nullable<const PdfString&> GetAuthor() const;

        /** Set the subject of the document.
         * \param subject subject
         */
        void SetSubject(nullable<const PdfString&> subject);

        /** Get the subject of the document
         *  \returns the subject
         */
        nullable<const PdfString&> GetSubject() const;

        /** Get the raw keywords of the document
         *  \returns the subject
         */
        nullable<const PdfString&> GetKeywordsRaw() const;

        /** Set keywords for this document
         * \param keywords a list of keywords
         */
        void SetKeywords(std::vector<std::string> keywords);

        /** Get the keywords of the document
         *  \returns the keywords
         */
        std::vector<std::string> GetKeywords() const;

        /** Set the creator of the document.
         * Typically the name of the application using the library.
         * \param creator creator
         */
        void SetCreator(nullable<const PdfString&> creator);

        /** Get the creator of the document
         *  \returns the creator
         */
        nullable<const PdfString&> GetCreator() const;

        /** Set the producer of the document.
         * \param producer producer
         */
        void SetProducer(nullable<const PdfString&> producer);

        /** Get the producer of the document
         *  \returns the producer
         */
        nullable<const PdfString&> GetProducer() const;

        /** Set the document creation date
         * \param date the creation date
         */
        void SetCreationDate(nullable<PdfDate> date);

        /** Get creation date of document
         *  \return creation date
         */
        nullable<const PdfDate&> GetCreationDate() const;

        /** Set the document modification date
         * \param date the modification date
         */
        void SetModifyDate(nullable<PdfDate> date);

        /** Get modification date of document
         *  \return modification date
         */
        nullable<const PdfDate&> GetModifyDate() const;

        /** Set the trapping state of the document.
         * \param trapped trapped
         */
        void SetTrapped(nullable<bool> trapped);

        /** Get the trapping state of the document
         */
        nullable<bool>GetTrapped() const;

        /** Set the PDF Version of the document. Has to be called before Write() to
         *  have an effect.
         *  \param version  version of the pdf document
         */
        void SetPdfVersion(PdfVersion version);

        PdfVersion GetPdfVersion() const;

        PdfALevel GetPdfALevel() const;

        /** Set the document PDF/A level
         * \param level the PDF/A level
         */
        void SetPdfALevel(PdfALevel level);

        PdfUALevel GetPdfUALevel() const;

        void SetPdfUALevel(PdfUALevel version);

        nullable<const PdfString&> GetProperty(PdfAdditionalMetadata prop) const;

        void SetProperty(PdfAdditionalMetadata prop, nullable<const PdfString&> value);

        /** Ensure the XMP metadata is created
         * Also, ensure some /Info metadata is normalized
         * so it will be compatible with the correspondent XMP
         * \param resetXMPPacket true if the XMP packet should be reset unconditionally.
         *      This will loose custom entities
         */
        void SyncXMPMetadata(bool resetXMPPacket = false);

        /** Try to sync an XMP packet, if present
         * \returns true if the XMP packet was present and synced
         */
        bool TrySyncXMPMetadata();

        /** Take the XMP packet, if available, and invalidate the data
         */
        std::unique_ptr<PdfXMPPacket> TakeXMPPacket();

    private:
        void Invalidate();

    private:
        PdfMetadata& operator=(PdfMetadata&) = delete;

        void setKeywords(nullable<const PdfString&> keywords);
        void ensureInitialized();
        void syncXMPMetadata(bool resetXMPPacket);
        void invalidate();

    private:
        PdfDocument* m_doc;
        PdfMetadataStore* m_metadata;
        bool m_xmpSynced;
        std::unique_ptr<PdfXMPPacket> m_packet;
    };
}

#endif // PDF_METADATA
