import Vertex from "./Vertex.js";
import EventProvider from "./EventProvider.js";
import Container from "./Container.js";
import Edge from "./Edge.js";
import { castToFloat } from "../../lib/libaux.js";
import GraphEvent from "./GraphEvent.js";

const XGEE_LAYOUT_UPDATE_PERIOD = 500; //ms;

export default class GraphLayoutManager extends EventProvider {
  constructor(eObject) {
    super();
    this.ecoreSync = ecoreSync;
    this.eObject = eObject;

    this.resource = null;
    this.root = null;
    this.layout = null;

    this.cache = new Map();

    this.vertexCache = new Map();

    this.scaleUpdate = null;
    this.translateUpdate = { x: null, y: null };

    this.updates = new eoq2.Cmp();
    this.scheduledUpdate = null;
    this.updatesEnabled = true;

    //Temporary positions that are only available locally
    this.temporaryPositions = [];

    //Layout requests
    this.positionRequests = [];
    this.sizeRequests = [];
    this.scheduledRequest = null;

    //Layout events
    this.createEvent("CACHE_BUILT");
  }

  async init() {
    this.resource = await this.getLayoutResource();
    this.observeResource();

    //Init
    this.root = await this.getRoot();
    this.layout = await this.getLayout();
    await this.buildCache();
  }

  async buildCache() {
    var self = this;
    var invalidEntries = [];
    //Command for retrieving layout information
    let cmd = new eoq2.Cmp();
    cmd.Get(new eoq2.Obj(this.ecoreSync.rlookup(this.layout)).Cls("Vertex"));
    cmd.Get(new eoq2.His(0).Pth("refersTo"));
    cmd.Get(new eoq2.His(0).Pth("parent").Trm().Pth("refersTo"));
    cmd.Get(new eoq2.His(0).Pth("sizeX"));
    cmd.Get(new eoq2.His(0).Pth("sizeY"));
    cmd.Get(new eoq2.His(0).Pth("x"));
    cmd.Get(new eoq2.His(0).Pth("y"));

    var results = await this.ecoreSync.exec(cmd);

    //Building the cache
    results[1].forEach((obj, idx) => {
      let oid = null;
      let pid = null;
      let parent = results[2][idx];

      if (obj != null) {
        oid = this.ecoreSync.rlookup(obj);
      }
      if (parent != null) {
        pid = this.ecoreSync.rlookup(parent);
      }

      if (oid) {
        let entryKey = "default";
        if (pid != null) {
          entryKey = String(pid) + "." + String(oid);
        } else {
          entryKey = String(oid);
        }

        if (!self.vertexCache.has(entryKey)) {
          self.vertexCache.set(entryKey, results[0][idx]);
        }
      }

      if (obj == null) invalidEntries.push(idx);
    });

    //Remove invalid entries from layout
    //this.clearEntries(results[0].filter((v,idx) => { return invalidEntries.includes(idx) }).map((obj) => { return this.ecoreSync.rlookup(obj) }))

    this.raise("CACHE_BUILT");
  }

  async update() {
    //scheduled canceable update action
    const scheduledLayoutUpdate = (layoutManager, interval) => {
      var timer = null;
      var rejectUpdate = () => {};
      var scheduledUpdate = new Promise(function (resolve, reject) {
        reject = rejectUpdate;
        timer = setTimeout(function () {
          layoutManager.updateNow();
          resolve();
        }, interval);
      });

      return {
        promise: scheduledUpdate,
        cancel: () => {
          clearTimeout(timer);
          timer = null;
          rejectUpdate();
          rejectUpdate = () => {};
        },
      };
    };

    if (this.scheduledUpdate != null) {
      this.scheduledUpdate.cancel();
      this.scheduledUpdate = scheduledLayoutUpdate(this, XGEE_LAYOUT_UPDATE_PERIOD);
    } else {
      this.scheduledUpdate = scheduledLayoutUpdate(this, XGEE_LAYOUT_UPDATE_PERIOD);
    }
  }

