#ifndef __STORE_UTIL_H
#define __STORE_UTIL_H

#include "ASN1Blob.h"

#include <set>

#ifdef _WIN32
#include <windows.h>
#include <WinCrypt.h>
#else
#include "WinCryptEx.h"
#endif	/* _WIN32 */

class CertificateStore
{
private:
    wchar_t * StoreName;
    bool isSystemStore;

public:
    CertificateStore() : StoreName(NULL), isSystemStore(true) {}
    CertificateStore(const wchar_t * aStoreName, const bool aisSystemStore);
    CertificateStore(const CertificateStore & store);
    const CertificateStore& operator=(const CertificateStore &);
    ~CertificateStore() { ::free(StoreName); }

    void  Set(const wchar_t * name,const bool aisSystemStore);
    void Set(const wchar_t * name); // Только для PKIXCMPTESTа (парсит имя на user./system. имя store
    const wchar_t * GetName() const { return StoreName; }
    bool isSystem() const { return isSystemStore; }

    bool operator == (const CertificateStore & s) const;
    bool operator < (const CertificateStore & s) const;
};

#define Store_CA	 CertificateStore (L"CA",	true)
#define Store_RA	 CertificateStore (L"RA",	true)
#define Store_Root	 CertificateStore (L"Root",	true)
#define Store_Trust	 CertificateStore (L"Trust",	true)


struct store_handle
{
    store_handle(): store_(0), trust_(false) {}
    explicit store_handle(const HANDLE& store, bool dup_handle, bool trust = false);
    store_handle( const store_handle& handle);
    ~store_handle();

    bool open(const std::wstring & store, bool issystem,
	      unsigned long flags = CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG);
    bool open(const CertificateStore & store)
    {
	    return store_handle::open(store.GetName(), store.isSystem());
    };
    bool open(const std::wstring & store,
	      unsigned long flags = CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER);

    HANDLE store_;
    bool trust_;
private:
    // копирование запрещено
    store_handle& operator=( const store_handle& handle);
};

template< class f1, class f2, bool v > bool cmp_handles( const store_handle &left,
    const store_handle &right )
{ 
    if( left.trust_ != right.trust_ ) 
	return f1() ( left.trust_, right.trust_);
    if( left.store_ != right.store_ ) 
	return f2() ( left.store_, right.store_ );
    return v;
}

inline bool operator !=( const store_handle &left, const store_handle &right )
{ return cmp_handles< std::not_equal_to<bool>, std::not_equal_to<HANDLE>, false >( left, right ); }
inline bool operator ==( const store_handle &left, const store_handle &right )
{ return cmp_handles< std::equal_to<bool>, std::equal_to<HANDLE>, false >( left, right ); }
inline bool operator <( const store_handle &left, const store_handle &right )
{ return cmp_handles< std::greater<bool>, std::greater<HANDLE>, false >( left, right ); }
inline bool operator <=( const store_handle &left, const store_handle &right )
{ return cmp_handles< std::less_equal<bool>, std::less_equal<HANDLE>, true >( left, right ); }
inline bool operator >( const store_handle &left, const store_handle &right )
{ return cmp_handles< std::less<bool>, std::less<HANDLE>, false >( left, right ); }
inline bool operator >=( const store_handle &left, const store_handle &right )
{ return cmp_handles< std::greater_equal<bool>, std::greater_equal<HANDLE>, true >( left, right ); }

typedef std::set<store_handle> store_set;

class ThreadSpecificKey
{
    unsigned int m_key;
  public:
    ThreadSpecificKey ();
    ~ThreadSpecificKey ();
    void * GetValue ();
    bool SetValue (const void * ptr, void **old_ptr = NULL);
};

#if defined UNIX || defined CAPILITE_WIN
typedef BOOL (*CRYPT_PIN_CALLBACK) (char *pin, size_t len, void * arg);
extern "C" BOOL CPCryptGetPinFromCallback (char *pin, size_t len);
extern "C" void CPCryptSetPinCallback (CRYPT_PIN_CALLBACK func, void *arg);
extern "C" void CPCryptGetPinCallback (CRYPT_PIN_CALLBACK* func, void **arg);
#endif // _WIN32

extern const wchar_t ROOT_STORE[];
extern const wchar_t CA_STORE[];

#endif // __STORE_UTIL_H
