//--------------------------------------------------------------------------------------------------
// Copyright (c) id3 Technologies
// All Rights Reserved.
//--------------------------------------------------------------------------------------------------
#pragma once
#include <id3BiosealCppWrapper/id3BiosealException.hpp>
#include <id3BiosealCppWrapper/id3BiosealDateTime.hpp>
#include <id3BiosealCppWrapper/id3BiosealStringArray.hpp>
#include <id3BiosealCppWrapper/id3BiosealCertificateExtensionList.hpp>
#include <id3Bioseal/id3BiosealCertificateInformation.h>
#include "vector"

namespace id3BiosealCppWrapper
{

/**
 * Represents the information about a certificate.
 */
class CertificateInformation
{
private:
    ID3_BIOSEAL_CERTIFICATE_INFORMATION handle_{};

public:
    CertificateInformation() {
        check_error(id3BiosealCertificateInformation_Initialize(&handle_));
    }

    virtual ~CertificateInformation() {
        if (handle_) {
            id3BiosealCertificateInformation_Dispose(&handle_);
        }
    }


    CertificateInformation(CertificateInformation &&src) noexcept: handle_(src.handle_) {
        src.handle_ = nullptr;
    }

    ID3_BIOSEAL_CERTIFICATE_INFORMATION getHandle() const { return handle_; }
    operator ID3_BIOSEAL_CERTIFICATE_INFORMATION () const { return handle_; }

    // public getters and setters
    /**
    * Gets the the common name (CN) of the certificate issuer.
    * @param issuerCommonName [out] The common name (CN) of the certificate issuer.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The common name (CN) of the certificate issuer.
    */
    void getIssuerCommonName(std::string & issuerCommonName) {
        int issuerCommonNameSize = -1;
        auto err = id3BiosealCertificateInformation_GetIssuerCommonName(handle_, issuerCommonName.data(), &issuerCommonNameSize);
        if (err == (int)id3BiosealError_InsufficientBuffer) {
            issuerCommonName.resize(issuerCommonNameSize);
            err = id3BiosealCertificateInformation_GetIssuerCommonName(handle_, issuerCommonName.data(), &issuerCommonNameSize);
            if (err == 0) { issuerCommonName.resize(issuerCommonNameSize); }
        }
        check_error(err);
    }

    /**
    * Gets the the common name (CN) of the certificate issuer.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The common name (CN) of the certificate issuer.
    */
    std::string getIssuerCommonName() {
        std::string issuer_common_name;
        getIssuerCommonName(issuer_common_name);
        return issuer_common_name;
    }

    /**
    * Gets the the organization (O) of the certificate issuer.
    * @param issuerOrganization [out] The organization (O) of the certificate issuer.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The organization (O) of the certificate issuer.
    */
    void getIssuerOrganization(std::string & issuerOrganization) {
        int issuerOrganizationSize = -1;
        auto err = id3BiosealCertificateInformation_GetIssuerOrganization(handle_, issuerOrganization.data(), &issuerOrganizationSize);
        if (err == (int)id3BiosealError_InsufficientBuffer) {
            issuerOrganization.resize(issuerOrganizationSize);
            err = id3BiosealCertificateInformation_GetIssuerOrganization(handle_, issuerOrganization.data(), &issuerOrganizationSize);
            if (err == 0) { issuerOrganization.resize(issuerOrganizationSize); }
        }
        check_error(err);
    }

    /**
    * Gets the the organization (O) of the certificate issuer.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The organization (O) of the certificate issuer.
    */
    std::string getIssuerOrganization() {
        std::string issuer_organization;
        getIssuerOrganization(issuer_organization);
        return issuer_organization;
    }

