#ifndef CMS_SIGNED_DATA_H_INCLUDED
#define CMS_SIGNED_DATA_H_INCLUDED

#include "cms/isigned_data.h"
#include "../common/common.h"
#include "../stdafx.h"

#include "../pki/pki.h"
#include "../pki/certs.h"
#include "../utils/tools.h"
#include "../utils/asn1_utils.h"
#include "../utils/buffer_file_helper.h"
#include "../cms/signer.h"
#include "../cms/signers.h"
#include "wrapper/utils/license_mng.h"

#include "wrapper/utils/connection_settings.h"
#include "wrapper/cms/sign_params.h"

#ifndef DLV_AND_JWT_NO_LICENSE
extern License_Mng *m_objLicense;
#endif // !DLV_AND_JWT_NO_LICENSE

#ifdef UNIX
#include <cpcsp/csp_product.h>
#if VER_PRODUCTVERSION_MAJOR < 5
typedef struct _CRYPT_CONTENT_INFO_SEQUENCE_OF_ANY
{
	LPSTR pszObjId;
	DWORD cValue;
	PCRYPT_DER_BLOB rgValue;
} CRYPT_CONTENT_INFO_SEQUENCE_OF_ANY, *PCRYPT_CONTENT_INFO_SEQUENCE_OF_ANY;
#endif
#endif

#include <map>

class SignedData : public ISignedData
{
public:
	// constructor
	SignedData();
	~SignedData();

	// Properties
	void setContentURI(Handle<std::string> value);
	void setContent(Handle<std::string> value, DWORD dwSize);
	void addContent(BYTE *value, DWORD dwSize);
	void freeContent();
	Handle<std::string> getContent();
	void writeContent(std::string fileToSave);
	bool isContentAvailable();
	void setHashAlg(HashAlg::HASH_ALG enmHashAlg);
	HashAlg::HASH_ALG getHashAlg();
	void setHashValue(Handle<std::string> hashValue, HashAlg::HASH_ALG enmHashAlg);
	Handle<std::string> getSignedMessage(DataFormat::DATA_FORMAT format);
	SignedDataPolicy getFlags();
	void setFlags(SignedDataPolicy v);
	void addFlag(SignedDataPolicy v);
	void removeFlags(SignedDataPolicy v);
	enmCertIncludePolicy getIncludeCertificates();
	void setIncludeCertificates(enmCertIncludePolicy value);
	void setPin(std::string pinValue);
	std::string getPin();

	// Methods
	Handle<ICertificateCollection> certificates();
	Handle<ICertificate> certificates(int index);
	Handle<ISignerCollection> signers();
	Handle<ISigner> signers(int index);
	bool isDetached();
	void setDetachedFlag(bool bFlag);
	bool checkDetachedFlag();
	void sign(Handle<ICertificate> cert);
	void sign(Handle<std::string> path, DataFormat::DATA_FORMAT format);
	void cosign(Handle<ICertificate> cert);
	bool verify();
	bool verify(Handle<ISigner> signer);
	void setDoNotVerifyAsCades(bool doNotVerifyAsCades);
	void close();
	static bool checkDetached(CRYPT_DATA_BLOB& blobBuffDer);
	DWORD getCadesSignerVerifyStatus(size_t idx);
	void removeSignature();

	void enhanceSignature(Handle<ICertificate> cert, Handle<std::string> hashOid, DWORD dwSignerIndex = 0);

	LPCSTR GetHashOidForSign(HCRYPTPROV hProv, DWORD dwKeySpec);

	void write(Handle<std::string> out, DataFormat::DATA_FORMAT format, bool addHeadersForBASE64 = true);
	void readURI(Handle<std::string> in, DataFormat::DATA_FORMAT format);
	void readFromBuffer(Handle<std::string> buffer, DataFormat::DATA_FORMAT format);

	bool isFileIsSignatureFile(std::string str);
	bool HashIsAbsentInMessage(LPSTR pszHashId);
	void AddSignerWithDifferentHash(PCCERT_CONTEXT pCosignerCert, DWORD dwKeySpec, HCRYPTPROV hCryptProv);
	void get_CountOfSigners(DWORD &dwRefSignerCount);

	void CopySignerWithDifferentHash(HCRYPTMSG refSrcSignerMsg, BOOL bAttrDisable);
	static void joinSignatureAndData(
		const CRYPT_DATA_BLOB blobCosignedMessage,
		const std::string strContent,
		PFN_CMSG_STREAM_OUTPUT pfnStreamOutput,
		const void *pvArg);

	void setStore(Handle<IPkiStore> store);
	Handle<IPkiStore> getStore();
	Handle<std::string> getProviderName();

	// callback
	static BOOL WINAPI callback_size_content(
		const void *pvArg,
		BYTE *pbData,
		DWORD cbData,
		BOOL fFinal);

	static BOOL WINAPI callback_content(
		const void *pvArg,
		BYTE *pbData,
		DWORD cbData,
		BOOL fFinal);

	static BOOL WINAPI CmsgStreamOutputCallback(
		const void *pvArg,
		BYTE *pbData,
		DWORD cbData,
		BOOL fFinal);

