/*jslint nomen: true, newcap: true, browser: true*/
/*global MAPJS, $, _, jQuery*/

jQuery.fn.scrollWhenDragging = function (scrollPredicate) {
  /*jslint newcap:true*/
  'use strict';
  return this.each(function () {
    var element = $(this),
        dragOrigin;
    element.on('dragstart', function () {
      if (scrollPredicate()) {
        dragOrigin = {
          top: element.scrollTop(),
          left: element.scrollLeft()
        };
      }
    }).on('drag', function (e) {
      if (e.gesture && dragOrigin) {
        element.scrollTop(dragOrigin.top - e.gesture.deltaY);
        element.scrollLeft(dragOrigin.left - e.gesture.deltaX);
      }
    }).on('dragend', function () {
      dragOrigin = undefined;
    });
  });
};
$.fn.domMapWidget = function (activityLog, mapModel, touchEnabled, imageInsertController, dragContainer, resourceTranslator, centerSelectedNodeOnOrientationChange, options) {
  'use strict';
  var hotkeyEventHandlers = {
        'return': 'addSiblingIdea',
        'shift+return': 'addSiblingIdeaBefore',
        'del backspace': 'removeSubIdea',
        'tab insert': 'addSubIdea',
        'left': 'selectNodeLeft',
        'up': 'selectNodeUp',
        'right': 'selectNodeRight',
        'shift+right': 'activateNodeRight',
        'shift+left': 'activateNodeLeft',
        'meta+right ctrl+right meta+left ctrl+left': 'flip',
        'shift+up': 'activateNodeUp',
        'shift+down': 'activateNodeDown',
        'down': 'selectNodeDown',
        'space f2': 'editNode',
        'shift+space': 'editNodeData',
        'f': 'toggleCollapse',
        'c meta+x ctrl+x': 'cut',
        'p meta+v ctrl+v': 'paste',
        'y meta+c ctrl+c': 'copy',
        'u meta+z ctrl+z': 'undo',
        'shift+tab': 'insertIntermediate',
        'Esc 0 meta+0 ctrl+0': 'resetView',
        'r meta+shift+z ctrl+shift+z meta+y ctrl+y': 'redo',
        'meta++ ctrl++ z': 'scaleUp',
        'meta+- ctrl+- shift+z': 'scaleDown',
        'meta+up ctrl+up': 'moveUp',
        'meta+down ctrl+down': 'moveDown',
        //'ctrl+shift+v meta+shift+v': 'pasteStyle',
        'Esc': 'cancelCurrentAction',
        'ctrl+s meta+s': 'save',
        'k': 'requestContextMenu'
      },
      charEventHandlers = {
        '[': 'activateChildren',
        '{': 'activateNodeAndChildren',
        '=': 'activateSiblingNodes',
        '.': 'activateSelectedNode',
        '/': 'toggleCollapse'
        //'a': 'openAttachment',
        //'i': 'editIcon'
      },
      actOnKeys = true,
      self = this;
  mapModel.addEventListener('inputEnabledChanged', function (canInput, holdFocus) {
    actOnKeys = canInput;
    if (canInput && !holdFocus) {
      self.focus();
    }
  });

  return this.each(function () {
    var element = $(this),
        stage = $('<div>').css({
          position: 'relative'
        }).attr('data-mapjs-role', 'stage').appendTo(element).data({
          'offsetX': element.innerWidth() / 2,
          'offsetY': element.innerHeight() / 2,
          'width': element.innerWidth() - 20,
          'height': element.innerHeight() - 20,
          'scale': 1
        }).updateStage(),
        previousPinchScale = false;
    element.css('overflow', 'auto').attr('tabindex', 1);
    if (mapModel.isEditingEnabled()) {
      (dragContainer || element).simpleDraggableContainer();
    }

    if (!touchEnabled) {
      element.scrollWhenDragging(mapModel.getInputEnabled); //no need to do this for touch, this is native
      element.on('mousedown', function (e) {
        if (e.target !== element[0]) {
          element.css('overflow', 'hidden');
        }
      });
      jQuery(document).on('mouseup', function () {
        if (element.css('overflow') !== 'auto') {
          element.css('overflow', 'auto');
        }
      });
      element.imageDropWidget(imageInsertController);
    } else {
      element.on('doubletap', function (event) {
        if (mapModel.requestContextMenu(event.gesture.center.pageX, event.gesture.center.pageY)) {
          event.preventDefault();
          event.gesture.preventDefault();
          return false;
        }
      }).on('pinch', function (event) {
        if (!event || !event.gesture || !event.gesture.scale) {
          return;
        }
        event.preventDefault();
        event.gesture.preventDefault();

        var scale = event.gesture.scale;
        if (previousPinchScale) {
          scale = scale / previousPinchScale;
        }
        if (Math.abs(scale - 1) < 0.05) {
          return;
        }
        previousPinchScale = event.gesture.scale;

        mapModel.scale('touch', scale, {
          x: event.gesture.center.pageX - stage.data('offsetX'),
          y: event.gesture.center.pageY - stage.data('offsetY')
        });
      }).on('gestureend', function () {
        previousPinchScale = false;
      });

    }
    MAPJS.DOMRender.viewController(mapModel, stage, touchEnabled, imageInsertController, resourceTranslator, options);
    _.each(hotkeyEventHandlers, function (mappedFunction, keysPressed) {
      element.keydown(keysPressed, function (event) {
        mapModel.getYsy().log.debug("keydown " + keysPressed + " => " + mappedFunction, "keys");
        if (actOnKeys) {
          event.stopImmediatePropagation();
          event.preventDefault();
          mapModel[mappedFunction]('keyboard');
        }
      });
    });
    if (!touchEnabled) {
      jQuery(window).on('resize', function () {
        mapModel.resetView();
      });
    }

    jQuery(window).on('orientationchange', function () {
      if (centerSelectedNodeOnOrientationChange) {
        mapModel.centerOnNode(mapModel.getSelectedNodeId());
      } else {
        mapModel.resetView();
      }

    });
    jQuery("#container").on('keydown', function (e) {
      var functions = {
        'U+003D': 'scaleUp',
        'U+002D': 'scaleDown',
        61: 'scaleUp',
        173: 'scaleDown'
      }, mappedFunction;
      if (e && !e.altKey && (e.ctrlKey || e.metaKey)) {
        if (e.originalEvent && e.originalEvent.keyIdentifier) { /* webkit */
          mappedFunction = functions[e.originalEvent.keyIdentifier];
        } else if (e.key === 'MozPrintableKey') {
          mappedFunction = functions[e.which];
        }
        if (mappedFunction) {
          mapModel.getYsy().log.debug("keydown => " + mappedFunction, "keys");
          if (actOnKeys) {
            e.preventDefault();
            mapModel[mappedFunction]('keyboard');
          }
        }
      }
    }).on('wheel mousewheel', function (e) {
      var scroll = e.originalEvent.deltaX || (-1 * e.originalEvent.wheelDeltaX);
      if (scroll < 0 && element.scrollLeft() === 0) {
        e.preventDefault();
      }
      if (scroll > 0 && (element[0].scrollWidth - element.width() - element.scrollLeft() === 0)) {
        e.preventDefault();
      }
    });

    element.on('keypress', function (evt) {
      if (!actOnKeys) {
        return;
      }
      if (/INPUT|TEXTAREA/.test(evt && evt.target && evt.target.tagName)) {
        return;
      }
      var unicode = evt.charCode || evt.keyCode,
          actualkey = String.fromCharCode(unicode),
          mappedFunction = charEventHandlers[actualkey];
      mapModel.getYsy().log.debug("keydown " + actualkey + " => " + mappedFunction, "keys");
      if (mappedFunction) {
        evt.preventDefault();
        mapModel[mappedFunction]('keyboard');
      } else if (Number(actualkey) <= 9 && Number(actualkey) >= 1) {
        evt.preventDefault();
        mapModel.activateLevel('keyboard', Number(actualkey) + 1);
      }
    });
  });
};