  async updateNow() {
    //uncancelable update action
    this.scheduledUpdate = null;
    var pendingUpdates = this.updates;
    this.updates = new eoq2.Cmp();

    if (this.scaleUpdate) {
      pendingUpdates.Set(
        new eoq2.Obj(this.ecoreSync.rlookup(this.layout)),
        "scale",
        castToFloat(this.scaleUpdate),
      );
      this.scaleUpdate = null;
    }

    if (this.translateUpdate) {
      if (this.translateUpdate.x)
        pendingUpdates.Set(
          new eoq2.Obj(this.ecoreSync.rlookup(this.layout)),
          "translateX",
          castToFloat(this.translateUpdate.x),
        );
      if (this.translateUpdate.y)
        pendingUpdates.Set(
          new eoq2.Obj(this.ecoreSync.rlookup(this.layout)),
          "translateY",
          castToFloat(this.translateUpdate.y),
        );
      this.translateUpdate.x = null;
      this.translateUpdate.y = null;
    }

    if (pendingUpdates.a.length) {
      await this.ecoreSync.exec(pendingUpdates);
    }
  }

  async createLayoutResource(directory, layoutResourceName) {
    let cmd = new eoq2.Cmp();
    cmd.Crn("http://www.xgee.de/layout/v1", "LayoutContainer", 1);
    cmd.Crn("http://www.eoq.de/workspacemdbmodel/v1.0", "ModelResource", 1);
    cmd.Set(new eoq2.Qry().His(1), "name", layoutResourceName);
    cmd.Add(new eoq2.Qry().His(1), "contents", new eoq2.Qry().His(0));
    cmd.Add(
      new eoq2.Qry().Obj(this.ecoreSync.rlookup(directory)),
      "resources",
      new eoq2.Qry().His(1),
    );

    var result = await this.ecoreSync.exec(cmd);

    if (result.length != cmd.a.length) {
      throw new Error("Cannot create layout resource. layout.ecore loaded?");
    }

    return result[1];
  }

  async getLayoutResource() {
    if (this.resource != null) {
      return this.resource;
    }
    let res = await this.ecoreSync.utils.getResource(this.eObject);
    let directory = await this.ecoreSync.utils.getContainer(res);
    if (directory) {
      var layoutResourceName = (await ecoreSync.get(res, "name")) + ".layout";
      let cmd = new eoq2.Get(
        QRY.Obj(this.ecoreSync.rlookup(directory))
          .Pth("resources")
          .Sel(QRY.Pth("name").Equ(layoutResourceName))
          .Trm(QRY.Met("SIZE").Equ(0), null)
          .Idx(0),
      );
      var layoutResource = await this.ecoreSync.remoteExec(cmd, true);
      if (layoutResource == null) {
        layoutResource == (await this.createLayoutResource(directory, layoutResourceName));
      }
      return layoutResource;
    } else {
      throw " Resource could not be found";
    }
  }

  async getRoot() {
    if (this.root != null) {
      return this.root;
    }
    var layoutResource = await this.getLayoutResource();
    var resourceContents = await this.ecoreSync.get(layoutResource, "contents");
    if (resourceContents.length) {
      return resourceContents[0];
    } else {
      //transparently repair resource
      let cmd = new eoq2.Cmp();
      cmd.Crn("http://www.xgee.de/layout/v1", "LayoutContainer", 1);
      cmd.Add(new eoq2.Obj(this.ecoreSync.rlookup(layoutResource)), "contents", new eoq2.His(-1));
      var res = this.ecoreSync.remoteExec(cmd, true);
      return res[0];
    }
  }

