#ifndef INCLUDED_BOBCAT_ISYMCRYPTBASE_
#define INCLUDED_BOBCAT_ISYMCRYPTBASE_

#include <memory>
#include <iosfwd>
#include <streambuf>
#include <bobcat/symcryptbase>

namespace FBB
{

namespace IUO   // the facilities defined here are not further documented
{               // elsewhere. The ISymCryptBase class defined below
                // should only be used by IISymCrypt.


class ISymCryptBase: private SymCryptBase, public std::streambuf
{
    std::unique_ptr<std::ifstream> d_ifStream;  // used by the 2nd constructor
    std::istream &d_inStream;                   // source stream to process

    size_t d_inBufSize;
    std::unique_ptr<char []> d_inBuf;   // buffer receiving chars from
                                        // d_instream

    int (*d_evpUpdate)(EVP_CIPHER_CTX *ctx,
                unsigned char *out, int *outl,
                unsigned char const *in, int inl);

    int (*d_evpFinal)(EVP_CIPHER_CTX *, unsigned char *out, int *outl);

    public:
        ISymCryptBase(
            std::istream &inStream,
            std::string const &cipherName,
            std::string const &key,
            std::string const &iv,
            size_t inBufSize,
            OSSL_PARAM const *params,

            int (*evpInit)(EVP_CIPHER_CTX *ctx, EVP_CIPHER const *type,
                unsigned char const *key, unsigned char const *iv,
                OSSL_PARAM const *params),

            int (*evpUpdate)(EVP_CIPHER_CTX *ctx, unsigned char *out,
                int *outl, unsigned char const *in, int inl),

            int (*evpFinal)(EVP_CIPHER_CTX *ctx, unsigned char *out,
                int *outl)
        );

        ISymCryptBase(
            std::string const &inStreamName,
            std::string const &cipherName,
            std::string const &key,
            std::string const &iv,
            size_t inBufSize,
            OSSL_PARAM const *params,

            int (*evpInit)(EVP_CIPHER_CTX *ctx, EVP_CIPHER const *type,
                unsigned char const *key, unsigned char const *iv,
                OSSL_PARAM const *params),

            int (*evpUpdate)(EVP_CIPHER_CTX *ctx, unsigned char *out,
                int *outl, unsigned char const *in, int inl),

            int (*evpFinal)(EVP_CIPHER_CTX *ctx, unsigned char *out,
                int *outl)
        );

        ~ISymCryptBase() override;

        using SymCryptBase::errorMsg;       // static members
        using SymCryptBase::ivLength;
        using SymCryptBase::keyLength;

    private:
        bool evpFinal();
        bool evpUpdate(size_t inBufRead);

        int underflow() override;
};

}   // IUO

}   // FBB

#endif
