///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2024, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область ОписаниеПеременных

&НаКлиенте
Перем ДополнительнаяИнформация;

#КонецОбласти

#Область ОбработчикиСобытийФормы

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	
	ЭтоНовый = Объект.Ссылка.Пустая();
	
	Если ЭтоНовый Тогда
		Параметры.ПоказатьДиалогЗагрузкиИзФайлаПриОткрытии = Истина;
	КонецЕсли;
	
	УстановитьВидимостьДоступность();
	
	Если Не ПравоДоступа("Редактирование", Метаданные.Справочники.ВнешниеКомпоненты) Тогда
		
		Элементы.ФормаОбновитьИзФайла.Видимость = Ложь;
		Элементы.ФормаСохранитьКак.Видимость = Ложь;
		Элементы.ОбновитьСПортала1СИТС.Видимость = Ложь;
	
	КонецЕсли;
	
	Если Не ВнешниеКомпонентыСлужебный.ДоступнаЗагрузкаСПортала() Тогда 
		
		Элементы.ОбновлятьСПортала1СИТС.Видимость = Ложь;
		Элементы.ОбновитьСПортала1СИТС.Видимость = Ложь;
		
	КонецЕсли;
	
КонецПроцедуры

&НаКлиенте
Процедура ПриОткрытии(Отказ)
	
	Если Параметры.ПоказатьДиалогЗагрузкиИзФайлаПриОткрытии Тогда
		ПодключитьОбработчикОжидания("ЗагрузитьКомпонентуИзФайла", 0.1, Истина);
	КонецЕсли;
	
КонецПроцедуры

&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
	
	// Если вызвана команда "Перечитать" необходимо удалить буфер данных компоненты
	Если ЭтоАдресВременногоХранилища(АдресДвоичныхДанныхКомпоненты) Тогда
		УдалитьИзВременногоХранилища(АдресДвоичныхДанныхКомпоненты);
	КонецЕсли;
	
	АдресДвоичныхДанныхКомпоненты = Неопределено;
	УстановитьВидимостьДоступность();
	ЦелевыеПлатформы = ТекущийОбъект.ЦелевыеПлатформы.Получить();
	
КонецПроцедуры

&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
	
	// Если есть двоичные данные компоненты, которые надо сохранить, то помещаем их в ДополнительныеСвойства.
	Если ЭтоАдресВременногоХранилища(АдресДвоичныхДанныхКомпоненты) Тогда
		ДвоичныеДанныеКомпоненты = ПолучитьИзВременногоХранилища(АдресДвоичныхДанныхКомпоненты);
		ТекущийОбъект.ДополнительныеСвойства.Вставить("ДвоичныеДанныеКомпоненты", ДвоичныеДанныеКомпоненты);
	КонецЕсли;
	
	ТекущийОбъект.ЦелевыеПлатформы = Новый ХранилищеЗначения(ЦелевыеПлатформы, Новый СжатиеДанных(9));
	
КонецПроцедуры

&НаСервере
Процедура ПриЗаписиНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
	
	Записана = Истина; // Факт записи свидетельствует положительный результат при закрытии отдельно от записи.
	Параметры.ПоказатьДиалогЗагрузкиИзФайлаПриОткрытии = Ложь; // Избежание закрытия формы при ошибке.
	
КонецПроцедуры

&НаСервере
Процедура ПослеЗаписиНаСервере(ТекущийОбъект, ПараметрыЗаписи)
	
	УстановитьВидимостьДоступность();
	
	ВнешниеКомпонентыСлужебный.ОповеститьВсеСеансыОбИзмененииВнешнейКомпоненты();
	
КонецПроцедуры

