package org.openlca.app.editors.processes;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Section;
import org.openlca.app.M;
import org.openlca.app.util.Actions;
import org.openlca.app.rcp.images.Images;
import org.openlca.app.util.Labels;
import org.openlca.app.util.Numbers;
import org.openlca.app.util.UI;
import org.openlca.app.util.tables.TableClipboard;
import org.openlca.app.util.tables.Tables;
import org.openlca.app.viewers.table.modify.ModifySupport;
import org.openlca.app.viewers.table.modify.TextCellModifier;
import org.openlca.core.model.AllocationFactor;
import org.openlca.core.model.AllocationMethod;
import org.openlca.core.model.Exchange;
import org.openlca.core.model.Process;
import org.openlca.io.CategoryPath;
import org.openlca.util.Strings;
/**
* A table for the display and editing of the causal allocation factors of a
* process. The output products are displayed in columns.
*/
class CausalFactorTable {
private ProcessEditor editor;
private Column[] columns;
private TableViewer viewer;
public CausalFactorTable(ProcessEditor editor) {
this.editor = editor;
initColumns();
}
private Process process() {
return editor.getModel();
}
public void refresh() {
List<Exchange> products = Processes.getOutputProducts(process());
List<Exchange> newProducts = new ArrayList<>(products);
List<Integer> removalIndices = new ArrayList<>();
for (int i = 0; i < columns.length; i++) {
Exchange product = columns[i].product;
if (products.contains(product))
newProducts.remove(product);
else
removalIndices.add(i);
}
for (int col : removalIndices)
removeColumn(col);
for (Exchange product : newProducts)
addColumn(product);
viewer.setInput(Processes.getNonOutputProducts(process()));
createModifySupport();
}
private void removeColumn(int col) {
Column[] newColumns = new Column[columns.length - 1];
System.arraycopy(columns, 0, newColumns, 0, col);
if ((col + 1) < columns.length)
System.arraycopy(columns, col + 1, newColumns, col,
newColumns.length - col);
columns = newColumns;
Table table = viewer.getTable();
table.getColumn(col + 4).dispose();
}
private void addColumn(Exchange product) {
Column newColumn = new Column(product);
Table table = viewer.getTable();
TableColumn tableColumn = new TableColumn(table, SWT.VIRTUAL);
tableColumn.setText(newColumn.getTitle());
tableColumn.setWidth(150);
Column[] newColumns = new Column[columns.length + 1];
System.arraycopy(columns, 0, newColumns, 0, columns.length);
newColumns[columns.length] = newColumn;
columns = newColumns;
}
private void initColumns() {
List<Exchange> products = Processes.getOutputProducts(process());
columns = new Column[products.size()];
for (int i = 0; i < columns.length; i++)
columns[i] = new Column(products.get(i));
Arrays.sort(columns);
}
public void render(Section section, FormToolkit toolkit) {
Composite composite = UI.sectionClient(section, toolkit);
UI.gridLayout(composite, 1);
String[] columnTitles = getColumnTitles();
viewer = Tables.createViewer(composite, columnTitles);
viewer.setLabelProvider(new FactorLabel());
Action copy = TableClipboard.onCopy(viewer);
Actions.bind(viewer, copy);
Tables.bindColumnWidths(viewer, 0.2, 0.1, 0.1, 0.1);
createModifySupport();
Table table = viewer.getTable();
for (int i = 0; i < table.getColumnCount(); i++) {
if (i < 4)
continue;
TableColumn column = table.getColumn(i);
column.setWidth(80);
column.setToolTipText(columnTitles[i]);
}
for (int i = 3; i < table.getColumnCount(); i++) {
viewer.getTable().getColumns()[i].setAlignment(SWT.RIGHT);
}
}
void setInitialInput() {
viewer.setInput(Processes.getNonOutputProducts(process()));
}
private void createModifySupport() {
String[] keys = getColumnTitles();
for (int i = 0; i < columns.length; i++)
keys[i + 4] = columns[i].getKey();
viewer.setColumnProperties(keys);
ModifySupport<Exchange> modifySupport = new ModifySupport<>(viewer);
for (int i = 0; i < columns.length; i++)
modifySupport.bind(keys[i + 4], new ValueModifier(
columns[i].product));
}
private String[] getColumnTitles() {
String[] titles = new String[columns.length + 4];
titles[0] = M.Flow;
titles[1] = M.Direction;
titles[2] = M.Category;
titles[3] = M.Amount;
for (int i = 0; i < columns.length; i++)
titles[i + 4] = columns[i].getTitle();
return titles;
}
private AllocationFactor getFactor(Exchange product, Exchange exchange) {
AllocationFactor factor = null;
for (AllocationFactor f : process().getAllocationFactors()) {
if (f.getAllocationType() != AllocationMethod.CAUSAL)
continue;
if (product.getFlow().getId() == f.getProductId()
&& Objects.equals(f.getExchange(), exchange)) {
factor = f;
break;
}
}
return factor;
}
private class FactorLabel extends LabelProvider implements
ITableLabelProvider {
@Override
public Image getColumnImage(Object element, int col) {
if (col != 0)
return null;
if (!(element instanceof Exchange))
return null;
Exchange exchange = (Exchange) element;
if (exchange.getFlow() == null)
return null;
return Images.get(exchange.getFlow());
}
@Override
public String getColumnText(Object element, int col) {
if (!(element instanceof Exchange))
return null;
Exchange exchange = (Exchange) element;
if (exchange.getFlow() == null || exchange.getUnit() == null)
return null;
switch (col) {
case 0:
return Labels.getDisplayName(exchange.getFlow());
case 1:
return exchange.isInput() ? M.Input : M.Output;
case 2:
return CategoryPath.getShort(exchange.getFlow().getCategory());
case 3:
return Numbers.format(exchange.getAmountValue()) + " "
+ exchange.getUnit().getName();
default:
return getFactorLabel(exchange, col);
}
}
private String getFactorLabel(Exchange exchange, int col) {
int idx = col - 4;
if (idx < 0 || idx > (columns.length - 1))
return null;
Column column = columns[idx];
AllocationFactor factor = getFactor(column.getProduct(), exchange);
if (factor == null)
return Double.toString(1.0);
else
return Double.toString(factor.getValue());
}
}
private class Column implements Comparable<Column> {
private Exchange product;
private String key;
public Column(Exchange product) {
this.product = product;
key = UUID.randomUUID().toString();
}
public Exchange getProduct() {
return product;
}
public String getKey() {
return key;
}
public String getTitle() {
if (product == null || product.getFlow() == null)
return "";
return Labels.getDisplayName(product.getFlow());
}
@Override
public int compareTo(Column o) {
return Strings.compare(this.getTitle(), o.getTitle());
}
}
private class ValueModifier extends TextCellModifier<Exchange> {
private Exchange product;
public ValueModifier(Exchange product) {
this.product = product;
}
@Override
protected String getText(Exchange exchange) {
AllocationFactor factor = getFactor(product, exchange);
if (factor == null)
return Double.toString(1);
else
return Double.toString(factor.getValue());
}
@Override
protected void setText(Exchange exchange, String text) {
Double val = AllocationPage.parseFactor(text);
if (val == null)
return;
AllocationFactor factor = getFactor(product, exchange);
if (factor == null) {
factor = new AllocationFactor();
factor.setAllocationType(AllocationMethod.CAUSAL);
factor.setExchange(exchange);
factor.setProductId(product.getFlow().getId());
process().getAllocationFactors().add(factor);
}
factor.setValue(val);
editor.setDirty(true);
}
}
}