import { EModalType } from "../ui/react-pathway-mapper";
import EditorActionsManager from "./EditorActionsManager";

export default class ContextMenuManager {
  private cy: any;
  private editor: EditorActionsManager;
  private handleOpen: (modalId: EModalType) => void;
  private undoRedoManager: any;
  private isCollaborative: any;
  constructor(cy: any, editor: EditorActionsManager,
              handleOpen: (modalId: EModalType) => void, undoRedoManager: any,
              isCollaborative: boolean){
    this.cy = cy;
    this.editor = editor;
    this.handleOpen = handleOpen;
    this.undoRedoManager = undoRedoManager;
    this.isCollaborative = isCollaborative;
    this.init();
  }

  init() {
    const classRef = this;

    const ctxMenus = this.cy.scratch('cycontextmenus') ? 
                      this.cy.contextMenus('get') :
                      this.cy.contextMenus();

    let menuItems = [
      {
        id: 'deleteSelected',
        content: 'Delete Selected',
        coreAsWell: true,
        onClickFunction: () => {
            const selectedEles = this.cy.elements(':selected');
            classRef.editor.removeElement(selectedEles);
        },
        disabled: false, 
        hasTrailingDivider: false,
      },
      {
          id: 'hideSelected',
          content: 'Hide Selected',
          coreAsWell: true,
          onClickFunction: function () {
              classRef.editor.hideSelectedNodes();
          },
          disabled: false,
          hasTrailingDivider: false, 
      },
      {
          id: 'loadFromCBioPortal',
          content: 'Load From cBioPortal...', 
          coreAsWell: true,
          onClickFunction: () => {
            this.handleOpen(EModalType.STUDY);
          },
          disabled: false,
          hasTrailingDivider: false,
      },
      //Context menu items when clicking on nodes/compounds
      {
        id: 'remove', 
        content: 'Delete', 
        selector: 'node, edge',
        onClickFunction: function (event) {
          var ele = event.target;
          // The function to be executed on click
          var selectedElements = classRef.cy.nodes(':selected').union(ele);
          classRef.editor.removeElement(selectedElements);
        },
        disabled: false,
        hasTrailingDivider: false, 
        coreAsWell: false 
      },
      {
        id: 'addSelected',
        content: 'Add Selected Into This', 
        selector: 'node',
        onClickFunction: function (event)
        {
          var ele = event.target;
          var selectedNodes = classRef.cy.nodes(':selected');
          var containerType = ele.data('type');
          var validNodes = classRef.cy.collection();

          //Do nothing if node is GENE
          if (ele._private.data['type'] === 'GENE' || selectedNodes.size() < 1) {
            return;
          }
          //Prevent actions like adding root node to children & addition to itself
          else
          {
            var notValid = false;
            selectedNodes.forEach(function (tmpNode, i)
            {
              if (ele.id() == tmpNode.id()) {
                notValid = true;
                return false;
              }

              if (tmpNode.isParent()) {
                notValid = classRef.isChildren(tmpNode, ele);
                if (notValid) {
                  return false;
                }
              }

              return true;
            });

            if (notValid) {
              return;
            }
          }


          selectedNodes.forEach(function (tmpNode, i)
          {

            if(containerType == "FAMILY" || containerType == "COMPLEX")
            {
              if(tmpNode.data('type') != "COMPARTMENT" && tmpNode.data('type') != "PROCESS")
              {
                validNodes = validNodes.add(tmpNode);
              }
            }
            else
            {
              validNodes = validNodes.add(tmpNode);
            }

          });

          var compId = ele.id();
          classRef.editor.changeParents(validNodes, compId);
          //Unselecting nodes to remove them from selectedNodeStack
          selectedNodes.unselect();

        },
        disabled: false,
        hasTrailingDivider: false, 
        coreAsWell: false 
      },
      {
        id: 'removeSelected',
        content: 'Remove Selected From Parent', 
        selector: 'node',
        onClickFunction: function (event) {
          const ele = event.target;
          const selectedNodes = classRef.cy.nodes(':selected');

          let notValid = false;
          selectedNodes.forEach(function (tmpNode, i) {

            if (tmpNode.isParent()) {
              notValid = classRef.isChildren(tmpNode, ele);
              if (notValid) {
                return false;
              }
            }

            return true;
          });

          if (notValid) {
            return;
          }

          classRef.editor.changeParents(selectedNodes, null);
          //Unselecting nodes to remove them from selectedNodeStack
          selectedNodes.unselect();
        },
        disabled: false, 
        hasTrailingDivider: false,
        coreAsWell: false 
      },
      {
          id: 'performLayout', 
          content: 'Perform Layout', 
          coreAsWell: true,
          onClickFunction: () => {
            this.editor.performLayout();
          },
          disabled: false, 
          hasTrailingDivider: false, 
      }

    ];
    let nonCollabItems = [ 
      //Context menu items when clicking on blank space
      {
          id: 'undoAction', 
          content: 'Undo', 
          coreAsWell: true,
          onClickFunction: () => {
              this.undoRedoManager.undo();
          },
          disabled: false, 
          hasTrailingDivider: false, 
      },
      {
          id: 'redoAction',
          content: 'Redo',
          coreAsWell: true,
          onClickFunction: () => {
            this.undoRedoManager.redo();
          },
          disabled: false,
          hasTrailingDivider: false,
      }
    ];

    if(!this.isCollaborative){
      menuItems = menuItems.concat(nonCollabItems);
    }
    ctxMenus.appendMenuItems(menuItems);
  }

    //TODO better move this to another class
    //Utility function to check whether query node is children of given node
    isChildren(node, queryNode)
    {
      var parent = queryNode.parent()[0];
      while(parent)
      {
        if (parent.id() == node.id()) {
          return true;
        }
        parent = parent.parent()[0];
      }
      return false;
    }
}
