//	+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++
//	|                           Абстрактный сериализумый объект                                 |
//	+                                      ShmalevoZ                                            +
//	|                                       2009-07                                             |
//	+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++---+++


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


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


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


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

	Возврат Результат;
КонецФункции // ЭтоДинамическийАтрибут()


//******************************************************************************
// ЭтоТипДокумент(Тип)
//
// Параметры: 
//  Тип
//
// Возвращаемое значение:
//  Число
//
// Описание:
//  Проверяет принадлежность типа к документам
//
Функция ЭтоТипДокумент(Тип)
	
	Результат	= ?(Лев(Тип, 8) = "Документ", 1, 0);
	
	Возврат Результат;
КонецФункции // ЭтоТипДокумент()


//******************************************************************************
// ЭтоТипСправочник(Тип)
//
// Параметры: 
//  Тип
//
// Возвращаемое значение:
//  Число
//
// Описание:
//  Проверяет принадлежность типа к справочникам
//
Функция ЭтоТипСправочник(Тип)
	
	Результат	= ?(Лев(Тип, 10) = "Справочник", 1, 0);
	
	Возврат Результат;
КонецФункции // ЭтоТипСправочник()


//******************************************************************************
// ЭтоТипСчет(Тип)
//
// Параметры: 
//  Тип
//
// Возвращаемое значение:
//  Число
//
// Описание:
//  Проверяет принадлежность типа к счетам
//
Функция ЭтоТипСчет(Тип)
	
	Результат	= ?(Лев(Тип, 4) = "Счет", 1, 0);
	
	Возврат Результат;
КонецФункции // ЭтоТипСчет()


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


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


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


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


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


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


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


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


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


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


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


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