#ifndef __ASN1_EXCEPTIONS_H
#define __ASN1_EXCEPTIONS_H

#include <stdexcept>
#include <string>
#include <wchar.h>
#include <cstdio>

class CAException : public std::runtime_error
{
public:
    CAException(const CAException& src) : std::runtime_error(src), wfile(src.wfile), wline(src.wline) {}

    CAException(const char *msg, const char *f, int l)
	: std::runtime_error(format_string(msg, f, l)), wfile(f), wline(l)
    {}

    // используется в Службах
    explicit CAException(const char *msg = NULL)
	: std::runtime_error(msg), wfile(""), wline(0)
    {}

    ~CAException() throw () {}

    // используются в Стандарте и Службах
    const char *file() const { return wfile.c_str(); }
    int line() const { return wline; }

    static const std::string format_string( const char *msg, const char *wfile, int line )
    {
	char str[20];
	sprintf( str, "%d", line );
	return std::string( "Exception :'" ) + msg + "' at file:'" + wfile + "' line:" + str;
    }

private:
    const std::string wfile;
    const int wline;

    CAException& operator=(const CAException&);
};

#define CA_EXCEPTION(x,y) x(y,__FILE__,__LINE__)

class Asn1Exception : public CAException
{
public:
    explicit Asn1Exception( const char *msg = "Asn1 fail.", const char *f = NULL, int l = 0 )
	: CAException( msg, f, l ) {}
};

class Asn1DecodeException : public CAException
{
public:
    explicit Asn1DecodeException( const char *msg = "Asn1 decode fail.", const char *f = NULL, int l = 0 )
	: CAException( msg, f, l ) {}
};

#define CA_CRYPT_EXCEPTION CryptException(GetLastError(),__FILE__,__LINE__)
#define CA_HR_EXCEPTION(hr) CryptException((DWORD)(hr),__FILE__,__LINE__)
#define CA_MEMORY_EXCEPTION CAException("out of memory",__FILE__,__LINE__)
#define CA_ASN1_EXCEPTION(pctxt) Asn1Exception(rtErrGetText(pctxt),__FILE__,__LINE__)

class CryptException : public CAException
{
public:
    explicit CryptException( unsigned int err, const char *f = NULL, int l = 0 )
	: CAException( format_crypt( err ).c_str(), f, l ), code(err) {}
    unsigned get_err() const { return code; }
private:
    const unsigned code;
    static const std::string format_crypt( unsigned int err );
};

#include "reader/support.h"

SUP_INLINE const std::string CryptException::format_crypt(unsigned int err)
{ 
    char message[32];
    sprintf(message, "Error 0x%x.", err);
    return std::string(message);
}

#endif // __ASN1_EXCEPTIONS_H
