//	+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++
//	|                     Фабрика стандартных событий и событий FormEx                          |
//	+                                      ShmalevoZ                                            +
//	|                                       2009-06                                             |
//	+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++

//---------------------------------------------------------------------------------------------
// Собственные атрибуты
Перем гМенеджерСобытий;
Перем гТаблицаШаблонов;
Перем гКэшНаличияДелегатов;
Перем гСервис;
Перем гПерехватчик;


//******************************************************************************
// НормализоватьКонтекст(СсылаКонтекст)
//
// Параметры: 
//  СсылаКонтекст
//
// Возвращаемое значение:
//  Неопределенный
//
// Описание:
//  Возвращает ссылка на переданный контекст
//
Функция НормализоватьКонтекст(СсылаКонтекст)
	
	Возврат СсылаКонтекст;
	
КонецФункции // НормализоватьКонтекст()


//******************************************************************************
// _this()
//
// Параметры: 
//  СсылкаКонтекст			- контекст
//
// Возвращаемое значение:
//  ГрупповойКонтекст		- ссылка на контекст
//
// Описание:
//  Возвращает ссылку на контекст
//
Функция _this()
	
	Возврат НормализоватьКонтекст(Контекст);
	
КонецФункции // _this()


//******************************************************************************
// Конструктор()
//
// Параметры: 
//  
//
// Возвращаемое значение:
//  Нет
//
// Описание:
//  ТекстОписания
//
Процедура Конструктор()
	
	//---------------------------------------------------------------------------------------------
	// Создадим собственные объекты
	гПерехватчик		= СоздатьОбъект("Перехватчик");
	гСервис				= СоздатьОбъект("Общие.Сервис.Контекст");
	Регистратор			= СоздатьОбъект("Общие.Статик.Регистратор");
	гМенеджерСобытий	= Регистратор.Получить("Общие.Статик.Объект.МенеджерСобытий");
	//---------------------------------------------------------------------------------------------
	// Шаблоны должны быть наследниками от Общие.Абстрактный.Шаблон.Фабрика.События
	гТаблицаШаблонов	= СоздатьОбъект("ТаблицаЗначений");
	гТаблицаШаблонов.НоваяКолонка("Ссылка");
	Информатор			= СоздатьОбъект("MetaInfoClasses");
	СписокКлассов		= Информатор.ПолучитьВсеИменаКлассов();
	КоличествоКлассов	= СписокКлассов.РазмерСписка();
	Искомое				= "Общие.Абстрактный.Шаблон.Фабрика.События";
	Для НомерКласса = 1 По КоличествоКлассов Цикл
		Идентификатор	= СписокКлассов.ПолучитьЗначение(НомерКласса);
		Если Информатор.ЯвляетсяОбъектом(Идентификатор, Искомое) = 1 Тогда
			гТаблицаШаблонов.НоваяСтрока();
			гТаблицаШаблонов.Ссылка	= СоздатьОбъект(Идентификатор);
		КонецЕсли;
	КонецЦикла;
	//---------------------------------------------------------------------------------------------
	// Кэш
	гКэшНаличияДелегатов	= СоздатьОбъект("ИндексированнаяТаблица");
	гКэшНаличияДелегатов.НоваяКолонка("Индекс");
	гКэшНаличияДелегатов.НоваяКолонка("Шаблон");
	гКэшНаличияДелегатов.ДобавитьИндекс("ОсновнойИндекс", "Индекс");
	
КонецПроцедуры // Конструктор()


//******************************************************************************
// БазовыйКласс()
//
// Параметры: 
//  
//
// Возвращаемое значение:
//  Ссылка					- ссылка на основной базовый класс
//
// Описание:
//  Возвращает ссылку на основной базовый класс
//
Функция БазовыйКласс()
	
	Возврат _this()._БазовыйКласс("Общие.Событие.Делегат");
	
КонецФункции // БазовыйКласс()


