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

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

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

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

Функция НайтиТекстВСтроке(Знач Строка, Знач Текст, Шрифт, Цвет, ПоискСУчетомУровней) Экспорт
	
	Результат = Новый Структура("ФорматированнаяСтрока, Вес, СоответствуетОтбору", Неопределено, 0, Ложь);
	
	Если СтрНайти(Строка.ПутьКДанным, ".Удалить") > 0 Тогда
		Возврат Результат;
	КонецЕсли;
	
	НачалоПредставленияПути = 0;
	
	Если ПоискСУчетомУровней Тогда
		Если ТипЗнч(Строка) = Тип("ДанныеФормыЭлементДерева") Тогда
			Родитель = Строка.ПолучитьРодителя();
		ИначеЕсли ТипЗнч(Строка) = Тип("СтрокаДереваЗначений") Тогда
			Родитель = Строка.Родитель;
		КонецЕсли;
		
		Если Родитель <> Неопределено Тогда
			НачалоПредставленияПути = СтрДлина(Родитель.ПредставлениеПутиКДанным)+1;
			СтрокаПоиска = Сред(Строка.ПредставлениеПутиКДанным, НачалоПредставленияПути+1);
		Иначе
			СтрокаПоиска = Строка.ПредставлениеПутиКДанным;
		КонецЕсли;
	Иначе
		СтрокаПоиска = Строка.ПредставлениеПутиКДанным;
	КонецЕсли;
	СтрокаПредставленияПоиска = Строка.ПредставлениеПутиКДанным;
	ТекущаяСтрокаПредставленияПоиска = СтрокаПредставленияПоиска;
	ТекущаяСтрокаПоиска = СтрокаПоиска;
	МаксимальнаяДлиннаСтрокиПоиска = 1024;
	МаксимальнаяДлиннаСлова = 150;
	ДлиннаТекущейСтрокиПоиска = СтрДлина(ТекущаяСтрокаПредставленияПоиска);
	
	Вес = 0;
	ФорматированныеСтроки = Новый Массив;
	СловаПоиска = СтрРазделить(Текст, " ", Ложь);
	
	Если СловаПоиска.Количество() > 0 Тогда
		ВесСлова = 1/СловаПоиска.Количество();
	КонецЕсли;
	
	ВесУровня = 20;
	ВесПолноеСовпадение = 12;
	ВесСловоЦеликом = 7;
	ВесКоличестваВхождений = 4;
	ВесБлизостиКНачалуСтроки = 2;
	ВесБлизостиКНачалуСлова = 1;
	
	РазделителиСлов = Новый Соответствие;
	РазделителиСлов.Вставить(" ", Истина);
	РазделителиСлов.Вставить(".", Истина);
	
	ПозицияСНачалаСтроки = 0;
	Для Каждого Подстрока Из СловаПоиска Цикл
		Позиция = СтрНайти(НРег(ТекущаяСтрокаПоиска), НРег(Подстрока));
		Если Позиция = 0 Тогда
			ФорматированныеСтроки = Неопределено;
			Результат.СоответствуетОтбору = Ложь;
			Прервать;
		КонецЕсли;
		ДлиннаПодстрокиПоиска = СтрДлина(Подстрока);
		ЧислоВхождений = СтрЧислоВхождений(НРег(ТекущаяСтрокаПоиска), НРег(Подстрока));
		
		Если НРег(СтрокаПоиска) = НРег(Подстрока) Тогда
			Вес = Вес + ВесСлова * ВесПолноеСовпадение;
		КонецЕсли;
		
		ТекущаяСтрокаПоиска = Сред(ТекущаяСтрокаПоиска, Позиция + ДлиннаПодстрокиПоиска);
		ПозицияСНачалаСтроки = ПозицияСНачалаСтроки + Позиция;
		Позиция = СтрНайти(НРег(ТекущаяСтрокаПредставленияПоиска), НРег(Подстрока),,НачалоПредставленияПути + Позиция);
		НачалоПредставленияПути = 0;
		
		ПодстрокаДоВхождения = Лев(ТекущаяСтрокаПредставленияПоиска, Позиция - 1);
		Вес = Вес + (5 - ЧислоВхождений)/4 * ВесСлова * ВесКоличестваВхождений;
		
		Для НомерВхождения = 1 По ЧислоВхождений Цикл
			Вес = Вес + (1 - (ПозицияСНачалаСтроки-1)/МаксимальнаяДлиннаСтрокиПоиска) * ВесСлова * ВесБлизостиКНачалуСтроки / ЧислоВхождений;
			Если (ПозицияСНачалаСтроки = 1 Или РазделителиСлов[Сред(СтрокаПредставленияПоиска, ПозицияСНачалаСтроки - 1, 1)] = Истина)
				И (ПозицияСНачалаСтроки + ДлиннаПодстрокиПоиска = ДлиннаТекущейСтрокиПоиска +1
					Или РазделителиСлов[Сред(СтрокаПредставленияПоиска, ПозицияСНачалаСтроки + ДлиннаПодстрокиПоиска, 1)] = Истина) Тогда
				Вес = Вес + ВесСлова * ВесСловоЦеликом / ЧислоВхождений;
			КонецЕсли;
			
			ПозицияНачалаСлова = 0;
			Для Каждого РазделительСлов Из РазделителиСлов Цикл
				ПозицияНачалаСлова = Макс(ПозицияНачалаСлова, 
					СтрНайти(СтрокаПредставленияПоиска, РазделительСлов.Ключ, НаправлениеПоиска.СКонца, ПозицияСНачалаСтроки));
			КонецЦикла;
			Вес = Вес + (1 - ПозицияНачалаСлова/МаксимальнаяДлиннаСлова) * ВесСлова * ВесБлизостиКНачалуСлова / ЧислоВхождений;
		КонецЦикла;
		
		ПодстрокаВхождения = Сред(ТекущаяСтрокаПредставленияПоиска, Позиция, СтрДлина(Подстрока));
		ТекущаяСтрокаПредставленияПоиска = Сред(ТекущаяСтрокаПредставленияПоиска, Позиция + ДлиннаПодстрокиПоиска);
		Результат.СоответствуетОтбору = Истина;
		ФорматированныеСтроки.Добавить(ПодстрокаДоВхождения);
		ФорматированныеСтроки.Добавить(Новый ФорматированнаяСтрока(ПодстрокаВхождения,
			Шрифт, Цвет));
	КонецЦикла;
	
	Если Не Результат.СоответствуетОтбору Тогда
		Возврат Результат;
	КонецЕсли;
	Результат.Вес = Вес + (10 - СтрРазделить(Строка.ПутьКДанным, ".").Количество()) * ВесУровня;
	ФорматированныеСтроки.Добавить(ТекущаяСтрокаПоиска);
	Результат.ФорматированнаяСтрока = Новый ФорматированнаяСтрока(ФорматированныеСтроки); // АПК:1356 - можно использовать составную форматированную строку, так как массив строк формируется из переданного в функцию текста.
	
	Возврат Результат;
	
