#ifndef CPP_ENROLL_CERTIFICATE_REQUEST_OBJECT_H_
#define CPP_ENROLL_CERTIFICATE_REQUEST_OBJECT_H_

#include "cppcades.h"
#include "CPPEnrollEnumerations.h"
#include "CPPEnrollObjectId.h"
#include "CPPEnrollX509PrivateKey.h"
#include "CPPEnrollX509Extension.h"
#include "CPPEnrollX500DistinguishedName.h"
#include "CPPEnrollX509SignatureInformation.h"
#include "CPPEnrollCollections.h"
#include "cplib/DateTime.h"
#include <atlcrypt2.h>

using namespace ATL;
namespace CryptoPro {
namespace PKI {
namespace Enroll {

class CPPEnrollX509CertificateRequest
{
public:
    CPPEnrollX509CertificateRequest(void);
    virtual ~CPPEnrollX509CertificateRequest(void);

    HRESULT get_ClientId(RequestClientInfoClientId *pVal);
    HRESULT put_ClientId(RequestClientInfoClientId newVal);

    HRESULT get_HashAlgorithm(boost::shared_ptr<CPPEnrollObjectId>& pVal);
    HRESULT put_HashAlgorithm(boost::shared_ptr<CPPEnrollObjectId> newVal);

    //web disabled
    virtual HRESULT Encode(EncodingType Encoding, CStringBlob& encRequest);
    virtual HRESULT Initialize(X509CertificateEnrollmentContext Context);

    HRESULT get_EnrollmentContext(X509CertificateEnrollmentContext *pValue);

    // internal
    virtual HRESULT get_PrivateKey(boost::shared_ptr<CPPEnrollX509PrivateKey>& pVal);
    virtual HRESULT get_SmimeCapabilities(bool* pVal);
    virtual HRESULT get_Subject(boost::shared_ptr<CPPEnrollX500DistinguishedName>& pVal);
    virtual HRESULT get_X509Extensions(boost::shared_ptr<CPPEnrollX509Extensions>& pVal);
    virtual HRESULT get_X509NameValuePairs(boost::shared_ptr<CPPEnrollX509NameValuePairs>& pVal);
    virtual HRESULT get_SignatureInformation(
        boost::shared_ptr<CPPEnrollX509SignatureInformation>& pVal);
    virtual HRESULT get_PublicKey(boost::shared_ptr<CPPEnrollX509PublicKey>& pVal);
    bool IsMachineContext();
    HRESULT put_Silent(BOOL bVal);
    HRESULT put_ForceReaderDialog(BOOL bVal);
protected:
    HRESULT CheckObjectState();

    RequestClientInfoClientId m_clientId;
    bool m_bInitialized;
    bool m_bSilent;
    bool m_bForceReaderDialog;
    boost::shared_ptr<CPPEnrollObjectId> m_pHashAlgorithm;
    X509CertificateEnrollmentContext m_enrollmentContext;
private:
    DISALLOW_COPY_AND_ASSIGN(CPPEnrollX509CertificateRequest);
};

class CPPEnrollX509CertificateRequestPkcs10 : public CPPEnrollX509CertificateRequest
{
public:
    CPPEnrollX509CertificateRequestPkcs10(void);
    ~CPPEnrollX509CertificateRequestPkcs10(void);

    HRESULT InitializeFromPrivateKey(
        X509CertificateEnrollmentContext Context,
        boost::shared_ptr<CPPEnrollX509PrivateKey> pVal,
        CAtlString strTemplateName);

    HRESULT get_PrivateKey(boost::shared_ptr<CPPEnrollX509PrivateKey>& pVal);

    HRESULT get_SmimeCapabilities(bool* pVal);
    HRESULT put_SmimeCapabilities(bool newVal);

    HRESULT get_Subject(boost::shared_ptr<CPPEnrollX500DistinguishedName>& pVal);
    HRESULT put_Subject(boost::shared_ptr<CPPEnrollX500DistinguishedName> newVal);