    /**
    * Gets the the country (C) of the certificate issuer.
    * @param issuerCountry [out] The country (C) of the certificate issuer.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The country (C) of the certificate issuer.
    */
    void getIssuerCountry(std::string & issuerCountry) {
        int issuerCountrySize = -1;
        auto err = id3BiosealCertificateInformation_GetIssuerCountry(handle_, issuerCountry.data(), &issuerCountrySize);
        if (err == (int)id3BiosealError_InsufficientBuffer) {
            issuerCountry.resize(issuerCountrySize);
            err = id3BiosealCertificateInformation_GetIssuerCountry(handle_, issuerCountry.data(), &issuerCountrySize);
            if (err == 0) { issuerCountry.resize(issuerCountrySize); }
        }
        check_error(err);
    }

    /**
    * Gets the the country (C) of the certificate issuer.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The country (C) of the certificate issuer.
    */
    std::string getIssuerCountry() {
        std::string issuer_country;
        getIssuerCountry(issuer_country);
        return issuer_country;
    }

    /**
    * Gets the the organizational unit (OU) of the certificate issuer.
    * @param issuerOrganizationalUnit [out] The organizational unit (OU) of the certificate issuer.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The organizational unit (OU) of the certificate issuer.
    */
    void getIssuerOrganizationalUnit(std::string & issuerOrganizationalUnit) {
        int issuerOrganizationalUnitSize = -1;
        auto err = id3BiosealCertificateInformation_GetIssuerOrganizationalUnit(handle_, issuerOrganizationalUnit.data(), &issuerOrganizationalUnitSize);
        if (err == (int)id3BiosealError_InsufficientBuffer) {
            issuerOrganizationalUnit.resize(issuerOrganizationalUnitSize);
            err = id3BiosealCertificateInformation_GetIssuerOrganizationalUnit(handle_, issuerOrganizationalUnit.data(), &issuerOrganizationalUnitSize);
            if (err == 0) { issuerOrganizationalUnit.resize(issuerOrganizationalUnitSize); }
        }
        check_error(err);
    }

    /**
    * Gets the the organizational unit (OU) of the certificate issuer.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The organizational unit (OU) of the certificate issuer.
    */
    std::string getIssuerOrganizationalUnit() {
        std::string issuer_organizational_unit;
        getIssuerOrganizationalUnit(issuer_organizational_unit);
        return issuer_organizational_unit;
    }

    /**
    * Gets the the distinguished name (DN) of the certificate issuer.
    * @param issuerDistinguishedName [out] The distinguished name (DN) of the certificate issuer.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The distinguished name (DN) of the certificate issuer.
    */
    void getIssuerDistinguishedName(std::string & issuerDistinguishedName) {
        int issuerDistinguishedNameSize = -1;
        auto err = id3BiosealCertificateInformation_GetIssuerDistinguishedName(handle_, issuerDistinguishedName.data(), &issuerDistinguishedNameSize);
        if (err == (int)id3BiosealError_InsufficientBuffer) {
            issuerDistinguishedName.resize(issuerDistinguishedNameSize);
            err = id3BiosealCertificateInformation_GetIssuerDistinguishedName(handle_, issuerDistinguishedName.data(), &issuerDistinguishedNameSize);
            if (err == 0) { issuerDistinguishedName.resize(issuerDistinguishedNameSize); }
        }
        check_error(err);
    }

    /**
    * Gets the the distinguished name (DN) of the certificate issuer.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The distinguished name (DN) of the certificate issuer.
    */
    std::string getIssuerDistinguishedName() {
        std::string issuer_distinguished_name;
        getIssuerDistinguishedName(issuer_distinguished_name);
        return issuer_distinguished_name;
    }

    /**
    * Gets the the subject common name (CN) from the certificate.
    * @param subjectCommonName [out] The subject common name (CN) from the certificate.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The subject common name (CN) from the certificate.
    */
    void getSubjectCommonName(std::string & subjectCommonName) {
        int subjectCommonNameSize = -1;
        auto err = id3BiosealCertificateInformation_GetSubjectCommonName(handle_, subjectCommonName.data(), &subjectCommonNameSize);
        if (err == (int)id3BiosealError_InsufficientBuffer) {
            subjectCommonName.resize(subjectCommonNameSize);
            err = id3BiosealCertificateInformation_GetSubjectCommonName(handle_, subjectCommonName.data(), &subjectCommonNameSize);
            if (err == 0) { subjectCommonName.resize(subjectCommonNameSize); }
        }
        check_error(err);
    }

