1 package org.simantics.spreadsheet.graph;
3 import java.io.Serializable;
4 import java.util.ArrayList;
5 import java.util.Arrays;
6 import java.util.Collection;
7 import java.util.Collections;
8 import java.util.HashMap;
11 import java.util.Optional;
13 import org.simantics.databoard.binding.mutable.Variant;
14 import org.simantics.db.exception.DatabaseException;
15 import org.simantics.db.layer0.StandardEngine;
16 import org.simantics.spreadsheet.graph.formula.SpreadsheetEvaluationEnvironment;
17 import org.simantics.spreadsheet.graph.synchronization.LineNodeUpdater;
18 import org.simantics.spreadsheet.graph.synchronization.LineUpdater;
19 import org.simantics.spreadsheet.graph.synchronization.NullUpdater;
20 import org.simantics.spreadsheet.graph.synchronization.SheetLineComponent;
21 import org.simantics.spreadsheet.graph.synchronization.StyleUpdater;
22 import org.simantics.structural.synchronization.base.ComponentFactory;
23 import org.simantics.structural.synchronization.base.MappingBase;
24 import org.simantics.structural.synchronization.base.ModuleUpdaterBase;
25 import org.simantics.structural.synchronization.base.ModuleUpdaterFactoryBase;
26 import org.simantics.structural.synchronization.base.Solver;
27 import org.simantics.structural.synchronization.base.SolverNameUtil;
29 import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
30 import it.unimi.dsi.fastutil.longs.AbstractLongList;
31 import it.unimi.dsi.fastutil.longs.AbstractLongSet;
32 import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
33 import it.unimi.dsi.fastutil.longs.LongArraySet;
34 import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet;
36 public class SpreadsheetBook implements SpreadsheetElement<SpreadsheetElement, SpreadsheetElement>, StandardEngine<SheetNode>, Serializable, SheetNode<SpreadsheetEngine, SheetNode>, Solver, SolverNameUtil, ComponentFactory<SheetLineComponent>, ModuleUpdaterFactoryBase<SheetLineComponent> {
38 private static final long serialVersionUID = 7417208688311691396L;
40 public Serializable NotAvailableError = new Serializable() {};
42 public Long2ObjectOpenHashMap<AbstractLongSet> referenceMap = new Long2ObjectOpenHashMap<>();
44 private Int2ObjectArrayMap<SpreadsheetStyle> styles = new Int2ObjectArrayMap<>();
45 // public ObjectArrayList<SpreadsheetStyle> styles = new ObjectArrayList<SpreadsheetStyle>();
46 public ArrayList<SpreadsheetEngine> sheets = new ArrayList<SpreadsheetEngine>();
48 private SpreadsheetMapping mapping;
51 private int idCounter = 1;
53 public SpreadsheetBook() {
55 mapping = new SpreadsheetMapping(new SheetLineComponent(""));
58 public Map<Integer, SpreadsheetElement> children = new HashMap<>();
60 private boolean iterationEnabled;
62 public int getNewId(SpreadsheetElement element) {
63 int result = idCounter++;
64 children.put(result, element);
68 public long getEngineIndex(SpreadsheetEngine engine) {
69 for(int i=0;i<sheets.size();i++)
70 if(sheets.get(i) == engine) return i;
71 throw new IllegalStateException("Did not find sheet " + engine.getName());
74 public void registerReferences(long cell, AbstractLongList refs) {
75 for(int i=0;i<refs.size();i++) {
76 long key = refs.getLong(i);
77 AbstractLongSet set = referenceMap.get(key);
79 set = new LongArraySet();
80 referenceMap.put(key, set);
83 AbstractLongSet newSet = new LongLinkedOpenHashSet();
86 referenceMap.put(key, set);
93 public Object getValue(SheetNode node) {
94 if(node instanceof SpreadsheetCellContent) {
96 SpreadsheetCellContent scc = (SpreadsheetCellContent)node;
97 Object content = scc.cell.evaluate(SpreadsheetEvaluationEnvironment.getInstance(this));
98 if(content == null) return Variant.ofInstance("");
99 if(content instanceof Variant) return content;
100 else return Variant.ofInstance(content);
101 } catch (Throwable t) {
103 return Variant.ofInstance(t.toString());
105 } else if (node instanceof SpreadsheetCellContentExpression) {
106 SpreadsheetCellContentExpression scce = (SpreadsheetCellContentExpression)node;
107 if (scce.cell.content instanceof SpreadsheetFormula) {
108 SpreadsheetFormula formula = (SpreadsheetFormula)scce.cell.content;
109 return formula.expression;
110 } else if (scce.cell.content instanceof SpreadsheetSCLConstant) {
111 SpreadsheetSCLConstant sclConstant = (SpreadsheetSCLConstant) scce.cell.content;
112 return "=" + sclConstant.expression;
114 System.out.println("Broken SpreadsheetCellContentExpression possibly due to overwriting an existing expression with a constant or something else (current content is " + scce.cell.content + ")");
115 if (scce.cell.content instanceof Variant) {
116 return scce.cell.content;
118 return Variant.ofInstance(scce.cell.content);
121 } else if (node instanceof SpreadsheetTypeNode) {
122 SpreadsheetTypeNode stn = (SpreadsheetTypeNode)node;
124 } else if (node instanceof SpreadsheetCellStyle) {
125 int styleId = ((SpreadsheetCellStyle) node).cell.style;
126 SpreadsheetStyle style = getStyle(styleId);
128 style = SpreadsheetStyle.empty();
129 if (styleId != style.getStyleId())
130 new Exception("different style ids!" + styleId + " " + style.getStyleId()).printStackTrace();
134 } else if (node instanceof SpreadsheetCellEditable) {
135 boolean editable = ((SpreadsheetCellEditable) node).editable();
142 public void setValue(SheetNode node, Object value) {
146 public String getName(SheetNode node) {
147 return node.getName();
151 public Map<String, SheetNode> getChildren(SheetNode node) {
152 return node.getChildren();
156 public Map<String, SheetNode> getProperties(SheetNode node) {
157 return node.getProperties();
161 public String getName() {
166 public Map<String, SpreadsheetEngine> getChildren() {
167 Map<String,SpreadsheetEngine> result = new HashMap<String,SpreadsheetEngine>();
168 for(SpreadsheetEngine engine : sheets)
169 result.put(engine.getName(), engine);
174 public Map<String, SheetNode> getProperties() {
175 return Collections.emptyMap();
178 public SpreadsheetCell get(String sheet, int row, int column) {
179 SpreadsheetEngine engine = getEngine(sheet);
180 if(engine == null) return null;
181 SpreadsheetLine line = engine.getLine(row);
182 if(line == null) return null;
183 if(line.cells.size() <= column) return null;
184 return line.cells.get(column);
187 public SpreadsheetCell get(SpreadsheetEngine engine, int row, int column) {
188 SpreadsheetLine line = engine.getLine(row);
189 if(line == null) return null;
190 if(line.cells.size() <= column) return null;
191 return line.cells.get(column);
194 public SpreadsheetEngine getEngine(String sheet) {
195 for(SpreadsheetEngine engine : sheets)
196 if(sheet.equals(engine.getName())) return engine;
201 public ModuleUpdaterBase<SheetLineComponent> createUpdater(String id) throws DatabaseException {
202 if("http://www.simantics.org/Spreadsheet-1.2/Line".equals(id))
203 return new LineUpdater(id);
204 else if("http://www.simantics.org/Spreadsheet-1.2/LineNode".equals(id))
205 return new LineNodeUpdater(id);
206 else if ("http://www.simantics.org/Spreadsheet-1.2/Style".equals(id))
207 return new StyleUpdater(id);
208 else if("http://www.simantics.org/Spreadsheet-1.2/Lines".equals(id))
209 return new NullUpdater(id);
210 else if("http://www.simantics.org/Spreadsheet-1.2/Spreadsheet".equals(id))
211 return new NullUpdater(id);
212 else if("http://www.simantics.org/Spreadsheet-1.2/Book".equals(id))
213 return new NullUpdater(id);
215 throw new IllegalStateException("createUpdater " + id);
219 public SheetLineComponent create(String uid) {
220 return new SheetLineComponent(uid);
224 public String getFreshName(String parentName, String name) {
225 return parentName + "/" + name;
229 public String ensureNameIsVariationOf(String parentName, int id, String name) {
230 if (parentName.isEmpty())
232 return parentName + "/" + name;
235 final static int COMP_ROOT_POS = "COMP_ROOT/".length();
238 public int getId(String name) {
240 if("COMP_ROOT".equals(name)) return 1;
242 String path = name.substring(COMP_ROOT_POS);
243 String[] parts = path.split("/");
244 Object o = resolve(parts, 0);
245 if(o instanceof SpreadsheetLines) {
246 return ((SpreadsheetLines)o).getId();
247 } else if(o instanceof SpreadsheetLine) {
248 return ((SpreadsheetLine)o).getId();
249 } else if(o instanceof SpreadsheetEngine) {
250 return ((SpreadsheetEngine)o).getId();
251 } else if (o instanceof SpreadsheetStyle) {
252 return ((SpreadsheetStyle) o).getId();
255 throw new IllegalStateException("Resolved object for parts " + Arrays.toString(parts) + " is not the right type! It is " + o);
259 Object resolve(String[] parts, int index) {
260 String part = parts[index];
261 if (part.startsWith("Style")) {
262 for (SpreadsheetStyle style : styles.values()) {
263 if (style.name.equals(part)) {
268 SpreadsheetEngine engine = getEngine(part);
269 if(engine == null) return 0;
270 if(index == parts.length-1) return engine;
271 else return engine.resolve(parts, index+1);
275 public String getName(int id) {
276 if(id == -2) return "http://www.simantics.org/Spreadsheet-1.2/Book";
277 else if(id == -3) return "http://www.simantics.org/Spreadsheet-1.2/Spreadsheet";
278 else if(id == -4) return "http://www.simantics.org/Spreadsheet-1.2/Lines";
280 return "http://www.simantics.org/Spreadsheet-1.2/LineNode";
282 return "http://www.simantics.org/Spreadsheet-1.2/Line";
284 return "http://www.simantics.org/Spreadsheet-1.2/Style";
289 public int getModuleType(int id) {
290 Serializable s = children.get(id);
291 if(s instanceof SpreadsheetBook) return -2;
292 else if(s instanceof SpreadsheetEngine) return -3;
293 else if(s instanceof SpreadsheetLines) {
294 if("Lines".equals(((SpreadsheetLines) s).getName()))
299 else if(s instanceof SpreadsheetLine)
301 else if (s instanceof SpreadsheetStyle)
303 else throw new IllegalStateException();
307 public void remove(int id) {
309 SpreadsheetElement child = children.get(id);
310 Optional<SpreadsheetElement> parent = child.getParent();
312 if (parent.isPresent()) {
313 parent.get().remove(child);
319 public void addSubprocess(String name, String subprocessType) {
320 ensureSubprocess(name);
323 public <T> T ensureSubprocess(String name) {
324 String[] parts = name.split("/");
325 if(parts.length == 2) {
326 SpreadsheetEngine engine = getEngine(parts[1]);
328 engine = new SpreadsheetEngine(this, parts[1]);
332 } else if (parts.length > 2) {
333 SpreadsheetEngine engine = getEngine(parts[1]);
334 return (T)engine.ensureSubprocess(parts, 2);
336 throw new IllegalStateException();
341 public void includeSubprocess(String parentName, String subprocessName) {
346 public <T> T getConcreteSolver() {
351 public void accept(SpreadsheetVisitor v) {
355 public List<SpreadsheetCell> invalidate(SpreadsheetCell cell) {
356 ArrayList<SpreadsheetCell> result = new ArrayList<>();
359 long refKey = cell.makeReferenceKey();
360 AbstractLongSet refs = referenceMap.remove(refKey);
361 if(refs == null) return result;
362 for(long ref : refs) {
363 long sheet = ref >> 40;
364 long row = (ref >> 20) & 0xFFFFF;
365 long col = (ref) & 0xFFFFF;
366 SpreadsheetCell referer = get(sheets.get((int)sheet), (int)row, (int)col);
373 public void addStyle(SpreadsheetStyle style) {
374 if (style.name == null) {
375 new Exception("Trying to add style to book without name!!").printStackTrace();
378 style.setSynchronizationId(getNewId(style));
379 styles.put(style.getStyleId(), style);
382 public SpreadsheetStyle getStyle(int styleId) {
383 return styles.get(styleId);
386 public MappingBase<SheetLineComponent> getMapping() {
391 public Optional<SpreadsheetElement> getParent() {
392 return Optional.empty();
396 public Collection<SpreadsheetElement> getSpreadsheetChildren() {
397 return children.values();
401 public void remove(SpreadsheetElement child) {
402 // TODO Auto-generated method stub
406 public void setIterationEnabled(boolean value) {
407 this.iterationEnabled = value;
410 public boolean isIterationEnabled() {
411 return iterationEnabled;