  async getLayout() {
    if (this.layout == null) {
      var root = await this.getRoot();
      let cmd = new eoq2.Cmp();
      cmd.Get(
        new eoq2.Obj(this.ecoreSync.rlookup(root))
          .Pth("layouts")
          .Sel(
            new eoq2.Qry().Pth("refersTo").Equ(new eoq2.Obj(this.ecoreSync.rlookup(this.eObject))),
          )
          .Trm(QRY.Met("SIZE").Equ(0), null)
          .Idx(0),
      );
      cmd.Get(new eoq2.Met("IF", [new eoq2.His(0).Neq(null), new eoq2.His(0).Pth("scale"), null]));
      cmd.Get(
        new eoq2.Met("IF", [new eoq2.His(0).Neq(null), new eoq2.His(0).Pth("translateX"), null]),
      );
      cmd.Get(
        new eoq2.Met("IF", [new eoq2.His(0).Neq(null), new eoq2.His(0).Pth("translateY"), null]),
      );
      let resLayout = await this.ecoreSync.remoteExec(cmd, true);

      if (resLayout[0] != null) {
        this.layout = resLayout[0];
      } else {
        let cmd = new eoq2.Cmp();
        cmd.Crn("http://www.xgee.de/layout/v1/def", "Layout", 1);
        cmd.Set(
          new eoq2.Qry().His(-1),
          "refersTo",
          new eoq2.Obj(this.ecoreSync.rlookup(this.eObject)),
        );
        //should be obsolete if default values work correctly
        cmd.Set(new eoq2.Qry().His(0), "scale", castToFloat(1));
        cmd.Set(new eoq2.Qry().His(0), "translateX", castToFloat(0));
        cmd.Set(new eoq2.Qry().His(0), "translateY", castToFloat(0));
        cmd.Add(new eoq2.Obj(this.ecoreSync.rlookup(root)), "layouts", new eoq2.Qry().His(0));
        let res = await this.ecoreSync.remoteExec(cmd, true);
        this.layout = res[0];
      }
    }
    return this.layout;
  }

  async getScale() {
    var layout = await this.getLayout();
    return await this.ecoreSync.get(layout, "scale");
  }

  async setScale(scale) {
    var res = false;
    if (this.layout) {
      this.scaleUpdate = scale;
      res = true;
      this.update();
    }
    return res;
  }

  async setTranslate(x = null, y = null) {
    if (this.layout) {
      if (x) this.translateUpdate.x = x;
      if (y) this.translateUpdate.y = y;
      this.update();
      return true;
    }
  }

  async getTranslate() {
    if (this.layout) {
      var cmd = new eoq2.Cmp();
      cmd.Get(new eoq2.Obj(this.ecoreSync.rlookup(this.layout)).Pth("translateX"));
      cmd.Get(new eoq2.Obj(this.ecoreSync.rlookup(this.layout)).Pth("translateY"));
      var res = await this.ecoreSync.remoteExec(cmd, true);
      return { x: res[0], y: res[1] };
    }
  }

  async createVertexLayoutItem(eObject, x = null, y = null, parent = null) {
    var vertexLayoutItem = null;
    let cmd = new eoq2.Cmp();
    let oid = this.ecoreSync.rlookup(eObject);
    if (parent != null) var poid = this.ecoreSync.rlookup(parent);
    if (oid == null) throw "invalid eObject supplied: oid is null";
    if (parent != null && poid == null) throw "invalid parent supplied: oid is null";

    cmd.Crn("http://www.xgee.de/layout/v1/def", "Vertex", 1);
    cmd.Set(new eoq2.Qry().His(0), "refersTo", new eoq2.Obj(oid));
    cmd.Add(new eoq2.Obj(this.ecoreSync.rlookup(this.layout)), "contents", new eoq2.Qry().His(0));
    if (x != null && y != null) {
      cmd.Set(QRY.His(0), "x", x);
      cmd.Set(QRY.His(0), "y", y);
    }
    cmd.Get(new eoq2.Qry(), QRY.His(0).Pth("x"));
    cmd.Get(new eoq2.Qry(), QRY.His(0).Pth("y"));
    cmd.Get(new eoq2.Qry(), QRY.His(0).Pth("sizeX"));
    cmd.Get(new eoq2.Qry(), QRY.His(0).Pth("sizeY"));

    if (poid != null) cmd.Set(new eoq2.Qry().His(0), "parent", QRY.Obj(poid));
    var result = await this.ecoreSync.exec(cmd);
    vertexLayoutItem = result[0];
    if (parent != null) await this.ecoreSync.set(vertexLayoutItem, "parent", parent);
    return vertexLayoutItem;
  }

