package ru.hflabs.rcd.web.controller.rule;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import ru.hflabs.rcd.model.document.Field;
import ru.hflabs.rcd.model.rule.RecodeRule;
import ru.hflabs.rcd.model.rule.RecodeRuleSet;
import ru.hflabs.rcd.service.document.IFieldService;
import ru.hflabs.rcd.service.rule.IRecodeRuleService;
import ru.hflabs.rcd.service.rule.IRecodeRuleSetService;
import ru.hflabs.rcd.web.controller.ControllerTemplate;
import ru.hflabs.rcd.web.model.rule.RecodeRuleRequestBean;
import ru.hflabs.rcd.web.model.rule.RecodeRuleResponseBean;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import static ru.hflabs.rcd.accessor.Accessors.FROM_RULE_INJECTOR;
import static ru.hflabs.rcd.accessor.Accessors.TO_RULE_INJECTOR;
import static ru.hflabs.rcd.model.ModelUtils.*;
/**
* Класс <class>RecodeRuleController</class> реализует контроллер управления правилами перекодирования
*
* @see RecodeRule
*/
@Controller(RecodeRuleController.MAPPING_URI + RecodeRuleController.NAME_POSTFIX)
@RequestMapping(RecodeRuleController.MAPPING_URI + RecodeRuleController.DATA_URI)
public class RecodeRuleController extends ControllerTemplate {
public static final String MAPPING_URI = "recodes";
/** Сервис работы со значениями полей */
@Resource(name = "fieldService")
private IFieldService fieldService;
/** Сервис работы с наборами правил перекодирования */
@Resource(name = "recodeRuleSetService")
private IRecodeRuleSetService recodeRuleSetService;
/** Сервис работы с правилами перекодирования */
@Resource(name = "recodeRuleService")
private IRecodeRuleService recodeRuleService;
@RequestMapping(value = "/{rrsId}", method = RequestMethod.GET)
@ResponseBody
public Collection<RecodeRuleResponseBean> getRecodeRules(@PathVariable String rrsId, @RequestParam(value = "recordIDs") Set<String> fromRecordIDs) {
RecodeRuleSet ruleSet = recodeRuleSetService.findByID(rrsId, false, false);
// Определяем исходных значения полей по идентификаторам записей
Collection<Field> fromFields = fieldService.findByNames(ruleSet.getFromFieldId(), fromRecordIDs, false);
// Определяем правила
Collection<RecodeRule> rules = !CollectionUtils.isEmpty(fromFields) ?
recodeRuleService.findAllByFieldIDs(ruleSet.getId(), Collections2.transform(fromFields, ID_FUNCTION), true) :
Collections.<RecodeRule>emptyList();
// Формируем декораторы
return Collections2.transform(rules, RecodeRuleResponseBean.CONVERT);
}
/**
* Выполняет модификацию правил для указанных полей
*
* @param ruleSet набор правил перекодирования
* @param fromFields коллекция исходных полей
* @param toField целевое поле
* @return Возвращает коллекция модифицированных правил
*/
private Collection<RecodeRule> doModifyRecodeRules(RecodeRuleSet ruleSet, Collection<Field> fromFields, Field toField) {
ImmutableSet.Builder<RecodeRule> toCreate = ImmutableSet.builder();
ImmutableSet.Builder<RecodeRule> toUpdate = ImmutableSet.builder();
ImmutableSet.Builder<RecodeRule> toClose = ImmutableSet.builder();
// Получаем все существующие правила
Map<String, RecodeRule> existedRules = Maps.newHashMap(Maps.uniqueIndex(
recodeRuleService.findAllByFieldIDs(ruleSet.getId(), Collections2.transform(fromFields, ID_FUNCTION), true),
FROM_RULE_FIELD_ID
));
// Для каждого исходного значения определяем действие по модификации
for (Field fromField : fromFields) {
RecodeRule existed = existedRules.remove(ID_FUNCTION.apply(fromField));
if (existed == null && toField != null) {
RecodeRule rule = new RecodeRule().injectRecodeRuleSet(ruleSet);
rule = FROM_RULE_INJECTOR.inject(rule, fromField);
rule = TO_RULE_INJECTOR.inject(rule, toField);
toCreate.add(rule);
} else if (existed != null && toField != null) {
toUpdate.add(TO_RULE_INJECTOR.inject(existed, toField));
} else if (existed != null) {
toClose.add(existed);
}
}
// Выполняем модификацию
return recodeRuleService.modify(toCreate.build(), toUpdate.build(), toClose.build(), false);
}
@RequestMapping(value = "/{rrsId}", method = RequestMethod.POST)
@ResponseBody
public Collection<RecodeRuleResponseBean> modifyRecodeRules(@PathVariable String rrsId, @Valid @RequestBody RecodeRuleRequestBean request) {
final RecodeRuleSet ruleSet = recodeRuleSetService.findByID(rrsId, false, false);
// Определяем целевое поле
final Field toField = StringUtils.hasText(request.getToRecordId()) ?
fieldService.findUniqueByRelativeId(ruleSet.getToFieldId(), request.getToRecordId(), true, false) :
null;
// Определяем исходные поля по идентификаторам записей
Collection<Field> fieldByIDs = fieldService.findByNames(ruleSet.getFromFieldId(), request.getFromRecordIDs(), false);
// Если поля найдены, то определяем все существующие поля с такими же значениями
if (!CollectionUtils.isEmpty(fieldByIDs)) {
Collection<Field> fieldByValues = fieldService.findByValues(ruleSet.getFromFieldId(), Sets.newHashSet(Collections2.transform(fieldByIDs, FIELD_VALUE)), true);
// Выполняем модификацию
Collection<RecodeRule> changed = doModifyRecodeRules(ruleSet, fieldByValues, toField);
// Формируем декораторы
return Collections2.transform(changed, new Function<RecodeRule, RecodeRuleResponseBean>() {
@Override
public RecodeRuleResponseBean apply(RecodeRule input) {
return RecodeRuleResponseBean.CONVERT.apply(input.injectTo(toField));
}
});
} else {
return Collections.emptyList();
}
}
}