class DragHandler {

  constructor(controller) {
    this.controller = controller;
    this.online = false;
  }

  setOnline(online) {
    this.online = online;
  }

  install(graph) {
    const oldStart = graph.graphHandler.start;
    const oldUpdate = graph.graphHandler.updateLivePreview;
    const oldReset = graph.graphHandler.reset;
    const oldMoveCells = graph.graphHandler.moveCells;
    const self = this;

    graph.graphHandler.start = function(cell, x, y) {
      // start dragging (locally)
      oldStart.apply(this, arguments);

      console.log("drag start");

      if (self.online) {
        const cells = graph.graphHandler.getCells(cell);
        const cellIds = cells.map(c => c.id);

        let acquiredCallback, denyCallback;
        const acquiredPromise = new Promise((resolve, reject) => {
          acquiredCallback = resolve;
          denyCallback = reject;
        }).then(
          () => {console.log("acquired")},
          e => {console.log("denied"); throw e},
        );

        console.log("request lock");
        self.controller.addInput("request_lock", "in", [cellIds, acquiredCallback, denyCallback], self.controller.wallclockToSimtime());

        let resolveDragEnd;
        const dragPromise = new Promise(resolve => {
          resolveDragEnd = resolve;
        });

        const resetOnce = {
          reset: () => {
            graph.graphHandler.reset();
          },
        };

        // let's pretend we acquire the lock

        let moveCellsArgs;
        // In the graph handler, moveCells is called when the mouse is released (end of drag).
        graph.graphHandler.moveCells = function(cells, dx, dy, clone, target, event) {
          moveCellsArgs = [cells, dx, dy, clone, target, event];
        };

        // When drag has completed AND a lock was acquired, release the lock.
        Promise.all([dragPromise, acquiredPromise])
        .then(() => {
          if (moveCellsArgs !== undefined) {
            oldMoveCells.apply(graph.graphHandler, moveCellsArgs);
          }
          console.log("release lock");
          self.controller.addInput("release_lock", "in", [cellIds], self.controller.wallclockToSimtime());
        })
        .catch(() => {
          console.log("could not acquire lock");
          resetOnce.reset();
        });

        let dX = 0;
        let dY = 0;
        graph.graphHandler.updateLivePreview = function(dx, dy) {
          oldUpdate.apply(this, arguments);
          dX = dx;
          dY = dy;
          const msg = {
            type: "update_drag",
            cells,
            dx, dy,
          };
        };

        graph.graphHandler.reset = function() {
          console.log("drag end");
          oldReset.apply(this, arguments);
          resetOnce.reset = () => {};
          resolveDragEnd();
          console.log(dX, dY);
        };
      }
      else {
        // offline
        graph.graphHandler.updateLivePreview = oldUpdate;
        graph.graphHandler.moveCells = oldMoveCells;
        graph.graphHandler.reset = oldReset;
      }


    };

    // document.addEventListener('keydown', e => {
    //   if (e.code === 'ShiftLeft') {
    //     graph.graphHandler.reset();
    //   }
    // });
  }
};

module.exports = { DragHandler };