  async createEdgeLayoutItem(eObject, supportPoints = null) {
    let cmd = new eoq2.Cmp();
    cmd.Crn("http://www.xgee.de/layout/v1/def", "Edge", 1);
    cmd.Set(new eoq2.Qry().His(-1), "refersTo", new eoq2.Obj(this.ecoreSync.rlookup(eObject)));
    cmd.Add(new eoq2.Obj(this.ecoreSync.rlookup(this.layout)), "contents", new eoq2.Qry().His(-2));
    if (supportPoints != null) {
    }
    var result = await this.ecoreSync.remoteExec(cmd);
    return this.ecoreSync.getObject(result[0].v);
  }

  async getVertexLayoutItem(vertex) {
    var layout = await this.getLayout();
    var parentVertex = null;
    var vertexLayoutItem = null;

    if (!this.cache.has(vertex)) {
      if (
        vertex.parent &&
        (vertex.parent instanceof Vertex || vertex.parent instanceof Container)
      ) {
        parentVertex = await this.getVertexLayoutItem(vertex.parent);
        if (!parentVertex) throw "missing parent layout item";
      }

      if (parentVertex) {
        let cmd = CMD.Get(
          new eoq2.Obj(this.ecoreSync.rlookup(layout))
            .Pth("contents")
            .Cls("Vertex")
            .Sel(
              new eoq2.Qry().Pth("refersTo").Equ(new eoq2.Obj(ecoreSync.rlookup(vertex.eObject))),
            )
            .Sel(
              new eoq2.Qry().Pth("parent").Equ(new eoq2.Obj(this.ecoreSync.rlookup(parentVertex))),
            )
            .Idx("FLATTEN")
            .Trm(QRY.Met("SIZE").Equ(0), null)
            .Idx(0),
        );
        let result = await this.ecoreSync.remoteExec(cmd, true);

        if (result != null) {
          vertexLayoutItem = result;
        } else {
          vertexLayoutItem = await this.createVertexLayoutItem(
            vertex.eObject,
            null,
            null,
            parentVertex,
          );
        }
      } else {
        let cmd = CMD.Get(
          new eoq2.Obj(this.ecoreSync.rlookup(this.layout))
            .Pth("contents")
            .Cls("Vertex")
            .Sel(
              new eoq2.Qry().Pth("refersTo").Equ(new eoq2.Obj(ecoreSync.rlookup(vertex.eObject))),
            )
            .Idx("FLATTEN")
            .Trm(QRY.Met("SIZE").Equ(0), null)
            .Idx(0),
        );
        let result = await this.ecoreSync.remoteExec(cmd, true);
        if (result != null) {
          vertexLayoutItem = result;
        } else {
          vertexLayoutItem = await this.createVertexLayoutItem(vertex.eObject);
        }
      }

      this.cache.set(vertex, vertexLayoutItem);
    } else {
      vertexLayoutItem = this.cache.get(vertex);
    }

    return vertexLayoutItem;
  }

  async getEdgeLayoutItem(edge) {
    if (!this.layout) {
      this.layout = await this.getLayout();
      if (!this.layout) throw "Failed getting layout";
    }

    var parentVertex = null;
    if (edge.parent && edge.parent.eObject) {
      parentVertex = await this.getVertexLayoutItem(edge.parent);
      if (!parentVertex) throw "missing parent layout item";
    }

    if (parentVertex) {
      let cmd = new eoq2.Get(
        new eoq2.Obj(this.ecoreSync.rlookup(this.layout))
          .Pth("contents")
          .Sel(new eoq2.Qry().Met("CLASSNAME").Equ("Edge"))
          .Sel(new eoq2.Qry().Pth("refersTo").Equ(new eoq2.Obj(ecoreSync.rlookup(edge.eObject))))
          .Sel(new eoq2.Qry().Pth("parent").Equ(new eoq2.Obj(this.ecoreSync.rlookup(parentVertex))))
          .Idx("FLATTEN"),
      );
      let result = await this.ecoreSync.remoteExec(cmd);
      if (result.length) {
        return this.ecoreSync.utils.decode(result[0]);
      } else {
        var edgeLayoutItem = await this.createEdgeLayoutItem(edge.eObject);
        await this.ecoreSync.set(edgeLayoutItem, "parent", parentVertex);
        return edgeLayoutItem;
      }
    } else {
      let cmd = new eoq2.Get(
        new eoq2.Obj(this.ecoreSync.rlookup(this.layout))
          .Pth("contents")
          .Cls("Edge")
          .Sel(new eoq2.Qry().Pth("refersTo").Equ(new eoq2.Obj(ecoreSync.rlookup(edge.eObject))))
          .Idx("FLATTEN"),
      );
      let result = await this.ecoreSync.remoteExec(cmd);

      if (result.length) {
        return await this.ecoreSync.utils.decode(result[0]);
      } else {
        return await this.createEdgeLayoutItem(edge.eObject);
      }
    }
  }

