//	+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++
//	|     Обработка перехваченных событий поступивших из сети при помощи компоненты netainet    |
//	+                                        ShmalevoZ                                          +
//	|                                         2008-01                                           |
//	+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++

Перем гСерверСообщений;
Перем гСерверСообщенийАдрес, гСерверСообщенийПорт;
Перем гРасположениеСведенийОбСервере;
Перем гРасположениеОбработкиОтправки, гПараметрыОбработкиОтправки;
Перем гСообщенияОжидающиеОтвета;

Перем гКонтекстФормыОтправки	Экспорт;


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


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


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


//******************************************************************************
// СоздатьСервер()
//
// Параметры: 
//  
//
// Возвращаемое значение:
//  Нет
//
// Описание:
//  ТекстОписания
//
Функция СоздатьСервер()
	
	//---------------------------------------------------------------------------------------------
	// Для работы необходима внешняя компонента netainet
	Результат	= ЗагрузитьВнешнююКомпоненту("netainet.dll");
	
	Если Результат = 1 Тогда
		гСерверСообщений				= СоздатьОбъект("AddIn.netaInet");
		гСерверСообщенийАдрес			= гСерверСообщений.ПолучитьТекущийIPАдрес();
		
		НомерДоступногоПортаНачало		= 6711;
		НомерДоступногоПортаОкончания	= 6832;
		Результат						= 0;
		
		Для НомерПорта = НомерДоступногоПортаНачало По НомерДоступногоПортаОкончания Цикл
			Если гСерверСообщений.СоздатьПодключение(НомерПорта, 2, 2, 7) = 1 Тогда
				Результат	= 1;
				Прервать;
			КонецЕсли;
		КонецЦикла;
		
		Если Результат = 1 Тогда
			гСерверСообщенийПорт	= НомерПорта;
			
			гРасположениеСведенийОбСервере	= КаталогИБ() + "user_" + СтрЗаменить(гСерверСообщенийАдрес, ".", "_") + "_" + гСерверСообщенийПорт + ".info";
			//---------------------------------------------------------------------------------------------
			// Заранее позаботимся об исключении дублирующих файлов сведений о подключенных машинах :
			// такое наблюдается, если например пользователь снял задачу
			УдалитьСведенияОПодключении();

			// и сразу опубликуем сведения о созданном сервере
			Информатор	= СоздатьОбъект("Текст");
			Информатор.ДобавитьСтроку("[Сервер]");
			Информатор.ДобавитьСтроку("Адрес=" + гСерверСообщенийАдрес);
			Информатор.ДобавитьСтроку("Порт=" + гСерверСообщенийПорт);
			Информатор.ДобавитьСтроку("ИмяКомпьютера=" + ИмяКомпьютера());
			Информатор.Записать(гРасположениеСведенийОбСервере);
		КонецЕсли;
	КонецЕсли;
	
	Возврат Результат;
КонецФункции // СоздатьСервер()


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


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


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


//******************************************************************************
// Конструктор()
//
// Параметры: 
//  
//
// Возвращаемое значение:
//  Нет
//
// Описание:
//  ТекстОписания
//
Процедура Конструктор()
	
	Если _this().ПараметрДелегата_НеИспользовать = 0 Тогда
		РасположениеРеализации	= _this().ПолучитьПуть();
		РасположениеОбработки	= "";
		Позиция					= Найти(РасположениеРеализации, "\");
		Пока Позиция <> 0 Цикл
			РасположениеОбработки	= РасположениеОбработки + Лев(РасположениеРеализации, Позиция);
			РасположениеРеализации	= Прав(РасположениеРеализации, СтрДлина(РасположениеРеализации) - Позиция);
			Позиция					= Найти(РасположениеРеализации, "\");
		КонецЦикла;
		
		гРасположениеОбработкиОтправки	= РасположениеОбработки + "netamsg.ert";
		
		гСообщенияОжидающиеОтвета		= СоздатьОбъект("СписокЗначений");
		
		СоздатьСервер();
	КонецЕсли;
	
КонецПроцедуры // Конструктор()


//******************************************************************************
// Деструктор()
//
// Параметры: 
//  
//
// Возвращаемое значение:
//  Нет
//
// Описание:
//  ТекстОписания
//
Процедура Деструктор()
	
	ОбработатьСобытие_ПриЗавершенииРаботыСистемы();
	
КонецПроцедуры // Деструктор()


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


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


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


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


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


//	+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++
//	|                                                                                           |
//	+                      Собственные общедоступные методы                                     +
//	|                                                                                           |
//	+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++

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


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


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


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