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

#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда

#Область ПрограммныйИнтерфейс

#Область ДляВызоваИзДругихПодсистем

// СтандартныеПодсистемы.ГрупповоеИзменениеОбъектов

// Возвращает реквизиты объекта, которые разрешается редактировать
// с помощью обработки группового изменения реквизитов.
//
// Возвращаемое значение:
//  Массив из Строка
//
Функция РеквизитыРедактируемыеВГрупповойОбработке() Экспорт
	
	Возврат РаботаСФайлами.РеквизитыРедактируемыеВГрупповойОбработке();
	
КонецФункции

// Конец СтандартныеПодсистемы.ГрупповоеИзменениеОбъектов

// СтандартныеПодсистемы.УправлениеДоступом

// Параметры:
//   Ограничение - см. УправлениеДоступомПереопределяемый.ПриЗаполненииОграниченияДоступа.Ограничение.
//
Процедура ПриЗаполненииОграниченияДоступа(Ограничение) Экспорт
	
	Ограничение.Текст =
	"РазрешитьЧтение
	|ГДЕ
	|	ЧтениеОбъектаРазрешено(ВладелецФайла)
	|;
	|РазрешитьИзменениеЕслиРазрешеноЧтение
	|ГДЕ
	|	ИзменениеОбъектаРазрешено(ВладелецФайла)";
	
	Ограничение.ТекстДляВнешнихПользователей =
	"РазрешитьЧтение
	|ГДЕ
	|	ВЫБОР 
	|		КОГДА ТипЗначения(ВладелецФайла) = Тип(Справочник.ПапкиФайлов)
	|			ТОГДА ЧтениеОбъектаРазрешено(ВЫРАЗИТЬ(ВладелецФайла КАК Справочник.ПапкиФайлов))
	|		ИНАЧЕ ЗначениеРазрешено(ВЫРАЗИТЬ(Автор КАК Справочник.ВнешниеПользователи))
	|	КОНЕЦ
	|;
	|РазрешитьИзменениеЕслиРазрешеноЧтение
	|ГДЕ
	|	ВЫБОР 
	|		КОГДА ТипЗначения(ВладелецФайла) = Тип(Справочник.ПапкиФайлов)
	|			ТОГДА ИзменениеОбъектаРазрешено(ВЫРАЗИТЬ(ВладелецФайла КАК Справочник.ПапкиФайлов))
	|		ИНАЧЕ ЗначениеРазрешено(ВЫРАЗИТЬ(Автор КАК Справочник.ВнешниеПользователи))
	|	КОНЕЦ";
	Ограничение.ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей = Ложь;
	
КонецПроцедуры

// Конец СтандартныеПодсистемы.УправлениеДоступом

// СтандартныеПодсистемы.ПодключаемыеКоманды

// Определяет список команд создания на основании.
//
// Параметры:
//  КомандыСозданияНаОсновании - см. СозданиеНаОснованииПереопределяемый.ПередДобавлениемКомандСозданияНаОсновании.КомандыСозданияНаОсновании
//  Параметры - см. СозданиеНаОснованииПереопределяемый.ПередДобавлениемКомандСозданияНаОсновании.Параметры
//
Процедура ДобавитьКомандыСозданияНаОсновании(КомандыСозданияНаОсновании, Параметры) Экспорт
	
КонецПроцедуры

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

// Конец СтандартныеПодсистемы.ПодключаемыеКоманды

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

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

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

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

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

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

Процедура ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию(Параметры) Экспорт
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ ПЕРВЫЕ 1000
		|	Файлы.Ссылка КАК Ссылка
		|ИЗ
		|	Справочник.Файлы КАК Файлы
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СведенияОФайлах КАК СведенияОФайлах
		|		ПО Файлы.Ссылка = СведенияОФайлах.Файл
		|ГДЕ
		|	Файлы.Ссылка > &Ссылка
		|	И (Файлы.ТипХраненияФайла = ЗНАЧЕНИЕ(Перечисление.ТипыХраненияФайлов.ВТомахНаДиске)
		|	ИЛИ ((Файлы.ДатаМодификацииУниверсальная = ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0)
		|					И Файлы.ТекущаяВерсия <> ЗНАЧЕНИЕ(Справочник.ВерсииФайлов.ПустаяСсылка)
		|				ИЛИ Файлы.ТипХраненияФайла = ЗНАЧЕНИЕ(Перечисление.ТипыХраненияФайлов.ПустаяСсылка))
		|			ИЛИ СведенияОФайлах.Файл ЕСТЬ NULL))
		|
		|УПОРЯДОЧИТЬ ПО
		|	Ссылка";
	
	ОтработаныВсеФайлы = Ложь;
	Ссылка = "";
	
	ПараметрыВыборки = Параметры.ПараметрыВыборки;
	ПараметрыВыборки.ПолныеИменаОбъектов = "Справочник.Файлы";
	ПараметрыВыборки.СпособВыборки = ОбновлениеИнформационнойБазы.СпособВыборкиСсылки();
	
	Пока Не ОтработаныВсеФайлы Цикл
		
		Запрос.УстановитьПараметр("Ссылка", Ссылка);
		// @skip-check query-in-loop - Порционная обработка большого объема данных.
		МассивСсылок = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
		
		ОбновлениеИнформационнойБазы.ОтметитьКОбработке(Параметры, МассивСсылок);
		
		КоличествоСсылок = МассивСсылок.Количество();
		Если КоличествоСсылок < 1000 Тогда
			ОтработаныВсеФайлы = Истина;
		ИначеЕсли КоличествоСсылок > 0 Тогда
			Ссылка = МассивСсылок[КоличествоСсылок - 1];
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

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

	ЗаписьЖурналаРегистрации(ОбновлениеИнформационнойБазы.СобытиеЖурналаРегистрации(), 
		УровеньЖурналаРегистрации.Информация, , ,
		СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Обработана очередная порция файлов: %1'"),
			ОбъектовОбработано));
	Параметры.ОбработкаЗавершена = ОбновлениеИнформационнойБазы.ОбработкаДанныхЗавершена(Параметры.Очередь, "Справочник.Файлы");
	