  isVertexInLayout(vertex) {
    let entryKey = null;
    let oid = this.ecoreSync.rlookup(vertex.eObject);
    if (vertex.parent instanceof Vertex || vertex.parent instanceof Container) {
      pid = this.ecoreSync.rlookup(vertex.parent.eObject);
      entryKey = String(pid) + "." + String(oid);
    } else {
      entryKey = String(oid);
    }
    return this.vertexCache.has(entryKey);
  }

  async getVertexPosition(vertex) {
    var position = { x: 0, y: 0, isDefault: true };
    let oid = this.ecoreSync.rlookup(vertex.eObject);
    let pid = null;
    if (oid) {
      let entryKey = null;
      if (vertex.parent instanceof Vertex || vertex.parent instanceof Container) {
        pid = this.ecoreSync.rlookup(vertex.parent.eObject);
        entryKey = String(pid) + "." + String(oid);
      } else {
        entryKey = String(oid);
      }

      if (this.vertexCache.has(entryKey)) {
        position.x = this.vertexCache.get(entryKey).get("x");
        position.y = this.vertexCache.get(entryKey).get("y");
      }
    } else {
      try {
        var vertexLayoutItem = await this.getVertexLayoutItem(vertex);
        if (vertexLayoutItem) {
          position = {
            x: await this.ecoreSync.get(vertexLayoutItem, "x"),
            y: await this.ecoreSync.get(vertexLayoutItem, "y"),
          };
        } else {
          throw "missing layout item";
        }
      } catch (e) {
        console.error("Failed getting vertex position: " + e);
      }
    }
    return position;
  }

  async getVertexSize(vertex) {
    var size = { x: 0, y: 0 };

    let oid = this.ecoreSync.rlookup(vertex.eObject);
    let pid = null;
    if (oid) {
      let entryKey = null;
      if (vertex.parent instanceof Vertex || vertex.parent instanceof Container) {
        pid = this.ecoreSync.rlookup(vertex.parent.eObject);
        entryKey = String(pid) + "." + String(oid);
      } else {
        entryKey = String(oid);
      }

      if (this.vertexCache.has(entryKey)) {
        size.x = this.vertexCache.get(entryKey).get("sizeX");
        size.y = this.vertexCache.get(entryKey).get("sizeY");
      }
    } else {
      try {
        var vertexLayoutItem = await this.getVertexLayoutItem(vertex);
        if (vertexLayoutItem) {
          size = {
            x: await this.ecoreSync.get(vertexLayoutItem, "sizeX"),
            y: await this.ecoreSync.get(vertexLayoutItem, "sizeY"),
          };
        } else {
          throw "missing layout item";
        }
      } catch (e) {
        console.error("Failed getting vertex size: " + e);
      }
    }
    return size;
  }

  async observeResource() {
    var self = this;
    this.ecoreSync.observe(
      new eoq2.Obj(this.ecoreSync.rlookup(this.resource)).Pth("contents"),
      async function (contents) {
        if (contents.length) {
          self.root = null;
          self.layout = null;
          self.root = await self.getRoot();
          self.layout = await self.getLayout();
          self.vertexCache = new Map();
          await self.buildCache();
        }
      },
    );
  }

