/* eslint-disable */
define(function (require, exports, module) {
  var kity = require('../core/kity');
  var utils = require('../core/utils');
  var keymap = require('../core/keymap');

  var Minder = require('../core/minder');
  var MinderNode = require('../core/node');
  var Command = require('../core/command');
  var Module = require('../core/module');
  var Renderer = require('../core/render');

  Module.register('KeyboardModule', function () {
    var min = Math.min,
      max = Math.max,
      abs = Math.abs,
      sqrt = Math.sqrt,
      exp = Math.exp;

    function buildPositionNetwork(root) {
      var pointIndexes = [],
        p;
      root.traverse(function (node) {
        p = node.getLayoutBox();

        // bugfix: 不应导航到收起的节点（判断其尺寸是否存在）
        if (p.width && p.height) {
          pointIndexes.push({
            left: p.x,
            top: p.y,
            right: p.x + p.width,
            bottom: p.y + p.height,
            width: p.width,
            height: p.height,
            node: node,
          });
        }
      });
      for (var i = 0; i < pointIndexes.length; i++) {
        findClosestPointsFor(pointIndexes, i);
      }
    }

    // 这是金泉的点子，赞！
    // 求两个不相交矩形的最近距离
    function getCoefedDistance(box1, box2) {
      var xMin, xMax, yMin, yMax, xDist, yDist, dist, cx, cy;
      xMin = min(box1.left, box2.left);
      xMax = max(box1.right, box2.right);
      yMin = min(box1.top, box2.top);
      yMax = max(box1.bottom, box2.bottom);

      xDist = xMax - xMin - box1.width - box2.width;
      yDist = yMax - yMin - box1.height - box2.height;

      if (xDist < 0) dist = yDist;
      else if (yDist < 0) dist = xDist;
      else dist = sqrt(xDist * xDist + yDist * yDist);

      var node1 = box1.node;
      var node2 = box2.node;

      // sibling
      if (node1.parent == node2.parent) {
        dist /= 10;
      }
      // parent
      if (node2.parent == node1) {
        dist /= 5;
      }

      return dist;
    }

    function findClosestPointsFor(pointIndexes, iFind) {
      var find = pointIndexes[iFind];
      var most = {},
        quad;
      var current, dist;

      for (var i = 0; i < pointIndexes.length; i++) {
        if (i == iFind) continue;
        current = pointIndexes[i];

        dist = getCoefedDistance(current, find);

        // left check
        if (current.right < find.left) {
          if (!most.left || dist < most.left.dist) {
            most.left = {
              dist: dist,
              node: current.node,
            };
          }
        }

        // right check
        if (current.left > find.right) {
          if (!most.right || dist < most.right.dist) {
            most.right = {
              dist: dist,
              node: current.node,
            };
          }
        }

        // top check
        if (current.bottom < find.top) {
          if (!most.top || dist < most.top.dist) {
            most.top = {
              dist: dist,
              node: current.node,
            };
          }
        }

        // bottom check
        if (current.top > find.bottom) {
          if (!most.down || dist < most.down.dist) {
            most.down = {
              dist: dist,
              node: current.node,
            };
          }
        }
      }
      find.node._nearestNodes = {
        right: (most.right && most.right.node) || null,
        top: (most.top && most.top.node) || null,
        left: (most.left && most.left.node) || null,
        down: (most.down && most.down.node) || null,
      };
    }

    function navigateTo(km, direction) {
      var referNode = km.getSelectedNode();
      if (!referNode) {
        km.select(km.getRoot());
        buildPositionNetwork(km.getRoot());
        return;
      }
      if (!referNode._nearestNodes) {
        buildPositionNetwork(km.getRoot());
      }
      var nextNode = referNode._nearestNodes[direction];
      if (nextNode) {
        km.select(nextNode, true);
      }
    }

    // 稀释用
    var lastFrame;
    return {
      events: {
        'layoutallfinish': function () {
          var root = this.getRoot();
          buildPositionNetwork(root);
        },
        'normal.keydown readonly.keydown': function (e) {
          var minder = this;
          ['left', 'right', 'up', 'down'].forEach(function (key) {
            if (e.isShortcutKey(key)) {
              navigateTo(minder, key == 'up' ? 'top' : key);
              e.preventDefault();
            }
          });
        },
      },
    };
  });
});