КонецПроцедуры

Функция ОбработатьФайл(Ссылка)
	
	Результат = Истина;
	ПредставлениеСсылки = Строка(Ссылка);
	
	БлокировкаДанныхФайл = Новый БлокировкаДанных;
	ЭлементБлокировкиДанных = БлокировкаДанныхФайл.Добавить("Справочник.Файлы");
	ЭлементБлокировкиДанных.УстановитьЗначение("Ссылка", Ссылка);
	
	НачатьТранзакцию();
	Попытка
		БлокировкаДанныхФайл.Заблокировать();
		
		ОбновляемыйФайл = Неопределено;
		ТребуетсяЗаписать = Ложь;
		// @skip-check query-in-loop - Порционная обработка большого объема данных.
		РеквизитыФайла = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Ссылка, 
			"ДатаМодификацииУниверсальная,ТекущаяВерсия,ТипХраненияФайла");
			
		Если ЗначениеЗаполнено(РеквизитыФайла.ТекущаяВерсия) 
			И (Не ЗначениеЗаполнено(РеквизитыФайла.ДатаМодификацииУниверсальная)
				Или Не ЗначениеЗаполнено(РеквизитыФайла.ТипХраненияФайла)) Тогда
			
			ОбновляемыйФайл = Ссылка.ПолучитьОбъект(); // СправочникОбъект.Файлы
			Если ОбновляемыйФайл = Неопределено Тогда
				ОбновлениеИнформационнойБазы.ОтметитьВыполнениеОбработки(Ссылка);
				ЗафиксироватьТранзакцию();
				Возврат Результат;
			КонецЕсли;

			// @skip-check query-in-loop - Порционная обработка большого объема данных.
			РеквизитыТекущейВерсии = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(РеквизитыФайла.ТекущаяВерсия, 
				"ДатаМодификацииУниверсальная,ТипХраненияФайла");
			ОбновляемыйФайл.ДатаМодификацииУниверсальная = РеквизитыТекущейВерсии.ДатаМодификацииУниверсальная;
			ОбновляемыйФайл.ТипХраненияФайла             = РеквизитыТекущейВерсии.ТипХраненияФайла;
			
			НаборЗаписей = РегистрыСведений.СведенияОФайлах.СоздатьНаборЗаписей();
			НаборЗаписей.Отбор.Файл.Установить(Ссылка);
			НаборЗаписей.Прочитать();
			Если НаборЗаписей.Количество() = 0 Тогда
				СведенияОФайле = НаборЗаписей.Добавить();
				ЗаполнитьЗначенияСвойств(СведенияОФайле, ОбновляемыйФайл);
				СведенияОФайле.Файл          = ОбновляемыйФайл.Ссылка;
				СведенияОФайле.Автор         = ОбновляемыйФайл.Автор;
				СведенияОФайле.ВладелецФайла = ОбновляемыйФайл.ВладелецФайла;
				
				Если ОбновляемыйФайл.ПодписанЭП И ОбновляемыйФайл.Зашифрован Тогда
					СведенияОФайле.НомерКартинкиПодписанЗашифрован = 2;
				ИначеЕсли ОбновляемыйФайл.Зашифрован Тогда
					СведенияОФайле.НомерКартинкиПодписанЗашифрован = 1;
				ИначеЕсли ОбновляемыйФайл.ПодписанЭП Тогда
					СведенияОФайле.НомерКартинкиПодписанЗашифрован = 0;
				Иначе
					СведенияОФайле.НомерКартинкиПодписанЗашифрован = -1;
				КонецЕсли;
				ОбновлениеИнформационнойБазы.ЗаписатьНаборЗаписей(НаборЗаписей);
			КонецЕсли;
			ТребуетсяЗаписать = Истина;
		КонецЕсли;
		
		Если РеквизитыФайла.ТипХраненияФайла = Перечисления.ТипыХраненияФайлов.ВТомахНаДиске Тогда

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

КонецФункции	

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

#КонецЕсли