  async observeVertexPosition(vertex, callback) {
    return true; // the following code has never been active, commented out to silence firefox
    // var pos={x:0,y:0};
    // var timeout = null;
    // var timeoutInterval=100;
    // var resetTimer=function(){
    //     if(timeout){ clearTimeout(timeout);  }  timeout=window.setTimeout(function(){ callback(pos); }, timeoutInterval);
    // }

    // try{
    //     var vertexLayoutItem=await this.getVertexLayoutItem(vertex)
    //     if(vertexLayoutItem)
    //     {
    //         this.ecoreSync.observe(new eoq2.Obj(this.ecoreSync.rlookup(vertexLayoutItem)).Pth('x'),function(val){ pos.x=val;    resetTimer();   });
    //         this.ecoreSync.observe(new eoq2.Obj(this.ecoreSync.rlookup(vertexLayoutItem)).Pth('y'),function(val){ pos.y=val;    resetTimer();   });
    //         return true
    //     }
    //     else
    //     {
    //         throw 'missing layout item'
    //     }
    // }
    // catch(e)
    // {
    //     console.error('Failed observing vertex position: '+e)
    // }
    // return false
  }

  addTemporaryVertexPosition(objectId, parentObjectId, pos) {
    var tempPosition = { objectId: objectId, parent: parentObjectId, pos: pos };
    this.temporaryPositions.push(tempPosition);
  }

  getTemporaryVertexPosition(objectId, parentObjectId) {
    var tempPosition = this.temporaryPositions.find(function (tempPos) {
      return tempPos.objectId == objectId && tempPos.parent == parentObjectId;
    });
    if (tempPosition) {
      this.removeTemporaryVertexPosition(tempPosition);
      return tempPosition.pos;
    }
    return null;
  }

  removeTemporaryVertexPosition(tempPosition) {
    var idx = this.temporaryPositions.indexOf(tempPosition);
    if (idx > -1) {
      this.temporaryPositions.splice(idx, 1);
    }
  }

  async setVertexPosition(vertex, x, y) {
    var vertexLayoutItem = await this.getVertexLayoutItem(vertex);
    this.updates.Set(new eoq2.Obj(this.ecoreSync.rlookup(vertexLayoutItem)), "x", castToFloat(x));
    this.updates.Set(new eoq2.Obj(this.ecoreSync.rlookup(vertexLayoutItem)), "y", castToFloat(y));
    vertexLayoutItem.set("x", castToFloat(x));
    vertexLayoutItem.set("y", castToFloat(y));
    this.update();
    return vertexLayoutItem;
  }

  async observeVertexSize(vertex, callback) {
    return true; // the following code has never been active, commented out to silence firefox
    // var size={x:0,y:0};
    // var timeout = null;
    // var timeoutInterval=100;
    // var resetTimer=function(){
    //     if(timeout){ clearTimeout(timeout);  }  timeout=window.setTimeout(function(){ callback(size); }, timeoutInterval);
    // }

    // try{
    //     var vertexLayoutItem=await this.getVertexLayoutItem(vertex)
    //     if(vertexLayoutItem)
    //     {
    //         this.ecoreSync.observe(new eoq2.Obj(this.ecoreSync.rlookup(vertexLayoutItem)).Pth('sizeX'),function(val){ size.x=val;    resetTimer();   });
    //         this.ecoreSync.observe(new eoq2.Obj(this.ecoreSync.rlookup(vertexLayoutItem)).Pth('sizeY'),function(val){ size.y=val;    resetTimer();   });
    //         return true
    //     }
    //     else
    //     {
    //         throw 'missing layout item'
    //     }
    // }
    // catch(e)
    // {
    //     console.error('Failed observing vertex size: '+e)
    // }
    // return false
  }

  async setVertexSize(vertex, x = null, y = null) {
    var vertexLayoutItem = await this.getVertexLayoutItem(vertex);
    if (x != null && y != null) {
      this.updates.Set(new eoq2.Obj(this.ecoreSync.rlookup(vertexLayoutItem)), "sizeX", x);
      this.updates.Set(new eoq2.Obj(this.ecoreSync.rlookup(vertexLayoutItem)), "sizeY", y);
      this.update();
      return true;
    }
  }

  async getEdgeSupportPoints(edge) {
    var edgeLayoutItem = await this.getEdgeLayoutItem(edge);
    var fetchSupportPoints = new eoq2.Cmp();
    fetchSupportPoints.Get(
      new eoq2.Obj(this.ecoreSync.rlookup(edgeLayoutItem)).Pth("supportPoints"),
    );
    fetchSupportPoints.Get(new eoq2.His(0).Pth("x"));
    fetchSupportPoints.Get(new eoq2.His(0).Pth("y"));
    fetchSupportPoints.Get(new eoq2.His(0).Pth("pointIndex"));
    let results = await this.ecoreSync.exec(fetchSupportPoints);
    return results[0];
  }

