--- /dev/null
+package org.simantics.spreadsheet.solver;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Optional;
+
+import org.simantics.spreadsheet.SpreadsheetVisitor;
+import org.simantics.spreadsheet.Spreadsheets;
+
+import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap;
+
+@SuppressWarnings("rawtypes")
+public class SpreadsheetLines implements SpreadsheetElement<SpreadsheetLine, SpreadsheetEngine>, SheetNode {
+
+ private static final long serialVersionUID = -3615335969248723486L;
+
+ private final int id;
+ private SpreadsheetEngine parent;
+ private String name;
+ public Int2ObjectAVLTreeMap<SpreadsheetLines> nodes = new Int2ObjectAVLTreeMap<SpreadsheetLines>();
+ public Int2ObjectAVLTreeMap<SpreadsheetLine> lines = new Int2ObjectAVLTreeMap<SpreadsheetLine>();
+ public int[] keys;
+
+ public SpreadsheetLines(SpreadsheetEngine parent, String name) {
+ this.parent = parent;
+ this.name = name;
+ id = getEngine().getBook().getNewId(this);
+ }
+
+ public SpreadsheetEngine getEngine() {
+ return parent;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @SuppressWarnings({ "unchecked" })
+ @Override
+ public Map getChildren() {
+ Int2ObjectAVLTreeMap result = new Int2ObjectAVLTreeMap();
+ result.putAll(nodes);
+ result.putAll(lines);
+ return result;
+ }
+
+ @Override
+ public Map getProperties() {
+ return Collections.singletonMap("typeURI", new SpreadsheetTypeNode(Spreadsheets.LINES_TYPE_URI));
+ }
+
+ Object resolve(String[] parts, int index) {
+
+ String part = parts[index];
+ if(part.charAt(0) == 'R') {
+ int indx = Integer.parseInt(part.substring(3));
+ SpreadsheetLine line = lines.get(-indx);
+ if(line != null) {
+ if(index == parts.length-1) return line;
+ else return line.resolve(parts, index+1);
+ }
+ } else {
+ int indx = Integer.parseInt(part);
+ SpreadsheetLines node = nodes.get(indx);
+ if(node != null) {
+ if(index == parts.length-1) return node;
+ else return node.resolve(parts, index+1);
+ }
+ }
+
+ return null;
+
+ }
+
+ public Object ensureSubprocess(String[] path, int index) {
+
+ String name = path[index];
+
+ int i = Integer.parseInt(name);
+ SpreadsheetLines line = nodes.get(i);
+ if(line == null) {
+ line = new SpreadsheetLines(parent, "" + i);
+ nodes.put(i, line);
+ }
+
+ if(index == path.length - 1) {
+ return line;
+ } else {
+ return line.ensureSubprocess(path, index+1);
+ }
+
+ }
+
+ public void setKeys(int[] keys) {
+ this.keys = keys;
+ }
+
+ @Override
+ public void accept(SpreadsheetVisitor v) {
+ v.visit(this);
+ }
+
+ public String getPath() {
+ return "/" + parent.getName() + "/" + parent.lines.getName() + "/" + getName();
+ }
+
+ private int getKey(int index) {
+ return keys[2*index+1];
+ }
+
+ private int getChild(int index) {
+ return keys[2*index];
+ }
+
+ /*
+ * [(child,key),...,key)
+ *
+ */
+ public SpreadsheetLine getLine(int k) {
+
+ int i=1;
+ int n = (keys.length - 1) / 2;
+
+ while(i <= n && k > getKey(i-1)) i++;
+
+ if(i <= n && k == getKey(i-1)) {
+ return lines.get(-k);
+ }
+
+ int nodeName = getChild(i-1);
+ SpreadsheetLines node = nodes.get(nodeName);
+ if(node == null) return null;
+ return node.getLine(k);
+
+ }
+
+ public int getMaxRow() {
+ // if keys == null then this is the root of BTree which has only one child
+ if (keys == null) {
+ int maxRow = 0;
+ for (SpreadsheetLines node : nodes.values()) {
+ int row = node.getMaxRow();
+ if (row > maxRow)
+ maxRow = row;
+ }
+ return maxRow;
+ }
+ int largestChild = keys[keys.length-1];
+ if(largestChild > 0) {
+ SpreadsheetLines child = nodes.get(largestChild);
+ return child.getMaxRow();
+ } else {
+ return keys[keys.length-2];
+ }
+ }
+
+ @Override
+ public Optional<SpreadsheetEngine> getParent() {
+ return Optional.of(parent);
+ }
+
+ @Override
+ public Collection<SpreadsheetLine> getSpreadsheetChildren() {
+ return lines.values();
+ }
+
+ @Override
+ public void remove(SpreadsheetLine child) {
+ lines.remove(-child.row);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ result = prime * result + ((parent == null) ? 0 : parent.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ SpreadsheetLines other = (SpreadsheetLines) obj;
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ if (parent == null) {
+ if (other.parent != null)
+ return false;
+ } else if (!parent.equals(other.parent))
+ return false;
+ return true;
+ }
+
+}