    HRESULT get_X509Extensions(boost::shared_ptr<CPPEnrollX509Extensions>& pVal);
    HRESULT get_X509NameValuePairs(boost::shared_ptr<CPPEnrollX509NameValuePairs>& pVal);

    HRESULT get_SignatureInformation(
        boost::shared_ptr<CPPEnrollX509SignatureInformation>& pVal);
    // web disabled
    HRESULT Encode(EncodingType Encoding, CStringBlob& encodedRequest);
    HRESULT Initialize(X509CertificateEnrollmentContext Context);

    HRESULT get_PublicKey(boost::shared_ptr<CPPEnrollX509PublicKey>& pVal);
    HRESULT put_Silent(BOOL bVal);

    // internal
    HRESULT init_PublicKey();
    HRESULT init_SignatureInformation();
    HRESULT addX509ExtensionKeyUsage();
    HRESULT addX509ExtensionSubjectKeyIdentifier();
    HRESULT addX509ExtensionSmimeCapabilities(); // это на будущее
    HRESULT addX509AttributeExtensions();
    HRESULT addX509AttributeNameValuePairs();
protected:
    bool m_bSmimeCapabilities;
    boost::shared_ptr<CPPEnrollX509Extensions> m_pExtensions;
    boost::shared_ptr<CPPEnrollX509NameValuePairs> m_pNameValuePairs;
    boost::shared_ptr<CPPEnrollX509AttributeNameValuePairs> m_pAttributeNameValuePairs;
    boost::shared_ptr<CPPEnrollCryptAttributes> m_pAttributes;
    boost::shared_ptr<CPPEnrollX509PrivateKey> m_pPrivateKey;
    boost::shared_ptr<CPPEnrollX509PublicKey> m_pPublicKey;
    boost::shared_ptr<CPPEnrollX500DistinguishedName> m_pSubjectName;
    boost::shared_ptr<CPPEnrollX509SignatureInformation> m_pSignatureInfo;
private:
    DISALLOW_COPY_AND_ASSIGN(CPPEnrollX509CertificateRequestPkcs10);
};

class CPPEnrollX509CertificateRequestCertificate : public CPPEnrollX509CertificateRequestPkcs10
{
public:
    CPPEnrollX509CertificateRequestCertificate(void);
    ~CPPEnrollX509CertificateRequestCertificate(void);

    HRESULT Encode(EncodingType Encoding, CStringBlob& encodedCert);
    HRESULT Initialize(X509CertificateEnrollmentContext Context);

    HRESULT get_NotAfter(CDateTime& pVal);
    HRESULT put_NotAfter(CDateTime newVal);

    HRESULT get_NotBefore(CDateTime& pVal);
    HRESULT put_NotBefore(CDateTime newVal);

    HRESULT get_Issuer(boost::shared_ptr<CPPEnrollX500DistinguishedName>& pVal);
    HRESULT put_Issuer(boost::shared_ptr<CPPEnrollX500DistinguishedName> newVal);

    HRESULT get_SerialNumber(EncodingType Encoding, CStringBlob& pVal);
    HRESULT put_SerialNumber(EncodingType Encoding, CStringBlob& newVal);

    // internal
    HRESULT InitializeFromRequest(boost::shared_ptr<CPPEnrollX509CertificateRequest>& pRequest);
    HRESULT GetCertificateContext(CCertContext& pContext);
    HRESULT EncodeCertificate();
    HRESULT CreateSerialNumber();
private:
    CDateTime m_notAfter;
    CDateTime m_notBefore;
    CStringBlob m_serialNumber;
    boost::shared_ptr<CPPEnrollX500DistinguishedName> m_pIssuerName;
    CStringBlob m_encodedCert;
private:
    DISALLOW_COPY_AND_ASSIGN(CPPEnrollX509CertificateRequestCertificate);
};
} /* namespace Enroll */
} /* namespace PKI */
} /* namespace CryptoPro */

#endif // CPP_ENROLL_CERTIFICATE_REQUEST_OBJECT_H_