  async updateEdge(edge, supportPoints) {
    if (supportPoints) {
      await this.clearEdgeSupportPoints(edge);
      let edgeLayoutItem = await this.getEdgeLayoutItem(edge);

      // Process added support points
      if (supportPoints.length) {
        let updateCmd = new eoq2.Cmp();
        updateCmd.Crn("http://www.xgee.de/layout/v1/def", "Point", supportPoints.length);
        if (supportPoints.length > 1) {
          let idx = 0;
          for (let supportPoint of supportPoints) {
            updateCmd.Set(new eoq2.His(0).Idx(idx), "x", castToFloat(supportPoint.x));
            updateCmd.Set(new eoq2.His(0).Idx(idx), "y", castToFloat(supportPoint.y));
            updateCmd.Set(new eoq2.His(0).Idx(idx), "pointIndex", idx);
            updateCmd.Add(
              new eoq2.Obj(this.ecoreSync.rlookup(edgeLayoutItem)),
              "supportPoints",
              new eoq2.His(0).Idx(idx),
            );
            idx += 1;
          }
        } else {
          updateCmd.Set(new eoq2.His(0), "x", castToFloat(supportPoints[0].x));
          updateCmd.Set(new eoq2.His(0), "y", castToFloat(supportPoints[0].y));
          updateCmd.Add(
            new eoq2.Obj(this.ecoreSync.rlookup(edgeLayoutItem)),
            "supportPoints",
            new eoq2.His(0),
          );
        }
        this.ecoreSync.exec(updateCmd);
      }
    }
  }

  async clearEdgeSupportPoints(edge) {
    let edgeLayoutItem = await this.getEdgeLayoutItem(edge);
    await this.ecoreSync._esDomain.clear(edgeLayoutItem, "supportPoints");
  }

  // async setEdgeSupportPoints(edge,supportPoints)
  // {
  //     console.error('setting edge support points')
  //     var edgeLayoutItem=await this.getEdgeLayoutItem(edge)
  //     let cmd=new eoq2.Cmp()
  //     cmd.Get(new eoq2.Obj(this.ecoreSync.rlookup(edgeLayoutItem)).Pth('supportPoints'))
  //     cmd.Rem(new eoq2.Obj(this.ecoreSync.rlookup(edgeLayoutItem)),"supportPoints",new eoq2.Qry().His(-1))
  //     if(supportPoints && Array.isArray(supportPoints) && supportPoints.length)
  //     {
  //         console.error('There are support points')
  //         cmd.Crn('http://www.xgee.de/layout/v1/def','Point',supportPoints.length)
  //         cmd.Add(new eoq2.Obj(this.ecoreSync.rlookup(edgeLayoutItem)),"supportPoints",new eoq2.Qry().His(-1))
  //         for(let i in supportPoints)
  //         {
  //             console.error(i);
  //             cmd.Set(new eoq2.His(-2-i).Idx(i),"x",castToFloat(supportPoints[i].x))
  //             cmd.Set(new eoq2.His(-3).Idx(i),"y",castToFloat(supportPoints[i].y))
  //         }
  //     }
  //     console.error(cmd);
  //     var result=await this.ecoreSync.exec(cmd)
  //     return result;
  // }

  //Removes entries from the layout model
  async clearEntries(objectIds) {
    let objects = objectIds
      .filter((objId) => {
        return !Number.isNaN(objId);
      })
      .map((objId) => {
        return new eoq2.Obj(objId);
      });
    let lid = this.ecoreSync.rlookup(this.layout);

    if (objects.length && !Number.isNaN(lid)) {
      console.info("Clearing " + objects.length + " entries from layout...");
      try {
        let cmd = new eoq2.Rem(new eoq2.Obj(lid), "contents", new eoq2.Arr(objects));
        this.ecoreSync.remoteExec(cmd);
      } catch (e) {
        console.error("Failed to clear layout entries:" + e);
      }
    }
  }
}