    /**
    * Gets the the subject common name (CN) from the certificate.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The subject common name (CN) from the certificate.
    */
    std::string getSubjectCommonName() {
        std::string subject_common_name;
        getSubjectCommonName(subject_common_name);
        return subject_common_name;
    }

    /**
    * Gets the the organization (O) of the certificate subject.
    * @param subjectOrganization [out] The organization (O) of the certificate subject.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The organization (O) of the certificate subject.
    */
    void getSubjectOrganization(std::string & subjectOrganization) {
        int subjectOrganizationSize = -1;
        auto err = id3BiosealCertificateInformation_GetSubjectOrganization(handle_, subjectOrganization.data(), &subjectOrganizationSize);
        if (err == (int)id3BiosealError_InsufficientBuffer) {
            subjectOrganization.resize(subjectOrganizationSize);
            err = id3BiosealCertificateInformation_GetSubjectOrganization(handle_, subjectOrganization.data(), &subjectOrganizationSize);
            if (err == 0) { subjectOrganization.resize(subjectOrganizationSize); }
        }
        check_error(err);
    }

    /**
    * Gets the the organization (O) of the certificate subject.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The organization (O) of the certificate subject.
    */
    std::string getSubjectOrganization() {
        std::string subject_organization;
        getSubjectOrganization(subject_organization);
        return subject_organization;
    }

    /**
    * Gets the the country (C) of the certificate subject.
    * @param subjectCountry [out] The country (C) of the certificate subject.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The country (C) of the certificate subject.
    */
    void getSubjectCountry(std::string & subjectCountry) {
        int subjectCountrySize = -1;
        auto err = id3BiosealCertificateInformation_GetSubjectCountry(handle_, subjectCountry.data(), &subjectCountrySize);
        if (err == (int)id3BiosealError_InsufficientBuffer) {
            subjectCountry.resize(subjectCountrySize);
            err = id3BiosealCertificateInformation_GetSubjectCountry(handle_, subjectCountry.data(), &subjectCountrySize);
            if (err == 0) { subjectCountry.resize(subjectCountrySize); }
        }
        check_error(err);
    }

    /**
    * Gets the the country (C) of the certificate subject.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The country (C) of the certificate subject.
    */
    std::string getSubjectCountry() {
        std::string subject_country;
        getSubjectCountry(subject_country);
        return subject_country;
    }

    /**
    * Gets the the organizational unit (OU) of the certificate subject.
    * @param subjectOrganizationalUnit [out] The organizational unit (OU) of the certificate subject.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The organizational unit (OU) of the certificate subject.
    */
    void getSubjectOrganizationalUnit(std::string & subjectOrganizationalUnit) {
        int subjectOrganizationalUnitSize = -1;
        auto err = id3BiosealCertificateInformation_GetSubjectOrganizationalUnit(handle_, subjectOrganizationalUnit.data(), &subjectOrganizationalUnitSize);
        if (err == (int)id3BiosealError_InsufficientBuffer) {
            subjectOrganizationalUnit.resize(subjectOrganizationalUnitSize);
            err = id3BiosealCertificateInformation_GetSubjectOrganizationalUnit(handle_, subjectOrganizationalUnit.data(), &subjectOrganizationalUnitSize);
            if (err == 0) { subjectOrganizationalUnit.resize(subjectOrganizationalUnitSize); }
        }
        check_error(err);
    }

    /**
    * Gets the the organizational unit (OU) of the certificate subject.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The organizational unit (OU) of the certificate subject.
    */
    std::string getSubjectOrganizationalUnit() {
        std::string subject_organizational_unit;
        getSubjectOrganizationalUnit(subject_organizational_unit);
        return subject_organizational_unit;
    }

