package org.openlca.app.editors.graphical.action;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.eclipse.gef.commands.Command;
import org.eclipse.jface.action.Action;
import org.openlca.app.M;
import org.openlca.app.db.Database;
import org.openlca.app.editors.graphical.command.CommandUtil;
import org.openlca.app.editors.graphical.command.ConnectionInput;
import org.openlca.app.editors.graphical.command.ExpansionCommand;
import org.openlca.app.editors.graphical.command.MassCreationCommand;
import org.openlca.app.editors.graphical.model.ExchangeNode;
import org.openlca.app.editors.graphical.model.ProcessNode;
import org.openlca.app.editors.graphical.model.ProductSystemNode;
import org.openlca.app.editors.graphical.search.ProcessLinkSearchMap;
import org.openlca.core.database.BaseDao;
import org.openlca.core.database.FlowDao;
import org.openlca.core.database.ProcessDao;
import org.openlca.core.model.Exchange;
import org.openlca.core.model.ProcessLink;
import org.openlca.core.model.ProcessType;
import org.openlca.core.model.descriptors.ProcessDescriptor;
class BuildNextTierAction extends Action implements IBuildAction {
private final FlowDao flowDao;
private final ProcessDao processDao;
private final BaseDao<Exchange> exchangeDao;
private List<ProcessNode> nodes;
private ProductSystemNode systemNode;
private ProcessType preferredType = ProcessType.UNIT_PROCESS;
BuildNextTierAction() {
setId(ActionIds.BUILD_NEXT_TIER);
setText(M.BuildNextTier);
flowDao = new FlowDao(Database.get());
processDao = new ProcessDao(Database.get());
exchangeDao = new BaseDao<>(Exchange.class, Database.get());
}
@Override
public void setProcessNodes(List<ProcessNode> nodes) {
this.nodes = nodes;
if (nodes == null || nodes.isEmpty())
return;
this.systemNode = nodes.get(0).parent();
}
void setPreferredType(ProcessType preferredType) {
this.preferredType = preferredType;
}
@Override
public void run() {
if (nodes == null || nodes.isEmpty())
return;
ProductSystemNode systemNode = nodes.get(0).parent();
List<ProcessDescriptor> providers = new ArrayList<>();
List<ConnectionInput> newConnections = new ArrayList<>();
for (ProcessNode node : nodes)
collectFor(node, providers, newConnections);
Command command = MassCreationCommand.nextTier(providers, newConnections, systemNode);
if (command == null)
return;
for (ProcessNode node : nodes)
command = command.chain(ExpansionCommand.expandLeft(node));
CommandUtil.executeCommand(command, systemNode.editor);
systemNode.editor.setDirty(true);
}
private void collectFor(ProcessNode node,
List<ProcessDescriptor> providers,
List<ConnectionInput> newConnections) {
long targetId = node.process.getId();
List<ExchangeNode> toConnect = loadExchangeNodes(node);
for (ExchangeNode exchange : toConnect) {
ProcessDescriptor provider = findProvider(exchange.exchange);
if (provider == null)
continue;
if (!providers.contains(provider))
providers.add(provider);
long flowId = exchange.exchange.getFlow().getId();
long exchangeId = exchange.exchange.getId();
ConnectionInput connectionInput = new ConnectionInput(provider.getId(), flowId, targetId, exchangeId);
if (newConnections.contains(connectionInput))
continue;
newConnections.add(connectionInput);
}
}
private List<ExchangeNode> loadExchangeNodes(ProcessNode node) {
List<ExchangeNode> nodes = new ArrayList<>();
for (ExchangeNode exchangeNode : node.loadExchangeNodes()) {
if (exchangeNode.isDummy())
continue;
if (isAlreadyConnected(exchangeNode))
continue;
if (exchangeNode.exchange.isInput())
nodes.add(exchangeNode);
}
return nodes;
}
private boolean isAlreadyConnected(ExchangeNode exchangeNode) {
ProcessNode processNode = exchangeNode.parent();
long processId = processNode.process.getId();
long flowId = exchangeNode.exchange.getFlow().getId();
ProcessLinkSearchMap linkSearch = processNode.parent().linkSearch;
List<ProcessLink> incomingLinks = linkSearch
.getIncomingLinks(processId);
for (ProcessLink link : incomingLinks)
if (link.flowId == flowId)
return true;
return false;
}
private ProcessDescriptor findProvider(Exchange exchange) {
ProcessDescriptor defaultProvider = getDefaultProvider(exchange);
if (defaultProvider != null)
return defaultProvider;
List<ProcessDescriptor> providers = getProviders(exchange);
if (providers.isEmpty())
return null;
long flowId = exchange.getFlow().getId();
ProcessDescriptor matching = findMatching(providers, flowId);
if (matching != null)
return matching;
ProcessDescriptor existing = findExisting(providers);
if (existing != null)
return existing;
ProcessDescriptor preferred = findPreferred(providers);
if (preferred != null)
return preferred;
return providers.get(0);
}
private ProcessDescriptor findMatching(List<ProcessDescriptor> providers,
long flowId) {
ProcessDescriptor candidate = null;
for (ProcessDescriptor descriptor : providers) {
Exchange reference = exchangeDao.getForId(descriptor
.getQuantitativeReference());
if (reference.getFlow().getId() != flowId)
continue;
if (descriptor.getProcessType() == preferredType)
return descriptor;
else if (candidate == null)
candidate = descriptor;
}
return candidate;
}
private ProcessDescriptor findExisting(List<ProcessDescriptor> providers) {
Set<Long> existing = systemNode.getProductSystem().getProcesses();
for (ProcessDescriptor descriptor : providers)
if (existing.contains(descriptor.getId()))
return descriptor;
return null;
}
private ProcessDescriptor findPreferred(List<ProcessDescriptor> providers) {
for (ProcessDescriptor descriptor : providers)
if (descriptor.getProcessType() == preferredType)
return descriptor;
return null;
}
private ProcessDescriptor getDefaultProvider(Exchange exchange) {
if (exchange.getDefaultProviderId() == 0)
return null;
return processDao.getDescriptor(exchange.getDefaultProviderId());
}
private List<ProcessDescriptor> getProviders(Exchange exchange) {
Set<Long> providerIds = flowDao
.getProviders(exchange.getFlow().getId());
return processDao.getDescriptors(providerIds);
}
}