const _ = require('lodash');

const {applyStyle, removeStyle} = require('../manage-style');

const dynamicScalingfactors = (zoom) => {
  const scalingFactor = (1 / zoom);
  const defaults = {
    fontSize: 40,
    outlineWidth: 4,
    arrowScale: 3,
    edgeWidth: 2,
  };

  const dynamicFontSize = Math.min(defaults.fontSize, Math.max(scalingFactor * 18, 18));
  const dynamicFontOutlineWidth = Math.min(defaults.outlineWidth, Math.max(scalingFactor * 3, 3));
  const dynamicArrowScale = Math.min(defaults.arrowScale, Math.max(scalingFactor * 2.5, 2.5));
  const dynamicEdgewidth = Math.min(defaults.edgeWidth, Math.max(scalingFactor * 2.5, 2.5));

  return {
    fontSize: dynamicFontSize,
    outlineWidth: dynamicFontOutlineWidth,
    arrowScale: dynamicArrowScale,
    edgeWidth: dynamicEdgewidth
  };
};

const scaledDimensions = (node, zoom) => {
  const nw = node.width();
  const nh = node.height();

  if (nw === 0 || nh === 0) { return { w: 0, h: 0 }; }

  const scaledVal = (1 / zoom) * 8;
  const aspectRatio = nw / nh;
  let xIncr = 0;
  let yIncr = 0;

  if (aspectRatio > 1) {
    xIncr = nw + scaledVal;
    yIncr = nh + (scaledVal / aspectRatio);
  } else {
    xIncr = nw + (scaledVal / aspectRatio);
    yIncr = nh + scaledVal;
  }

  return {
    w: xIncr,
    h: yIncr
  };
};


const baseNodeHoverStyle = {
  'background-color': 'blue',
  'opacity': 1,
  'z-compound-depth': 'top',
  'color': 'white',
  'text-outline-color': 'black'
};

const baseEdgeHoverStyle = {
  'line-color': 'orange',
  'opacity': 1
};

const bindHover = (cy) => {
  cy.on('mouseover', 'node[class!="compartment"]', function (evt) {
    const node = evt.target;
    const currZoom = cy.zoom();

    if (node.isParent() && node.isExpanded()) { return; }

    const { fontSize, outlineWidth, arrowScale, edgeWidth } = dynamicScalingfactors(currZoom);

    node.neighborhood().nodes().union(node).forEach((node) => {
      const { w, h } = scaledDimensions(node, currZoom);

      const nodeHoverStyle = _.assign({}, baseNodeHoverStyle, {
        'font-size': fontSize,
        'text-outline-width': outlineWidth,
        'width': w,
        'height': h
      });

      applyStyle(cy, node, nodeHoverStyle, '_hover-style-before');
    });

    const edgeHoverStyle = _.assign({}, baseEdgeHoverStyle, {
      'arrow-scale': arrowScale,
      'width': edgeWidth
    });

    applyStyle(cy, node.neighborhood().edges(), edgeHoverStyle, '_hover-style-before');
  });

  cy.on('mouseout', 'node[class!="compartment"]', function (evt) {
    const node = evt.target;
    const neighborhood = node.neighborhood();

    removeStyle(cy, neighborhood.nodes(), '_hover-style-before');
    removeStyle(cy, node, '_hover-style-before');
    removeStyle(cy, neighborhood.edges(), '_hover-style-before');
  });

  cy.on('mouseover', 'edge', function (evt) {
    const edge = evt.target;
    const currZoom = cy.zoom();

    const { fontSize, outlineWidth, arrowScale, edgeWidth } = dynamicScalingfactors(currZoom);

    const edgeHoverStyle = _.assign({}, baseEdgeHoverStyle, {
      'arrow-scale': arrowScale,
      'width': edgeWidth
    });
    applyStyle(cy, edge, edgeHoverStyle, '_hover-style-before');


    edge.source().union(edge.target()).forEach((node) => {
      const { w, h } = scaledDimensions(node, currZoom);
      const nodeHoverStyle = _.assign({}, baseNodeHoverStyle, {
        'width': w,
        'height': h,
        'font-size': fontSize,
        'color': 'white',
        'text-outline-color': 'black',
        'text-outline-width': outlineWidth,
        'opacity': 1,
        'background-color': 'blue',
        'z-compound-depth': 'top'
      });
      applyStyle(cy, node, nodeHoverStyle, '_hover-style-before');
    });
  });

  cy.on('mouseout', 'edge', function (evt) {
    const edge = evt.target;

    removeStyle(cy, edge, '_hover-style-before');
    removeStyle(cy, edge.source(), '_hover-style-before');
    removeStyle(cy, edge.target(), '_hover-style-before');
  });



};

module.exports = bindHover;
@@ -1550,23 +1550,87 @@
 er = (cy
+, nodeStyle = baseNodeHoverStyle, edgeStyle = baseEdgeHoverStyle
 ) =%3E %7B%0A
-
   cy.on(
@@ -2066,37 +2066,28 @@
 .assign(%7B%7D, 
-baseNodeHover
+node
 Style, %7B%0A   
@@ -2321,37 +2321,28 @@
 .assign(%7B%7D, 
-baseEdgeHover
+edge
 Style, %7B%0A   
@@ -3076,29 +3076,20 @@
 ign(%7B%7D, 
-baseEdgeHover
+edge
 Style, %7B
@@ -3380,29 +3380,20 @@
 ign(%7B%7D, 
-baseNodeHover
+node
 Style, %7B

add ability to specify style to bindHover - requires a better common cy module that accepts style arguments that trickles down to bindHover