    /**
    * Gets the the subject distinguished (DN) name of the certificate.
    * @param subjectDistinguishedName [out] The subject distinguished (DN) name of the certificate.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The subject distinguished (DN) name of the certificate.
    */
    void getSubjectDistinguishedName(std::string & subjectDistinguishedName) {
        int subjectDistinguishedNameSize = -1;
        auto err = id3BiosealCertificateInformation_GetSubjectDistinguishedName(handle_, subjectDistinguishedName.data(), &subjectDistinguishedNameSize);
        if (err == (int)id3BiosealError_InsufficientBuffer) {
            subjectDistinguishedName.resize(subjectDistinguishedNameSize);
            err = id3BiosealCertificateInformation_GetSubjectDistinguishedName(handle_, subjectDistinguishedName.data(), &subjectDistinguishedNameSize);
            if (err == 0) { subjectDistinguishedName.resize(subjectDistinguishedNameSize); }
        }
        check_error(err);
    }

    /**
    * Gets the the subject distinguished (DN) name of the certificate.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The subject distinguished (DN) name of the certificate.
    */
    std::string getSubjectDistinguishedName() {
        std::string subject_distinguished_name;
        getSubjectDistinguishedName(subject_distinguished_name);
        return subject_distinguished_name;
    }

    /**
    * Gets the the date in local time when a certificate becomes valid.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The date in local time when a certificate becomes valid.
    */
    DateTime getNotBefore() {
        DateTime not_before;
        check_error(id3BiosealCertificateInformation_GetNotBefore(handle_, not_before));
        return not_before;
    }

    /**
    * Gets the the date in local time after which a certificate is no longer valid.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The date in local time after which a certificate is no longer valid.
    */
    DateTime getNotAfter() {
        DateTime not_after;
        check_error(id3BiosealCertificateInformation_GetNotAfter(handle_, not_after));
        return not_after;
    }

    /**
    * Gets the the serial number of the certificate.
    * @param serialNumber [out] The serial number of the certificate.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The serial number of the certificate.
    */
    void getSerialNumber(std::vector<unsigned char> & serialNumber) {
        int serialNumberSize = -1;
        auto err = id3BiosealCertificateInformation_GetSerialNumber(handle_, serialNumber.data(), &serialNumberSize);
        if (err == (int)id3BiosealError_InsufficientBuffer) {
            serialNumber.resize(serialNumberSize);
            err = id3BiosealCertificateInformation_GetSerialNumber(handle_, serialNumber.data(), &serialNumberSize);
        }
        check_error(err);
    }

    /**
    * Gets the the serial number of the certificate.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The serial number of the certificate.
    */
    std::vector<unsigned char> getSerialNumber() {
        std::vector<unsigned char> serial_number;
        getSerialNumber(serial_number);
        return serial_number;
    }

    /**
    * Gets the the serial number from the certificate as a string.
    * @param serialNumberString [out] The serial number from the certificate as a string.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The serial number from the certificate as a string.
    */
    void getSerialNumberString(std::string & serialNumberString) {
        int serialNumberStringSize = -1;
        auto err = id3BiosealCertificateInformation_GetSerialNumberString(handle_, serialNumberString.data(), &serialNumberStringSize);
        if (err == (int)id3BiosealError_InsufficientBuffer) {
            serialNumberString.resize(serialNumberStringSize);
            err = id3BiosealCertificateInformation_GetSerialNumberString(handle_, serialNumberString.data(), &serialNumberStringSize);
            if (err == 0) { serialNumberString.resize(serialNumberStringSize); }
        }
        check_error(err);
    }

    /**
    * Gets the the serial number from the certificate as a string.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The serial number from the certificate as a string.
    */
    std::string getSerialNumberString() {
        std::string serial_number_string;
        getSerialNumberString(serial_number_string);
        return serial_number_string;
    }