&НаКлиенте
Процедура ПередЗакрытием(Отказ, ЗавершениеРаботы, ТекстПредупреждения, СтандартнаяОбработка)
	
	Если ЗавершениеРаботы Тогда 
		Возврат;
	КонецЕсли;
	
	Если Не Модифицированность Тогда
		СтандартнаяОбработка = Ложь;
		
		ПараметрЗакрытия = ВнешниеКомпонентыСлужебныйКлиент.РезультатЗагрузкиКомпоненты();
		ПараметрЗакрытия.Загружена = Записана;
		ПараметрЗакрытия.Идентификатор = Объект.Идентификатор;
		ПараметрЗакрытия.Версия = Объект.Версия;
		ПараметрЗакрытия.Наименование  = Объект.Наименование;
		ПараметрЗакрытия.ДополнительнаяИнформация = ДополнительнаяИнформация;
		
		Закрыть(ПараметрЗакрытия);
	КонецЕсли;	
	
КонецПроцедуры

#КонецОбласти

#Область ОбработчикиСобытийЭлементовШапкиФормы

&НаКлиенте
Процедура ИспользованиеПриИзменении(Элемент)
	
	УстановитьВидимостьДоступность();
	
КонецПроцедуры

&НаКлиенте
Процедура ОбновлятьСПортала1СИТСПриИзменении(Элемент)
	
	УстановитьВидимостьДоступность();
	
КонецПроцедуры

#КонецОбласти

#Область ОбработчикиКомандФормы

&НаКлиенте
Процедура ОбновитьСПортала(Команда)
	
	Если Модифицированность Тогда
		Оповещение = Новый ОписаниеОповещения("ПослеЗакрытияВопросаЗаписатьОбъект", ЭтотОбъект);
		ПоказатьВопрос(Оповещение, 
			НСтр("ru = 'Для проверки обновления запишите изменения. Записать?'"),
			РежимДиалогаВопрос.ДаНет);
	Иначе 
		НачатьОбновлениеКомпонентыСПортала();
	КонецЕсли;
	
КонецПроцедуры

&НаКлиенте
Процедура ОбновитьИзФайла(Команда)
	
	Параметры.ПомещенныйФайл = Неопределено;
	ОчиститьСообщения();
	ЗагрузитьКомпонентуИзФайла();
	
КонецПроцедуры

&НаКлиенте
Процедура СохранитьКак(Команда)
	
	Если ЭтоАдресВременногоХранилища(АдресДвоичныхДанныхКомпоненты) Тогда
		ПоказатьПредупреждение(, НСтр("ru = 'Перед сохранением компоненты в файл запишите элемент справочника.'"));
	Иначе 
		ОчиститьСообщения();
		ВнешниеКомпонентыСлужебныйКлиент.СохранитьКомпонентуВФайл(Объект.Ссылка);
	КонецЕсли;
	
КонецПроцедуры

&НаКлиенте
Процедура ПоддерживаемыеКлиентскиеПриложения(Команда)

	ПараметрыФормы = Новый Структура;
	ПараметрыФормы.Вставить("ПоддерживаемыеКлиенты", ЦелевыеПлатформы);
	
	ОткрытьФорму("ОбщаяФорма.ПоддерживаемыеКлиентскиеПриложения", ПараметрыФормы);
	
КонецПроцедуры

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

#Область КлиентскаяЛогика

&НаКлиенте
Процедура ЗагрузитьКомпонентуИзФайла()
	
	Если Параметры.ПомещенныйФайл <> Неопределено Тогда
		ЗагрузитьКомпонентуПослеПомещенияФайла(Параметры.ПомещенныйФайл, Неопределено);
		Возврат;
	КонецЕсли;
	
	Оповещение = Новый ОписаниеОповещения("ЗагрузитьКомпонентуПослеПредупрежденияБезопасности", ЭтотОбъект);
	ПользователиСлужебныйКлиент.ПоказатьПредупреждениеБезопасности(Оповещение,
		ПользователиСлужебныйКлиентСервер.ВидыПредупрежденийБезопасности().ПередДобавлениемВнешнейКомпоненты);
	
КонецПроцедуры

