/*
 * Copyright(C) 2003 Проект ИОК
 *
 * Этот файл содержит информацию, являющуюся
 * собственностью компании Крипто Про.
 *
 * Любая часть этого файла не может быть скопирована,
 * исправлена, переведена на другие языки,
 * локализована или модифицирована любым способом,
 * откомпилирована, передана по сети с или на
 * любую компьютерную систему без предварительного
 * заключения соглашения с компанией Крипто Про.
 */

/*!
 * \file $RCSfile: CA_CMP_Msg.h,v $
 * \version $Revision: 1.17 $
 * \date $Date: 2005/03/04 15:16:21 $
 * \author $Author: cav $
 *
 * \brief PKIXCMP_Message class
 */

#ifndef PKIXCMP_MSG_H
#define PKIXCMP_MSG_H

#include <algorithm>

#define CPCSP_C_SOURCE 30
#include "StoreUtil.h"

enum GeneralEventType {
    Unspecified = 0,
    ProcessCert = 1, // Выпуск сертификата
    ProcessCRL = 2, // Выпуск СОС
    RejectCert = 3, // Отказ в обработке запроса 
    RevokeCert = 4, // Отзыв сертификата
    CessationCert = 5, // Приостановление действия сертификата
    ResumeCert = 6, // Возобновление действия сертификата
    ArchiveCert = 7, // Архивация сертификата
    DeleteCert = 8, // Удаление сертификата из архива
    StartSession = 9, // Начало сессии-штатное
    Affiliation = 10, // Начало сессии - плановая смена ключей подписи сертификатов и СОС Уполномоченного лица
    NewAuthorizedPerson = 11, // Начало сессии - формирование ключей нового УЛ
    AuthorizedPersonStart = 12, // Начало сессии - введение в действие ключей УЛ
    DeleteKey = 13, // Удаление действующего ключа УЛ
    StopSession = 14, // Окончание сессии
    StartSessionNewPin = 15, // Старт сессии, смена защитных карт
    addOrganization = 16,
    changeOrganization = 17,
    deleteOrganization = 18,
    addLicense = 19,
    changeLicense = 20,
    deleteLicense = 21,
    addPolicy = 22,
    changePolicy = 23,
    deletePolicy = 24,
    addOfficial = 25,
    changeOfficial = 26,
    deleteOfficial = 27,
    addCertificate = 28,
    changeCertificate = 29,
    deleteCertificate = 30,
    OpenAdditionalKey = 31
};

struct GeneralAudit {
    GeneralAudit() : type( Unspecified ), session( 0 ),
	event_counter( 0 ), success( false ) {}
    GeneralEventType type;
    unsigned session;
    unsigned event_counter;
    bool success;
};

GeneralEventType GeneralEventType_fromString( const char *str );

class CACMPT_InfoTypeAndValue
{
public:
    ~CACMPT_InfoTypeAndValue() {}
    CACMPT_InfoTypeAndValue( const char *an_oid ) : m_oid( an_oid ) {}
    CACMPT_InfoTypeAndValue( const char *an_oid, const CACMPT_BLOB &a_der ) :
	m_oid( an_oid ), m_der( a_der ) {}
    CACMPT_InfoTypeAndValue( const CACMPT_InfoTypeAndValue &right ) :
	m_oid( right.m_oid ), m_der( right.m_der ) {}
    const char *oid() const { return m_oid.c_str(); }
    const CACMPT_BLOB &der() const { return m_der; }
    bool operator==( const char *an_oid ) const
    { return m_oid == an_oid; }
    bool operator!=( const char *an_oid ) const
    { return m_oid != an_oid; }
    CACMPT_InfoTypeAndValue& operator=( const CACMPT_InfoTypeAndValue &right )
    { m_oid = right.m_oid; m_der = right.m_der; return *this;}
protected:
    std::string m_oid;
    CACMPT_BLOB m_der;

private:
    CACMPT_InfoTypeAndValue();
    bool operator==(const CACMPT_InfoTypeAndValue &right) const;
    bool operator!=(const CACMPT_InfoTypeAndValue &right) const;
};

class CACMPT_InfoTypeAndValueList : public std::list<CACMPT_InfoTypeAndValue>
{
public:
    typedef std::list<CACMPT_InfoTypeAndValue> TAVList;
    CACMPT_InfoTypeAndValueList() : TAVList() {}
    CACMPT_InfoTypeAndValueList( const_iterator f, const_iterator l ) : 
	TAVList(f,l) {}
    ~CACMPT_InfoTypeAndValueList() {}
    iterator find( const char *oid )
    { 
	return std::find<iterator,const char*>(begin(),end(),oid); 
    }
    const_iterator find( const char *oid ) const
    { 
	return std::find<const_iterator,const char*>(begin(),end(),oid); 
    }
    void insert( const CACMPT_InfoTypeAndValue &tav )
    { 
	iterator i = find( tav.oid() );
	if( i == end() ) push_back( tav ); else *i = tav;
    }
};

class CACMPT_GeneralInfo : public CACMPT_InfoTypeAndValueList
{
public:
    CACMPT_GeneralInfo() : CACMPT_InfoTypeAndValueList() {}
    ~CACMPT_GeneralInfo() {}
    // return true, if specified
    bool get_audit( GeneralAudit &info ) const;
    //if info.type == Unspecified remove
    void set_audit( const GeneralAudit &info );

private:
    CACMPT_GeneralInfo(const_iterator f, const_iterator l);
};