КонецФункции

Процедура СортироватьПоКолонке(ДеревоПолей, Колонка, Направление = Неопределено) Экспорт
	Сортировка = Новый СписокЗначений;
	ИндексПоЗначениям = Новый Соответствие;
	
	ЭлементыДерева = ДеревоПолей.ПолучитьЭлементы();
	
	Для Каждого Элемент Из ЭлементыДерева Цикл
		Значение = Элемент[Колонка];
		
		СтрокиЗначения = ИндексПоЗначениям[Значение];
		Если СтрокиЗначения = Неопределено Тогда
			СтрокиЗначения = Новый Массив;
			ИндексПоЗначениям.Вставить(Значение, СтрокиЗначения);
			Сортировка.Добавить(Значение);
		КонецЕсли;
		СтрокиЗначения.Добавить(Элемент);
		СортироватьПоКолонке(Элемент, Колонка);
	КонецЦикла;
	
	Сортировка.СортироватьПоЗначению(?(Направление = Неопределено, НаправлениеСортировки.Убыв, Направление));
	
	НовыйИндекс = 0;
	Для Каждого ЭлементСортировки Из Сортировка Цикл
		
		СтрокиЗначения = ИндексПоЗначениям.Получить(ЭлементСортировки.Значение);
		Для Каждого ТекущаяСтрока Из СтрокиЗначения Цикл
			
			ТекущийИндекс = ЭлементыДерева.Индекс(ТекущаяСтрока);
			ШагСдвига = НовыйИндекс - ТекущийИндекс;
			Если НЕ ШагСдвига = 0 Тогда
				ЭлементыДерева.Сдвинуть(ТекущийИндекс, ШагСдвига);
			КонецЕсли;
			
			НовыйИндекс = НовыйИндекс + 1;
			
		КонецЦикла;
		
	КонецЦикла;
	
КонецПроцедуры

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

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