/*!
 * (C) 2002 "Kaspersky Lab"
 *
 * \file EVP/EventsProcessor.h
 * \author Михаил Кармазин
 * \date 2002
 * \brief Модуль, отвечающий за обработку событий, доставляемых Агентом 
 *        на Сервер администрирования.
 *
 */

#ifndef KLEVP_EVENTSPROCESSOR_H
#define KLEVP_EVENTSPROCESSOR_H

#include <vector>
#include <string>

#include <std/base/klbase.h>
#include <kca/prci/componentid.h>
#include <srvp/evp/eventproperties.h>
#include <srvp/evp/eventseverities.h>

namespace KLEVP {

    //! Структура с описанием события, доставляемого модулю EventsProcessor.
    struct EventInfo
    {
		std::wstring eventId; ///< GUID - уникальный идентификатор.
        KLPRCI::ComponentId publisher; ///< Идентификатор компонента, опубликовавшего событие.
		std::wstring eventType;		   ///< Тип опубликованного события.     
		KLSTD::CAutoPtr<KLPAR::Params> body;  ///< Тело события.
        time_t  eventTime;                    ///< Время возникновения события.
        long    eventTimeMsec;                  ///<Время возникновения события (мс)
        std::wstring subscription; ///< Идентификатор подписки для события.
		EventInfo():eventTime(0), eventTimeMsec(0){}
    };

    const wchar_t pcszEventInfoArray[] = L"EventInfoArray";

	const wchar_t pcszEventId[] = L"EventId";
	const wchar_t pcszEventType[] = L"EventType";
	const wchar_t pcszBody[] = L"Body";
	const wchar_t pcszEventTime[] = L"EventTime";
    const wchar_t pcszEventTimeMs[] = L"EventTimeMsec";
	const wchar_t pcszSubscription[] = L"Subscription";
	const wchar_t pcszComponentId_PRODUCT_NAME[] = L"COMPONENT_ID_PRODUCT_NAME";
	const wchar_t pcszComponentId_VERSION[] = L"COMPONENT_ID_VERSION";
	const wchar_t pcszComponentId_COMPONENT_NAME[] = L"COMPONENT_ID_COMPONENT_NAME";
	const wchar_t pcszComponentId_INSTANCE_ID[] = L"COMPONENT_ID_INSTANCE_ID";

    /*!
    * \brief Интерфейс реализует функциональность по обработке событий, доставляемых
    *        агентами (модулями EventsManager) на Сервер Администрирования.
    *
    *  Модуль принимает события от Агентов в методе Process и далее обрабатывает их
    *  по следующему алгоритму:
    *
    *   1) События помещаются во внутренную очередь в памяти. 
    *   2) События, о которых должны быть доставлены нотификации Администратору,
    *      записываются в отдельные persistent очереди событий для каждого из видов
    *      доставки (SNMP, net send, run executable).
    *   3) События, информация о которых должна быть помещена в базу, записываются в
    *      отдельную persistent очередь.
    *   4) События, которые модифицируют состояние базы данных (для которых определены
    *      специальные транзакционные обработчики), записываются
    *      в отдельную persistent очередь.  Транзакционные обработчики представляют собой
    *      callback-функции, которые вызываются в отдельной транзакции.
    *   5) Удаленному Агенту, пославшему события, отправляется уведомление о приеме 
    *      пакета событий с заданным идентификатором.
    *   6) Событие публикуется на Сервере Администрирования от лица компонента EventsManager.
    *
    *  Далее три persistent-очереди (очередь нотификаций, очередь для вставки в базу данных,
    *  очередь транзакционных обработчиков) обрабатываются параллельно и независимо друг от
    *  друга.
    *
    *  События из очереди нотификаций отправляются администратору с использованием
    *  соответствующих механизмов.
    *
    *  1) Происходит проверка того, не было ли уже отправлена администратору нотификация
    *     о событии с заданным идентификатором.
    *  2) Для SNMP и net send - нотификаций делаются попытки отправить сообщение 
    *     в течении установленного timeout, по истечении timeout в базу данных
    *     заносится событие о ошибке отправки нотификации.
    *  3) В случае ошибки запуска внешнего процесса для отправки нотификации
    *     дальнейшая обработка события немедленно прекращается, в базу данных
    *     заносится событие об ошибке отправки нотификации.
    *
    *  События из очереди для добавления в базу данных вставляются с помощью bulk insert:
    *
    *  1) Если потеряно соединение с базой данных, обработка очереди прекращается.  
    *     После возобновления соединения с базой данных, обработка событий продолжается.
    *  2) Если произошла ошибка при вставке события в базу данных, событие перемещается
    *     в специальную очередь и производится еще несколько попыток вставить событие в базу.
    *     После этого в базу помещается событие о ошибке добавления события в базу.
    *  3) Если ошибка при вставке события в базу произошла из-за того, что данное событие
    *     уже присутствует в базе, обработка события прекращается.
    * 
    *  
    *  События из очереди для транзакционных обработчиков обрабатываются следующим образом:
    *  
    *  1) Если потеряно соединение с базой данных, обработка очереди прекращается.
    *     После возобновления соединения с базой данных, обработка событий продолжается.
    *  2) Проверяется, не вызывались ли уже для данного события транзакционные обработчики.
    *     Если для данного события уже вызывались транзакционные обработчики, обработка
    *     события прекращается.  Информация о вызове транзакционных обработчиков для
    *     событий, полученных от конкретного Агента, удаляется после получения двух
    *     последующих пакетов событий от Агента либо по истечении определенного timeout.
    *  3) В одной транзакции вызываются последовательно все обработчики, 
    *     зарегистрированные для данного события и регистрируется факт вызова обработчиков.  
    *     Последовательность вызовов обработчиков не специфицируется, 
    *     обработчики должны быть независимы друг от друга, не приводить к deadlock 
    *     и работать максимально надежно.
    *  4) В случае успешного завершения всех обработчиков происходит commit транзакции.
    *     Обработка события прекращается.
    *  5) В случае неуспешного завершения обработчиков происходит rollback транзакции,
    *     событие перемещается в специальную очередь и делается еще несколько попыток
    *     вызова обработчиков для данного события.  После этого в базу помещается событие
    *     о ошибке обработки события.
    *
    */

    
    class EventsProcessor : public KLSTD::KLBase {
    public:

    /*!
      \brief Метод принимает на обработку пакет событий от Агента.

        \param package      [in] Пакет событий для обработки.
        \param deliveryId   [in] Идентификатор пакета событий, доставленный 
                                 на Сервер Администрирования.
        \param domain       [in] Идентификатор домена узла, который доставляет событие.
        \param hostName     [in] Имя узла в домене, который доставляет событие.
        \param agentId      [in] Идентификатор агента администрирования, который
                                 доставляет событие.
       
    */
        virtual void Process ( 
            const std::vector<EventInfo> & package,
            const std::wstring & deliveryId,
            const std::wstring & domain,
            const std::wstring & hostName,
            const std::wstring & agentId ) = 0;
    };
    
    class EventsProcessorFactory : public KLSTD::KLBase
    {
    public:
        virtual void CreateInstance( EventsProcessor ** pEventsProcessor ) = 0;
    };
}

#endif // KLEVP_EVENTSPROCESSOR_H

