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

#ifndef PDF_SIGNER_H
#define PDF_SIGNER_H

#include "PdfDeclarations.h"

#include "PdfMemDocument.h"
#include "PdfSignature.h"

namespace PoDoFo
{
    class StreamDevice;

    class PODOFO_API PdfSigner
    {
    public:
        PdfSigner();
        virtual ~PdfSigner();

        /// Prepare the signer for being used/re-used
        /// Called before computing the signature with ComputeSignature(buffer, false)
        /// @remarks It's not meant to clear parameters that have been set
        ///      on this signer
        virtual void Reset() = 0;

        /// Called incrementally with document raw data to compute
        /// the signature with
        /// @param data incremental raw data
        virtual void AppendData(const bufferview& data) = 0;

        /// Called to compute the signature
        /// @param contents the buffer that will hold the signature /Contents
        /// @param dryrun if true the buffer is not required to
        ///   hold the signature, the call is just performed to
        ///   infer the signature size
        /// @remarks it must support working without prior calls to AppendData()
        virtual void ComputeSignature(charbuff& contents, bool dryrun) = 0;

        /// Retrieve the intermediate result of a signature computation,
        /// most probably a hash to sign. Called on deferred (aka "async")
        /// signature computation
        /// @param result the buffer that will hold the intermediate result
        /// @remarks by default it throws with PdfErrorCode::NotImplemented
        virtual void FetchIntermediateResult(charbuff& result);

        /// Called when computing the signature in deferred (aka "async") mode
        /// @param processedResult the processed intermediate result, for example a signed hash
        /// @param contents the buffer that will hold the signature /Contents
        /// @param dryrun if true the buffer is not required to
        ///   hold the signature, the call is just performed to
        ///   infer the signature size
        /// @remarks by default it throws with PdfErrorCode::NotImplemented
        /// @remarks it must support working without prior calls to AppendData() and/or FetchIntermediateResult()
        virtual void ComputeSignatureDeferred(const bufferview& processedResult, charbuff& contents, bool dryrun);

        /// Determines if the buffer should not be cleared amid
        /// ComputeSignature(contents, dryrun) calls. The default is false
        virtual bool SkipBufferClear() const;

        /// Should return the signature /Filter, for example "Adobe.PPKLite"
        virtual std::string GetSignatureFilter() const;

        /// Should return the signature /SubFilter, for example "ETSI.CAdES.detached"
        virtual std::string GetSignatureSubFilter() const = 0;

        /// Should return the signature /Type. It can be "Sig" or "DocTimeStamp"
        virtual std::string GetSignatureType() const = 0;

        /// Return the number of signer identities, if the signer supports multiple
        /// @remarks by default it returns 1
        virtual unsigned GetSignerIdentityCount() const;

        /// Unpack intermediate results, if the signer supports multiple signer identities
        /// @remarks by default we just do a simple copy of the input to the output
        virtual void UnpackIntermediateResult(const bufferview& processedResult, unsigned signerIdx, charbuff& result);

        /// Assemble processed results handling multiple signer identities (if the signer supports it)
        /// @remarks by default we just do a simple copy of the input to the output
        virtual void AssembleProcessedResult(const bufferview& processedResult, unsigned signerIdx, charbuff& result);

    private:
        PdfSigner(const PdfSigner&) = delete;
        PdfSigner& operator=(const PdfSigner&) = delete;
    };

    /// Sign the document on the given signature field
    /// @param doc the document to be signed
    /// @param device the input/output device where the document will be saved
    /// @param signer the signer implementation that will compute the signature
    /// @param signature the signature field where the signature will be applied
    /// @param saveOptions document saving options
    PODOFO_API void SignDocument(PdfMemDocument& doc, StreamDevice& device, PdfSigner& signer,
        PdfSignature& signature, PdfSaveOptions saveOptions = PdfSaveOptions::None);
}

#endif // PDF_SIGNER_H