class Encoding
{
public:
    Encoding( const char *str ) : encoding_( normalize( str ) ) {}
    Encoding( const Encoding &right ) : encoding_( right.encoding_ ) {}

    // Default кодировка для чтения, определяется контекстом
    static const Encoding DEFAULT_READ;
    // Default кодировка для записи, определяется настройками PKIX
    // на данный момент определена как RU-RU
    static const Encoding DEFAULT_WRITE;

    std::wstring toUnicode() const;
    static Encoding fromUnicode( const wchar_t *&str );

    bool operator ==( const Encoding &right ) const
    { return encoding_ == right.encoding_; }
    bool operator !=( const Encoding &right ) const
    { return !( *this == right ); }
    const char* c_str() const { return encoding_.c_str(); }

protected:
    std::string encoding_;
    static std::string normalize( const char *ptr );
private:
    Encoding();
    void assign( const Encoding &right )
    { encoding_ = right.encoding_; }
};

class FreeTextItem : public std::wstring
{
public:
    typedef std::wstring FreeTextString;
    FreeTextItem( Encoding enc = Encoding::DEFAULT_WRITE )
	: FreeTextString(), encoding( enc ) 
    {}
    FreeTextItem( const std::wstring &right, Encoding enc = Encoding::DEFAULT_WRITE )
	: FreeTextString( right ), encoding( enc )
    {}
    FreeTextItem( const wchar_t *right, Encoding enc = Encoding::DEFAULT_WRITE )
	: FreeTextString( right ), encoding( enc )
    {}
    const Encoding &get_encoding() const { return encoding; }
    Encoding get_encoding() { return encoding; }
    FreeTextItem &operator=( const FreeTextItem &right )
    { 
	assign( right );
	return *this;
    }
    void assign( const FreeTextItem &right )
    {
	FreeTextString::assign( right );
	encoding = right.encoding;
    }
    bool operator==( Encoding enc ) const
    {
	return encoding == enc;
    }
    bool operator!=( Encoding enc ) const
    {
	return !( *this == enc );
    }
    bool operator==( const FreeTextItem &right ) const
    {
	return encoding == right.encoding
	    && FreeTextString( right ) == FreeTextString( *this );
    }
    bool operator!=( const FreeTextItem &right ) const
    {
	return !( *this == right );
    }
protected:
    Encoding encoding;
};

class FreeText : public std::list<FreeTextItem>
{
public:
    typedef std::list<FreeTextItem> FreeTextList;
    FreeText(const wchar_t *text, Encoding enc = Encoding::DEFAULT_WRITE) : FreeTextList() 
    {
	push_back(FreeTextItem(text, enc));
    }
    FreeText() : FreeTextList() {}
    FreeText(const FreeText &right) : FreeTextList(right) {}
    FreeText(const FreeTextItem &right)	: FreeTextList() { push_back(right); }
    FreeText &operator=( const FreeText &right )
    {
	assign( right.begin(), right.end() );
	return *this;
    }
    operator const FreeTextItem&() const { return *find(); }
    const_iterator find( Encoding enc = Encoding::DEFAULT_READ ) const
    {
	if( enc == Encoding::DEFAULT_READ )
	    return begin();
	return std::find<const_iterator,Encoding>(begin(),end(),enc); 
    }
    void insert( const FreeTextItem &item )
    { 
	if( item.get_encoding() == Encoding::DEFAULT_READ )
	{
	    push_back( item );
	    return;
	}
	iterator i = find( item.get_encoding() );
	if( i == end() ) push_back( item ); else *i = item;
    }

private:
    operator FreeTextItem();

    iterator find( Encoding enc = Encoding::DEFAULT_READ )
    {
	if( enc == Encoding::DEFAULT_READ )
	    return begin();
	return std::find<iterator,Encoding>(begin(),end(),enc); 
    }
};

class PKIXCMP_Message 
{ 
public:
    PKIXCMP_Message() { clear(); }
    PKIXCMP_Message( const PKIXCMP_Message &right ) { assign( right ); }
    void clear() 
    {
	*SenderGeneralName = 0; 
	*RecipientGeneralName = 0; 
	SubmittedWhen = CACMPT_Date();
	tav_list.clear();
	extra_certs.clear();
	m_sender_nonce.clear();
	m_transactionID.clear();
	m_sender_kid.clear();
    }
    PKIXCMP_Message &operator=( const PKIXCMP_Message &right )
    { assign( right ); return *this; }
    void assign( const PKIXCMP_Message &right )
    { 
	wcscpy( SenderGeneralName, right.SenderGeneralName );
	wcscpy( RecipientGeneralName, right.RecipientGeneralName );
	SubmittedWhen = right.SubmittedWhen;
	tav_list = right.tav_list;
	extra_certs = right.extra_certs;
	m_sender_nonce = right.m_sender_nonce;
	m_transactionID = right.m_transactionID;
	m_sender_kid = right.m_sender_kid;
    }
    wchar_t SenderGeneralName[8192];
    wchar_t RecipientGeneralName[ 8192 ];
    CACMPT_GeneralInfo tav_list;
    // Дата отправки сообщения
    CACMPT_Date SubmittedWhen;
    encoded_certificate_list extra_certs;
    CACMPT_BLOB m_sender_nonce;
    CACMPT_BLOB m_transactionID;
    CACMPT_BLOB m_sender_kid;
    FreeText free_text;
};
#endif // PKIXCMP_MSG_H