    /**
    * Gets the the certificate data.
    * @param data [out] The certificate data.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The certificate data.
    */
    void getData(std::vector<unsigned char> & data) {
        int dataSize = -1;
        auto err = id3BiosealCertificateInformation_GetData(handle_, data.data(), &dataSize);
        if (err == (int)id3BiosealError_InsufficientBuffer) {
            data.resize(dataSize);
            err = id3BiosealCertificateInformation_GetData(handle_, data.data(), &dataSize);
        }
        check_error(err);
    }

    /**
    * Gets the the certificate data.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The certificate data.
    */
    std::vector<unsigned char> getData() {
        std::vector<unsigned char> data;
        getData(data);
        return data;
    }

    /**
    * Gets the the OID of the certificate's signing algorithm.
    * @param signatureAlgorithm [out] The OID of the certificate's signing algorithm.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The OID of the certificate's signing algorithm.
    */
    void getSignatureAlgorithm(std::string & signatureAlgorithm) {
        int signatureAlgorithmSize = -1;
        auto err = id3BiosealCertificateInformation_GetSignatureAlgorithm(handle_, signatureAlgorithm.data(), &signatureAlgorithmSize);
        if (err == (int)id3BiosealError_InsufficientBuffer) {
            signatureAlgorithm.resize(signatureAlgorithmSize);
            err = id3BiosealCertificateInformation_GetSignatureAlgorithm(handle_, signatureAlgorithm.data(), &signatureAlgorithmSize);
            if (err == 0) { signatureAlgorithm.resize(signatureAlgorithmSize); }
        }
        check_error(err);
    }

    /**
    * Gets the the OID of the certificate's signing algorithm.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The OID of the certificate's signing algorithm.
    */
    std::string getSignatureAlgorithm() {
        std::string signature_algorithm;
        getSignatureAlgorithm(signature_algorithm);
        return signature_algorithm;
    }

    /**
    * Gets the the certificate version.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The certificate version.
    */
    int getVersion() {
        int version;
        check_error(id3BiosealCertificateInformation_GetVersion(handle_, &version));
        return version;
    }

    /**
    * Gets the the certificate public key.
    * @param publicKey [out] The certificate public key.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The certificate public key.
    */
    void getPublicKey(std::vector<unsigned char> & publicKey) {
        int publicKeySize = -1;
        auto err = id3BiosealCertificateInformation_GetPublicKey(handle_, publicKey.data(), &publicKeySize);
        if (err == (int)id3BiosealError_InsufficientBuffer) {
            publicKey.resize(publicKeySize);
            err = id3BiosealCertificateInformation_GetPublicKey(handle_, publicKey.data(), &publicKeySize);
        }
        check_error(err);
    }

    /**
    * Gets the the certificate public key.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The certificate public key.
    */
    std::vector<unsigned char> getPublicKey() {
        std::vector<unsigned char> public_key;
        getPublicKey(public_key);
        return public_key;
    }

    /**
    * Gets the the certificate key usage list.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The certificate key usage list.
    */
    StringArray getKeyUsage() {
        StringArray key_usage;
        check_error(id3BiosealCertificateInformation_GetKeyUsage(handle_, key_usage));
        return key_usage;
    }

    /**
    * Gets the the certificate policies.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The certificate policies.
    */
    StringArray getPolicies() {
        StringArray policies;
        check_error(id3BiosealCertificateInformation_GetPolicies(handle_, policies));
        return policies;
    }

    /**
    * Gets the the certificate extension list.
    * @exception BiosealException An error has occured during Bioseal library execution.
    * @retval The certificate extension list.
    */
    CertificateExtensionList getCertificateExtensionList() {
        CertificateExtensionList certificate_extension_list;
        check_error(id3BiosealCertificateInformation_GetCertificateExtensionList(handle_, certificate_extension_list));
        return certificate_extension_list;
    }

    // public methods
};
};