//******************************************************************************
// ПолучитьШаблонПерехватаСобытий(ТипКонтекста)
//
// Параметры: 
//  ТипКонтекста
//
// Возвращаемое значение:
//  Нет
//
// Описание:
//  ТекстОписания
//
Функция ПолучитьШаблонПерехватаСобытий(СсылкаКонтекст)
	
	ТипКонтекста	= гСервис.ПолныйТипКонтекста(СсылкаКонтекст);
	Если гКэшНаличияДелегатов.НайтиСтроку("ОсновнойИндекс", ТипКонтекста, 0, 1) = 0 Тогда
		
		//---------------------------------------------------------------------------------------------
		// Построим шаблон
		ШаблонМетодов	= "";
		гТаблицаШаблонов.ВыбратьСтроки();
		Пока гТаблицаШаблонов.ПолучитьСтроку() = 1 Цикл
			
			ИдентификаторСобытия		= гТаблицаШаблонов.Ссылка.ПолучитьИдентификаторСобытия();
			ПубликоватьСобытияДоПосле	= гТаблицаШаблонов.Ссылка.ПубликоватьСобытияДоПосле();
			ЕстьДелегатыСобытия			= 0;
			Если ПубликоватьСобытияДоПосле = 1 Тогда
				ЕстьДелегатыСобытия	= Макс(гМенеджерСобытий.ЕстьДелегатыСобытия("ДоСобытия" + ИдентификаторСобытия, СсылкаКонтекст), гМенеджерСобытий.ЕстьДелегатыСобытия("ПослеСобытия" + ИдентификаторСобытия, СсылкаКонтекст));
			Иначе
				ЕстьДелегатыСобытия	= гМенеджерСобытий.ЕстьДелегатыСобытия(ИдентификаторСобытия, СсылкаКонтекст);
			КонецЕсли;
			Если ЕстьДелегатыСобытия = 0 Тогда
				Продолжить;
			КонецЕсли;
			Если гТаблицаШаблонов.Ссылка.ПринадлежитКонтексту(ТипКонтекста) = 0 Тогда
				Продолжить;
			КонецЕсли;
			
			КоличествоПараметров		= гТаблицаШаблонов.Ссылка.ПолучитьКоличествоПараметров();
			СтрокаПараметров			= "";
			Для НомерПараметра = 1 По КоличествоПараметров Цикл
				СтрокаПараметров	= СтрокаПараметров + ",Параметр" + НомерПараметра;
			КонецЦикла;
			
			ШаблонМетодов	= ШаблонМетодов + "
			| // Перехват события " + ИдентификаторСобытия + "
			| Функция " + ИдентификаторСобытия + "(" + Прав(СтрокаПараметров, СтрДлина(СтрокаПараметров) - 1) + ") Экспорт
			|	Событие			= СоздатьОбъект(""Общие.Событие"");
			|	Результат		= 1;
			|";
			
			Если ПубликоватьСобытияДоПосле = 1 Тогда
				ШаблонМетодов	= ШаблонМетодов + "
				|	Результат	= Событие.Опубликовать(""ДоСобытия" + ИдентификаторСобытия + """, гСсылкаКонтекст" + СтрокаПараметров + ");
				|";
			Иначе
				ШаблонМетодов	= ШаблонМетодов + "
				|	Результат	= Событие.Опубликовать(""" + ИдентификаторСобытия + """, гСсылкаКонтекст" + СтрокаПараметров + ");
				|";
			КонецЕсли;
			ШаблонМетодов	= ШаблонМетодов + "
			|	Если Результат = 1 Тогда
			|		Результат	= гПерехватчик.ВыполнитьОригинальноеСобытиеГК(гСсылкаКонтекст, """ + ИдентификаторСобытия + """" + СтрокаПараметров + ");
			|	КонецЕсли;
			|";
			Если ПубликоватьСобытияДоПосле = 1 Тогда
				ШаблонМетодов	= ШаблонМетодов + "
				| Если Результат = 1 Тогда
				|	Результат	= Событие.Опубликовать(""ПослеСобытия" + ИдентификаторСобытия + """, гСсылкаКонтекст" + СтрокаПараметров + ");
				| КонецЕсли;
				|";
			КонецЕсли;
			ШаблонМетодов	= ШаблонМетодов + "
			| 	Возврат Результат;
			| КонецФункции
			|";
		КонецЦикла;
		
		Если ПустаяСтрока(ШаблонМетодов) = 0 Тогда
			
			ШаблонМетодов	= "
			|
			| Перем гСсылкаКонтекст, гПерехватчик;
			|
			| Процедура УстановитьПараметры(СсылкаКонтекст) Экспорт
			|	гСсылкаКонтекст		= СсылкаКонтекст;
			|	гПерехватчик		= СоздатьОбъект(""Перехватчик"");
			| КонецПроцедуры
			|
			|" + ШаблонМетодов;
			
		КонецЕсли;
	
		гКэшНаличияДелегатов.НоваяСтрока();
		гКэшНаличияДелегатов.Индекс	= ТипКонтекста;
		гКэшНаличияДелегатов.Шаблон	= ШаблонМетодов;
		
	КонецЕсли;
	
	Возврат гКэшНаличияДелегатов.Шаблон;
КонецФункции // ПолучитьШаблонПерехватаСобытий()


//******************************************************************************
// ОбработатьСобытие_СозданиеКонтекста(Параметры)
//
// Параметры: 
//  Параметры
//
// Возвращаемое значение:
//  Нет
//
// Описание:
//  ТекстОписания
//
Функция ОбработатьСобытие_СозданиеКонтекста(Параметры)
	
	Результат		= 1;
	СсылкаКонтекст	= Параметры.ПолучитьЗначение(1);
	ТекстМодуля		= ПолучитьШаблонПерехватаСобытий(СсылкаКонтекст);
		
	Если ПустаяСтрока(ТекстМодуля) = 1 Тогда
		Возврат Результат;
	КонецЕсли;
	
	Делегат		= СоздатьОбъект("Общие.Абстрактный.Модуль");
	Делегат.РазрешитьВложенныйВызовМетодов();
	Делегат.НазначитьКонтекст(СсылкаКонтекст);
	Делегат.УстановитьМодуль(ТекстМодуля);
	Если Делегат.КомпилироватьМодуль() = 0 Тогда
		Сообщить("Не удалось создать перехватчик событий " + ТипЗначенияСтр(_this()));
	КонецЕсли;
	Делегат.ВыполнитьМодуль();
	Делегат.ПрисоединитьТекущийМодуль();
	Делегат.УстановитьПараметры(СсылкаКонтекст);
	гПерехватчик.ПерехватитьСобытияГК(СсылкаКонтекст, Делегат);
	
	Возврат Результат;