// Продолжение процедуры ЗагрузитьКомпонентуИзФайла.
&НаКлиенте
Процедура ЗагрузитьКомпонентуПослеПредупрежденияБезопасности(Ответ, Контекст) Экспорт
	
	// Ответ: 
	// - "Продолжить" - Загрузить.
	// - КодВозвратаДиалога.Отмена - Отклонить.
	// - Неопределено - Закрыто окно.
	Если Ответ <> "Продолжить" Тогда
		ЗагрузитьКомпонентуПриОтображенииОшибки();
		Возврат;
	КонецЕсли;
	
	Оповещение = Новый ОписаниеОповещения("ЗагрузитьКомпонентуПослеПомещенияФайла", ЭтотОбъект, Контекст);
	ПараметрыЗагрузки = ФайловаяСистемаКлиент.ПараметрыЗагрузкиФайла();
	
	ПараметрыЗагрузки.Диалог.Фильтр    = НСтр("ru = 'Внешняя компонента (*.zip)|*.zip'")+"|"
			+ СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Все файлы (%1)|%1'"), ПолучитьМаскуВсеФайлы());
	ПараметрыЗагрузки.Диалог.Заголовок = НСтр("ru = 'Выберите файл внешней компоненты'");
	ПараметрыЗагрузки.ИдентификаторФормы = УникальныйИдентификатор;
	ФайловаяСистемаКлиент.ЗагрузитьФайл(Оповещение, ПараметрыЗагрузки, Объект.ИмяФайла);

КонецПроцедуры

// Продолжение процедуры ЗагрузитьКомпонентуИзФайла.
&НаКлиенте
Процедура ЗагрузитьКомпонентуПослеПомещенияФайла(ПомещенныйФайл, Контекст) Экспорт
	
	Если ПомещенныйФайл = Неопределено Тогда
		ЗагрузитьКомпонентуПриОтображенииОшибки(НСтр("ru = 'Не удалось загрузить файл компоненты.'"));
		Возврат;
	КонецЕсли;
	
	ПараметрыЗагрузки = Новый Структура;
	ПараметрыЗагрузки.Вставить("АдресХранилищаФайла", ПомещенныйФайл.Хранение);
	ПараметрыЗагрузки.Вставить("ИмяФайла",            ТолькоИмяФайла(ПомещенныйФайл.Имя));
	
	Результат = ЗагрузитьКомпонентуИзФайлаНаСервере(ПараметрыЗагрузки);
	Если Результат.Загружена И ЭтоАдресВременногоХранилища(АдресДвоичныхДанныхКомпоненты)Тогда
		ДополнительнаяИнформация = Результат.ДополнительнаяИнформация;
		Модифицированность = Истина;
	Иначе 
		ЗагрузитьКомпонентуПриОтображенииОшибки(Результат.ОписаниеОшибки, Результат.ИнформацияОбОшибке);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ЗагрузитьКомпонентуИзФайла.
