/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* Copyright (c) 2014, MPL CodeInside http://codeinside.ru
*/
package ru.codeinside.gses.beans;
import org.activiti.engine.impl.ServiceImpl;
import ru.codeinside.adm.database.SmevChain;
import ru.codeinside.gses.activiti.Activiti;
import ru.codeinside.gses.activiti.forms.FormID;
import ru.codeinside.gses.activiti.forms.GetFormValueCommand;
import ru.codeinside.gses.activiti.forms.api.definitions.PropertyNode;
import ru.codeinside.gses.activiti.forms.api.definitions.PropertyTree;
import ru.codeinside.gses.activiti.forms.api.definitions.PropertyType;
import ru.codeinside.gses.activiti.forms.api.definitions.ToggleNode;
import ru.codeinside.gses.activiti.forms.api.definitions.VariableType;
import ru.codeinside.gses.activiti.forms.api.values.BlockValue;
import ru.codeinside.gses.activiti.forms.api.values.FormValue;
import ru.codeinside.gses.activiti.forms.api.values.PropertyValue;
import ru.codeinside.gses.activiti.forms.types.AttachmentType;
import ru.codeinside.gses.beans.filevalues.SmevFileValue;
import ru.codeinside.gses.service.BidID;
import ru.codeinside.gses.service.DeclarantServiceProvider;
import ru.codeinside.gses.webui.Configurator;
import ru.codeinside.gws.api.DeclarerContext;
import ru.codeinside.gws.api.Enclosure;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Logger;
public class ActivitiDeclarerContext implements DeclarerContext {
final FormValue formValue;
final private String componentName;
final private SmevChain smevChain;
final private String processDefinitionId;
final private Logger logger = Logger.getLogger(getClass().getName());
final private Map<String, Object> formPropertyValues = new LinkedHashMap<String, Object>();
final private Map<String, ToggleNode> toggles;
final private Map<String, Boolean> requiredFlags = new HashMap<String, Boolean>();
final private AtomicLong gid;
final private AtomicLong bidId = new AtomicLong(-1L);
public ActivitiDeclarerContext(SmevChain smevChain,
AtomicLong gid, String processDefinitionId, String componentName) {
this.smevChain = smevChain;
this.processDefinitionId = processDefinitionId;
this.gid = gid;
this.componentName = componentName;
GetFormValueCommand cmd = new GetFormValueCommand(FormID.byProcessDefinitionId(processDefinitionId), null);
formValue = ((ServiceImpl) Configurator.get().getFormService()).getCommandExecutor().execute(cmd);
toggles = initializeRequireFlags(formValue.getFormDefinition());
}
@Override
public void setValue(String propertyId, Object value) {
if (value != null) {
formPropertyValues.put(propertyId, value);
} else {
formPropertyValues.remove(propertyId);
}
processRequireFlag(propertyId);
}
@Override
public boolean isRequired(String propertyId) {
final PropertyNode property = getWritableNodeById(propertyId);
if (requiredFlags.containsKey(propertyId)) {
return requiredFlags.get(propertyId);
}
return property != null && property.isFieldRequired();
}
@Override
public String getType(String propertyId) {
final PropertyNode property = getWritableNodeById(propertyId);
if (property == null) {
return "";
}
VariableType variableType = property.getVariableType();
return variableType == null ? "" : variableType.getName();
}
@Override
public Set<String> getPropertyNames() {
final Set<String> result = new LinkedHashSet<String>();
collectId(formValue.getPropertyValues(), result);
return result;
}
private void collectId(List<PropertyValue<?>> propertyValues, Set<String> result) {
for (PropertyValue<?> pv : propertyValues) {
if (pv.getNode().isFieldWritable()) {
result.add(pv.getId());
if (pv instanceof BlockValue) {
BlockValue blockValue = (BlockValue) pv;
for (List<PropertyValue<?>> clone : blockValue.getClones()) {
collectId(clone, result);
}
}
}
}
}
@Override
public String declare(String tag, String declarant) {
if (bidId.compareAndSet(-1L, 0L)) {
BidID bidID = DeclarantServiceProvider.get().smevDeclare(
smevChain, componentName, Configurator.get(),
processDefinitionId, formPropertyValues, declarant, tag
);
bidId.set(bidID.bidId);
gid.compareAndSet(0L, bidID.bidId);
return Long.toString(bidID.bidId);
} else {
// TODO: добавить в API тип исключений
throw new IllegalStateException("Заявление для данного контекста уже подано");
}
}
@Override
public String declare() {
return declare("", "smev");
}
public String getBidId() {
long id = bidId.get();
return (id == 0L || id == 1L) ? null : Long.toString(id);
}
private PropertyNode getWritableNodeById(String propertyId) {
PropertyNode node = findById(formValue.getPropertyValues(), propertyId);
if (node == null) {
logger.warning("Не найдено записываемое свойство '" + propertyId + "'");
}
return null;
}
private PropertyNode findById(List<PropertyValue<?>> propertyValues, String id) {
PropertyNode node = null;
for (PropertyValue<?> pv : propertyValues) {
if (pv.getId().equals(id)) {
if (pv.getNode().isFieldWritable()) {
node = pv.getNode();
}
break;
}
if (pv instanceof BlockValue) {
BlockValue blockValue = (BlockValue) pv;
for (List<PropertyValue<?>> clone : blockValue.getClones()) {
node = findById(clone, id);
if (node != null) {
break;
}
}
if (node != null) {
break;
}
}
}
return node;
}
@Override
public boolean isEnclosure(final String propertyId) {
final PropertyNode fp = getWritableNodeById(propertyId);
if (fp == null) {
return false;
}
VariableType variableType = fp.getVariableType();
if (variableType == null) {
return false;
}
return variableType.getClass() == AttachmentType.class;
}
@Override
public void addEnclosure(final String propertyId, final Enclosure enclosure) {
if (checkDigest(enclosure)) {
formPropertyValues.put(propertyId, new SmevFileValue(enclosure));
processRequireFlag(propertyId);
}
}
private boolean checkDigest(Enclosure enclosure) {
if (enclosure.digest != null && enclosure.digest.length > 0) {
if (!Arrays.equals(Activiti.createDigest(enclosure.content), enclosure.digest)) {
logger.warning("Ошибка в свёртке GOST3411 для вложения '" + enclosure.zipPath + "'");
return false; //TODO: исключительная ситуация?
}
}
return true;
}
private Map<String, ToggleNode> initializeRequireFlags(final PropertyTree nodeMap) {
final Map<String, ToggleNode> toggles = new HashMap<String, ToggleNode>();
for (final PropertyNode node : nodeMap.getNodes()) {
if (node.getPropertyType() == PropertyType.TOGGLE) {
final ToggleNode toggle = (ToggleNode) node;
toggles.put(toggle.getToggler().getId(), toggle);
processRequireFlag(toggle);
}
}
return toggles;
}
private void processRequireFlag(final ToggleNode toggle) {
final String value;
if (formPropertyValues.containsKey(toggle.getId())) {
value = null;
} else {
value = formPropertyValues.get(toggle.getId()).toString();
}
boolean required = !toggle.getToggleTo();
if (toggle.getToggleValue().equals(value)) {
required = !required;
}
for (PropertyNode it : toggle.getToggleNodes()) {
requiredFlags.put(it.getId(), required);
}
}
private void processRequireFlag(final String propertyId) {
final ToggleNode toggle = toggles.get(propertyId);
if (toggle != null) {
processRequireFlag(toggle);
}
}
public Object getVariable(final String name) {
return formPropertyValues.get(name);
}
}