КонецФункции // ОбработатьСобытие_СозданиеКонтекста()


//******************************************************************************
// ОбработатьСобытие_ПриИзмененииСоставаДелегатов(Параметры)
//
// Параметры: 
//  Параметры
//
// Возвращаемое значение:
//  СтатусВозврата
//
// Описание:
//  Очищает кэш
//
Функция ОбработатьСобытие_ПриИзмененииСоставаДелегатов(Параметры)
	
	гКэшНаличияДелегатов.УдалитьСтроки();
	
	Возврат 1;
КонецФункции // ОбработатьСобытие_ПриИзмененииСоставаДелегатов()


//	+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++
//	|                                                                                           |
//	+                           Методы, вызываемые из менеджера событий                         +
//	|                                                                                           |
//	+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++

//******************************************************************************
// Инициализация(ТаблицаПараметров)
//
// Параметры: 
//  ТаблицаПараметров		- параметры текущего делегата
//
// Возвращаемое значение:
//  Число					- успех инициализации (возможность использования делегата)
//
// Описание:
//  Инициализирует класс для использования
//
Функция Инициализация(ТаблицаПараметров) Экспорт
	
	Результат	= БазовыйКласс().Инициализация(ТаблицаПараметров);
	
	Возврат Результат;
КонецФункции // Инициализация()


//******************************************************************************
// Представление(Вариант = 0)
//
// Параметры: 
//  Вариант = 0
//
// Возвращаемое значение:
//  Строка					- пользовательское представление делегата
//
// Описание:
//  Возвращает пользовательское представление делегата
//
Функция Представление(Вариант = 0) Экспорт
	
	Результат	= "Публикация событий контекста";
	
	Возврат Результат;
КонецФункции // Представление()


//******************************************************************************
// Системный()
//
// Параметры: 
//  
//
// Возвращаемое значение:
//  Число
//
// Описание:
//  Флаг системного делегата
//
Функция Системный() Экспорт
	
	Возврат 1;
	
КонецФункции // Системный()


//******************************************************************************
// ПолучитьИдентификаторыСобытий()
//
// Параметры: 
//  
//
// Возвращаемое значение:
//  Строка					- идентификаторы событий через запятую
//
// Описание:
//  Возвращает идентификаторы обрабатываемых событий
//
Функция ПолучитьИдентификаторыСобытий() Экспорт
	
	Результат	= "СозданиеКонтекста, ПриИзмененииСоставаДелегатов";
	
	Возврат Результат;
КонецФункции // ПолучитьИдентификаторыСобытий()


//******************************************************************************
// ПолучитьИдентификаторыКонтекстов()
//
// Параметры: 
//  
//
// Возвращаемое значение:
//  Строка					- список идентификаторов через запятую
//
// Описание:
//  Возвращает список идентификаторов типов обрабатываемых контекстов через запятую
//
Функция ПолучитьИдентификаторыКонтекстов() Экспорт
	
	Результат	= "*";
	
	Возврат Результат;
КонецФункции // ПолучитьИдентификаторыКонтекстов()


//******************************************************************************
// Приоритет()
//
// Параметры: 
//  
//
// Возвращаемое значение:
//  Число					- приоритет вызова делегата
//
// Описание:
//  Возвращает числовой приоритет вызова делегата
//
Функция Приоритет() Экспорт
	
	Результат	= БазовыйКласс().Приоритет();
	
	Возврат Результат;
КонецФункции // Приоритет()


//******************************************************************************
// ОбработатьСобытие(Событие, Параметры, ТекстСсылкиНаДелегата)
//
// Параметры: 
//  Событие					: строка, идентификатор события
//  Параметры				: параметры события
//  ТекстСсылкиНаДелегата	: текст ссылки на глобальный объект класса
//
// Возвращаемое значение:
//  Число					: статус возврата обработки события
//
// Описание:
//  Вызывается менеджером событий при возникновении события, обратываемого классом
//	в контексте обрабатываемого типа
//
Функция ОбработатьСобытие(Событие, Параметры, ТекстСсылкиНаДелегата) Экспорт
	
	//---------------------------------------------------------------------------------------------
	// Возвращаем флаг 
	Результат	= 1;
	
	Если Событие = "СозданиеКонтекста" Тогда
		Результат	= ОбработатьСобытие_СозданиеКонтекста(Параметры);
	ИначеЕсли Событие = "ПриИзмененииСоставаДелегатов" Тогда
		Результат	= ОбработатьСобытие_ПриИзмененииСоставаДелегатов(Параметры);
	КонецЕсли;
	
	Возврат Результат;
КонецФункции // ОбработатьСобытие()