&НаКлиенте
Процедура ЗагрузитьКомпонентуПриОтображенииОшибки(ОписаниеОшибки = "", ИнформацияОбОшибке = Неопределено)
	
	Если ПустаяСтрока(ОписаниеОшибки) Тогда 
		ЗагрузитьКомпонентуПослеОтображенияОшибки(Неопределено);
	Иначе 
		Оповещение = Новый ОписаниеОповещения("ЗагрузитьКомпонентуПослеОтображенияОшибки", ЭтотОбъект);
		
		СтрокаСПредупреждением = НСтр("ru = '%1
			|Укажите zip-архив с внешней компонентой.
			|Подробнее см. <a href = ""%2"">Технология создания внешних компонент</a>'")
			+ ?(ИнформацияОбОшибке = Неопределено, "",
				Символы.ПС + ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
		
		СтрокаСПредупреждением = СтроковыеФункцииКлиент.ФорматированнаяСтрока(СтрокаСПредупреждением, ОписаниеОшибки,
			"https://its.1c.eu/db/metod8dev/content/3221");
		
		ПоказатьПредупреждение(Оповещение, СтрокаСПредупреждением);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ЗагрузитьКомпонентуИзФайла.
&НаКлиенте
Процедура ЗагрузитьКомпонентуПослеОтображенияОшибки(ДополнительныеПараметры) Экспорт
	
	// Открыта через программный интерфейс.
	Если Параметры.ПоказатьДиалогЗагрузкиИзФайлаПриОткрытии Тогда 
		Закрыть();
	КонецЕсли;
	
КонецПроцедуры

&НаКлиенте
Процедура ПослеЗакрытияВопросаЗаписатьОбъект(РезультатВопроса, Контекст) Экспорт 
	
	Если РезультатВопроса = КодВозвратаДиалога.Да Тогда 
		Записать();
		НачатьОбновлениеКомпонентыСПортала();
	КонецЕсли;
	
КонецПроцедуры

&НаКлиенте
Процедура НачатьОбновлениеКомпонентыСПортала()
	
	ЭтоНовый = Объект.Ссылка.Пустая();
	Если ЭтоНовый Тогда 
		Возврат;
	КонецЕсли;
	
	РазблокироватьДанныеФормыДляРедактирования();
	
	ОбновляемыеКомпоненты = Новый Массив;
	ОбновляемыеКомпоненты.Добавить(Объект.Ссылка);
	
	Оповещение = Новый ОписаниеОповещения("ПослеОбновленияКомпонентыСПортала", ЭтотОбъект);
	ВнешниеКомпонентыСлужебныйКлиент.ОбновитьКомпонентыСПортала(Оповещение, ОбновляемыеКомпоненты);
	
КонецПроцедуры

&НаКлиенте
Процедура ПослеОбновленияКомпонентыСПортала(Результат, ДополнительныеПараметры) Экспорт
	
	ОбновитьКарточкуПослеОбновленияКомпонентыСПортала();
	
КонецПроцедуры

#КонецОбласти

#Область СервернаяЛогика

// Серверная логика процедуры ЗагрузитьКомпонентуИзФайла.
&НаСервере
Функция ЗагрузитьКомпонентуИзФайлаНаСервере(Знач ПараметрыЗагрузки)
	
	Если Не Пользователи.ЭтоПолноправныйПользователь(,, Ложь) Тогда
		ВызватьИсключение(НСтр("ru = 'Недостаточно прав для загрузки компоненты.'"), КатегорияОшибки.НарушениеПравДоступа);
	КонецЕсли;
	
	ОбъектСправочника = РеквизитФормыВЗначение("Объект");
	
	ДвоичныеДанные = ПолучитьИзВременногоХранилища(ПараметрыЗагрузки.АдресХранилищаФайла);
	Информация = ВнешниеКомпонентыСлужебный.ИнформацияОКомпонентеИзФайла(ДвоичныеДанные,, 
		Параметры.ПараметрыПоискаДополнительнойИнформации);
	
	Результат = РезультатЗагрузкиКомпоненты();
	
	Если Не Информация.Разобрано Тогда 
		Результат.ОписаниеОшибки = Информация.ОписаниеОшибки;
		Результат.ИнформацияОбОшибке = Информация.ИнформацияОбОшибке;
		Возврат Результат;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ОбъектСправочника.Идентификатор)
		И ЗначениеЗаполнено(Информация.Реквизиты.Идентификатор) Тогда 
		
		Если ОбъектСправочника.Идентификатор <> Информация.Реквизиты.Идентификатор Тогда 
			Результат.ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Невозможно обновить компоненту, т.к. различаются идентификаторы.
					|Ожидался %1, а идентификатор загружаемой внешней компоненты: %2.'"),
				ОбъектСправочника.Идентификатор, Информация.Реквизиты.Идентификатор);
			Возврат Результат;
		КонецЕсли;
		
	КонецЕсли;
	
	ЗаполнитьЗначенияСвойств(ОбъектСправочника, Информация.Реквизиты,, "Идентификатор"); // По данным манифеста.
	ЦелевыеПлатформы = Информация.Реквизиты.ЦелевыеПлатформы;
	
	Если Не ЗначениеЗаполнено(ОбъектСправочника.Идентификатор) Тогда 
		ОбъектСправочника.Идентификатор = Информация.Реквизиты.Идентификатор;
	КонецЕсли;
	ОбъектСправочника.ИмяФайла =  ПараметрыЗагрузки.ИмяФайла;          // Установка имени файла.
	АдресДвоичныхДанныхКомпоненты = ПоместитьВоВременноеХранилище(Информация.ДвоичныеДанные,
		УникальныйИдентификатор);
	
	ОбъектСправочника.ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Загружена из файла %1. %2.'"),
		ОбъектСправочника.ИмяФайла,
		ТекущаяДатаСеанса());
	
	ЗначениеВРеквизитФормы(ОбъектСправочника, "Объект");
	
	Модифицированность = Истина;
	УстановитьВидимостьДоступность();
	
	Результат.Загружена = Истина;
	Результат.ДополнительнаяИнформация = Информация.ДополнительнаяИнформация;
	Возврат Результат;
	
