#ifndef CMS_SIGNER_H_INCLUDED
#define CMS_SIGNER_H_INCLUDED

#include "cms/isigner.h"
#include "common.h"
#include "./signer_id.h"

#include "wrapper/cms/sign_params.h"
#include "../pki/tsp.h"
#include "../pki/ocsp.h"

// content-time-stamp;
#define szOID_TIMESTAMP_CONTENT "1.2.840.113549.1.9.16.2.20"
// aa-timeStampToken
#define szOID_TIMESTAMP_SIGNATURE "1.2.840.113549.1.9.16.2.14"
// aa-ets-escTimeStamp
#define szOID_TIMESTAMP_ESC "1.2.840.113549.1.9.16.2.25"
// id-aa-ets-archiveTimestampV2
#define szOID_TIMESTAMP_ARCHIVE_V2 "1.2.840.113549.1.9.16.2.48"
// archiveTimestampV3 attribute
#define szOID_TIMESTAMP_ARCHIVE_V3 "0.4.0.1733.2.4"
// aa-ets-certificateRefs
#define szOID_CERTIFICATES_REFS "1.2.840.113549.1.9.16.2.21"
// aa-ets-revocationRefs
#define szOID_REVOCATION_REFS "1.2.840.113549.1.9.16.2.22"

class ExtVfyInfo : public IExtVfyInfo
{
public:
    ExtVfyInfo(enmCadesType ctCadesType, DWORD dwCadesVfyStatus, bool bMathValidity, enmCadesType* pSuccessType = NULL);

    enmCadesType getCadesType();

    DWORD getCadesVfyStatus();

    bool getMathValidity();

    bool isSuccessVfyTypeAvailable();
    enmCadesType getSuccessVfyType();

protected:
    enmCadesType m_ctCadesType;
    DWORD m_dwCadesVfyStatus;
    bool m_bMathValidity;
    enmCadesType m_csSuccessVfyType;
    bool m_bIsSuccessVfyTypeSet;
};

class Signer : public ISigner
{
public:
    Signer();
    Signer(DWORD dwIndex, PCMSG_SIGNER_INFO signerInfo, DWORD dwSize, enmCadesType cadesType = ctNone);
    ~Signer();

    void setCertificate(Handle<ICertificate> cert);
    Handle<ICertificate> getCertificate();
    Handle<std::string> getSignatureAlgorithm();
    Handle<std::string> getDigestAlgorithm();

    void setIssuerName(Handle<std::string> name);
    Handle<std::string> getIssuerName();
    void setSerialNumber(Handle<std::string> value);
    Handle<std::string> getSerialNumber();
    void setKeyId(Handle<std::string> value);

    Handle<std::string> getSigningTime();
    void setIndex(DWORD value);
    DWORD getIndex();

    bool verify();

    bool isAuthAttrsAvailable();
    bool verifyEncryptedHash(Handle<std::string> hashValue, HashAlg::HASH_ALG hashAlg);

    bool verifySignatureValue(
        Handle<std::string> hashValue,
        Handle<std::string> signValue,
        char *signAlgOid,
        Handle<std::string> keyValue);

    bool verifySignatureValue(
        Handle<std::string> hashValue,
        Handle<std::string> signValue,
        char *signAlgOid,
        Handle<std::string> keyValue,
        Handle<std::string> keyAlgOid,
        Handle<std::string> namedCurveId);

    bool verifySignatureValue(
        Handle<std::string> hashValue,
        Handle<std::string> signValue,
        char *signAlgOid,
        Handle<ICertificate> signerCert);

    Handle<ITSP> timestamp(enmStampType stampType, DWORD dwStampIdx = 0);
    bool verifyTimestamp(enmStampType stampType, DWORD dwStampIdx = 0);
    Handle<IOCSP> ocspResp();
    bool isCades();
    enmCadesType getCadesType();
    std::vector<std::string> revocationValues();

    void setContent(Handle<std::string> contentBuffer); // required for content time stamp verification

    Handle<ICertificateCollection> certificateValues(); // CAdES XLT1 field

    void setExtendedVerifyInfo(
        enmCadesType ctCadesType,
        DWORD dwCadesVfyStatus,
        bool bMathValidity,
        enmCadesType * pSuccessType = NULL
    );
    Handle<IExtVfyInfo> getExtendedVerifyInfo();

    Handle<std::string> getAttributeValue(std::string &attrToSearch, bool authAttr, DWORD dwAttrIdx = 0);
    Handle<std::string> getAttributeValue(std::vector<std::string>& attrsToSearch, bool authAttr, DWORD dwAttrIdx = 0);
protected:
    Handle<std::string> getAttributeValueForCadesC(std::string &attrToSearch, bool authAttr);

private:
    DWORD m_dwIndex;
    PCMSG_SIGNER_INFO m_pSignerInfo = NULL;
    Handle<Certificate> m_signerCert;

    Handle<std::string> content;

    bool m_isCades;
    enmCadesType m_cadesType;
    Handle<IExtVfyInfo> m_hExtVfyInfo;

protected:
    static Handle<std::string> keyAlgFromSignAlg(const char *signOid);

    Handle<std::vector<BYTE>> encodeParams(Handle<std::string> keyAlgOid, Handle<std::string> namedCurveId);
    Handle<std::string> CurveNameToOid(Handle<std::string> namedCurveId);

    bool verifySignatureValue(
        Handle<std::string> hashValue,
        Handle<std::string> signValue,
        char* signAlgOid,
        PCERT_PUBLIC_KEY_INFO pKeyInfo);

    std::vector<PCCRYPT_OID_INFO> getOidInfos(LPCSTR oidString);
};

#endif //! CMS_SIGNER_H_INCLUDED