	static BOOL WINAPI callback_write(
		const void *pvArg,
		BYTE *pbData,
		DWORD cbData,
		BOOL fFinal);

	static BOOL WINAPI callback_sign(
		const void *pvArg,
		BYTE *pbData,
		DWORD cbData,
		BOOL fFinal);

	static BOOL WINAPI callback_cosign_diffhash(
		const void *pvArg,
		BYTE *pbData,
		DWORD cbData,
		BOOL fFinal);

#ifndef TSP_OCSP_CPP_IMPL_IS_DEPRECATED
	void setTimestampParams(Handle<TimestampParams> tspParams);
#endif
	void setCadesParams(Handle<CadesParams> cadesParams);

#ifndef TSP_OCSP_CPP_IMPL_IS_DEPRECATED
	Handle<TimestampParams> getTimestampParams();
#endif
	Handle<CadesParams> getCadesParams();

	void joinTwoSigns(
		std::string strSign1Path,
		DataFormat::DATA_FORMAT sign1Format,
		std::string strSign2Path,
		DataFormat::DATA_FORMAT sign2Format,
		std::string strJoinedSignPath,
		DataFormat::DATA_FORMAT joinedSignFormat
	);
	void joinSigns(
		std::vector<std::pair<std::string, DataFormat::DATA_FORMAT>> signatures,
		std::string strJoinedSignPath,
		DataFormat::DATA_FORMAT joinedSignFormat
	);

protected:
#ifndef TSP_OCSP_CPP_IMPL_IS_DEPRECATED
	void AddTimeStampforSignature(DWORD dwSignerIndex, std::string hashAlgOid = "");
#endif // TSP_OCSP_CPP_IMPL_IS_DEPRECATED
	HCRYPTMSG LoadDetachedSignatureWithContent();
	bool VerifyAsCades(DWORD dwIndex, HCRYPTMSG hMsgToVerify, enmCadesType cadesType /*= ctCadesXLT1*/, PDWORD pdwCadesVfyStatus = NULL);

	static bool filetimeLess(const std::pair<DWORD, FILETIME> &time1, const std::pair<DWORD, FILETIME> &time2);
	DWORD FindSignerIndexForCertificate(Handle<Certificate> signerCert, BOOL findFirst = TRUE);

	enmCadesType getCadesType(HCRYPTMSG hMsg, DWORD index);
	DWORD cadesTypeCt2Cp(enmCadesType typeToConvert);

	bool isErrorRelatesOnCadesFormat(DWORD dwError);

protected:
	void LoadMessage(HCRYPTMSG hMsg, BOOL bIsDetached);
	void LoadDetachedContent(HCRYPTMSG hMsg, bool failIfEmpty = false);
	Handle<ISigner> getSignerFromOpenedMessage(unsigned int index, HCRYPTMSG hMsg, HCERTSTORE hStoreHandle);
	static std::vector<BYTE> getAuthAttrsForHash(const std::vector<BYTE> &blobEncodedSigner);
	bool verifySignerByHashValue(Handle<ISigner> signer, HCRYPTMSG hMsg);
	bool verifySignValue(PCCERT_CONTEXT pSignerCertContext, DWORD dwSignerIndex, HCRYPTMSG hMsg = NULL);

	Handle<ICertificateCollection> getCertsToAdd(Handle<ICertificate> signCert);
	HCERTSTORE getCertStoreFromCertValues(Handle<ISigner> signer);

	size_t getContentLength();
	std::vector<BYTE> getContentChunk(size_t offset, size_t length);

	DWORD getSignerCount(HCRYPTMSG hMsg);
	HCRYPTMSG mergeDigestAlgorithmsFromSecondIntoFirst(HCRYPTMSG hMsg1, HCRYPTMSG hMsg2);

	Handle<std::string> content; //Переделать для отчистки
	std::string contentUri;		 //Переделать для отчистки
	FileHeper m_fileContent;
	std::string m_strOutBuffer; //Вспомогательная переменная для поблочного преобразования в PEM

	std::string m_SignedMessage; // Memory storage for signed mesage
	FileHeper m_tmpFileSignedMessage;
	void OpenSignedFile(std::string &fileToOpen, DataFormat::DATA_FORMAT format);
	size_t getMsgLength();
	std::vector<unsigned char> getMsgChunk(size_t offset, size_t length);

	bool m_bIsSignedFile;
	bool m_bIsDetached;
	DWORD m_dwFlags;
	enmCertIncludePolicy m_enmCertIncludePolicy;
	std::string m_strPin;
	FILE *m_pFile = NULL;
	BOOL m_bIsBase64;
	BOOL m_bIsCosign;

	HCRYPTMSG m_hMsg = 0;

#ifndef TSP_OCSP_CPP_IMPL_IS_DEPRECATED
	Handle<TimestampParams> m_tspParams;
#endif
	Handle<CadesParams> m_cadesParams;
	std::map<int, DWORD> m_mapStatus;

	bool m_doNotVerifyAsCades;

	Handle<std::string> m_hashValue;
	HashAlg::HASH_ALG m_hashAlg;

	Handle<IPkiStore> m_store;
};

#endif //! CMS_SIGNED_DATA_H_INCLUDED