КонецФункции

&НаКлиентеНаСервереБезКонтекста
Функция РезультатЗагрузкиКомпоненты()
	
	Результат = Новый Структура;
	Результат.Вставить("Загружена", Ложь);
	Результат.Вставить("ОписаниеОшибки", "");
	Результат.Вставить("ИнформацияОбОшибке", Неопределено);
	Результат.Вставить("ДополнительнаяИнформация", Новый Соответствие);
	
	Возврат Результат;
	
КонецФункции

// Серверная логика обновления компоненты с сайта.
&НаСервере
Процедура ОбновитьКарточкуПослеОбновленияКомпонентыСПортала()
	
	Прочитать();
	Модифицированность = Ложь;
	УстановитьВидимостьДоступность();
	
КонецПроцедуры

#КонецОбласти

#Область Представление

&НаСервере
Процедура УстановитьВидимостьДоступность()
	
	СправочникОбъект = РеквизитФормыВЗначение("Объект");
	ЭтоНовый = Объект.Ссылка.Пустая();
	
	Элементы.Информация.Видимость = ЗначениеЗаполнено(Объект.ОписаниеОшибки);
	
	// Параметры отображения предупреждений при редактировании
	ОтображатьПредупреждение = ОтображениеПредупрежденияПриРедактировании.Отображать;
	НеОтображатьПредупреждение = ОтображениеПредупрежденияПриРедактировании.НеОтображать;
	Если ЗначениеЗаполнено(Объект.Наименование) Тогда
		Элементы.Наименование.ОтображениеПредупрежденияПриРедактировании = ОтображатьПредупреждение;
	Иначе
		Элементы.Наименование.ОтображениеПредупрежденияПриРедактировании = НеОтображатьПредупреждение;
	КонецЕсли;
	Если ЗначениеЗаполнено(Объект.Идентификатор) Тогда 
		Элементы.Идентификатор.ОтображениеПредупрежденияПриРедактировании = ОтображатьПредупреждение;
	Иначе 
		Элементы.Идентификатор.ОтображениеПредупрежденияПриРедактировании = НеОтображатьПредупреждение;
	КонецЕсли;
	Если ЗначениеЗаполнено(Объект.Версия) Тогда 
		Элементы.Версия.ОтображениеПредупрежденияПриРедактировании = ОтображатьПредупреждение;
	Иначе 
		Элементы.Версия.ОтображениеПредупрежденияПриРедактировании = НеОтображатьПредупреждение;
	КонецЕсли;
	
	// Доступность кнопки Сохранить в файл
	Элементы.ФормаСохранитьКак.Доступность = Не ЭтоНовый;
	
	// Зависимость использования и автоматического обновления.
	КомпонентаОтключена = (Объект.Использование = Перечисления.ВариантыИспользованияВнешнихКомпонент.Отключена);
	Элементы.ОбновлятьСПортала1СИТС.Доступность = Не КомпонентаОтключена И СправочникОбъект.ЭтоКомпонентаПоследнейВерсии();
	
	Элементы.ОбновитьСПортала1СИТС.Доступность = Объект.ОбновлятьСПортала1СИТС;
	
КонецПроцедуры

#КонецОбласти

#Область Прочее

&НаКлиенте
Функция ТолькоИмяФайла(ВыбранноеИмяФайла)
	
	// Использовать критично на клиенте, т.к. ПолучитьРазделительПути() на сервере может быть другим.
	МассивПодстрок = СтрРазделить(ВыбранноеИмяФайла, ПолучитьРазделительПути(), Ложь);
	Возврат МассивПодстрок.Получить(МассивПодстрок.ВГраница());
	
КонецФункции

#КонецОбласти

#КонецОбласти