'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.bind = bind;
exports.unbind = unbind;

var _constants = require('./constants');

var _convertFullwidthCharsToASCII = require('./utils/convertFullwidthCharsToASCII');

var _convertFullwidthCharsToASCII2 = _interopRequireDefault(_convertFullwidthCharsToASCII);

var _isCharConsonant = require('./utils/isCharConsonant');

var _isCharConsonant2 = _interopRequireDefault(_isCharConsonant);

var _toKana = require('./toKana');

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

/* import { addDebugListeners, removeDebugListeners } from './utils/logInputEvents';*/

var ELEMENTS = ['TEXTAREA', 'INPUT'];
var LISTENERS = [];
var idCounter = 0;
var ignoreMicrosoftIMEDoubleConsonant = false;

var newId = function newId() {
  idCounter += 1;
  return '' + Date.now() + idCounter;
};

/**
 * Binds eventListener for 'input' events to an input field to automagically replace values with kana
 * Can pass { IMEMode: 'toHiragana' } or `'toKatakana'` as second param to enforce kana conversion type
 * @param  {HTMLElement} input textarea, input[type="text"] etc
 * @param  {DefaultOptions} [options=defaultOptions] defaults to { IMEMode: true } using `toKana`
 */
function bind(input) {
  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

  var listener = onInput(options);
  if (input instanceof Element && ELEMENTS.includes(input.nodeName)) {
    var id = newId();
    /* addDebugListeners(input);*/
    input.setAttribute('data-wanakana-id', id);
    input.autocapitalize = 'none';
    input.addEventListener('compositionupdate', onCompositionUpdate);
    input.addEventListener('input', listener);
    LISTENERS = trackListener(listener, id);
  } else {
    // eslint-disable-next-line no-console
    console.warn('Input provided to Wanakana bind() was not a valid input field.');
  }
}

/**
 * Unbinds eventListener from input field
 * @param  {HTMLElement} input textarea, input[type="text"] etc
 */
function unbind(input) {
  var trackedListener = findListener(input);
  if (trackedListener != null) {
    /* removeDebugListeners(input); */
    input.removeAttribute('data-wanakana-id');
    input.removeEventListener('compositionupdate', onCompositionUpdate);
    input.removeEventListener('input', trackedListener.handler);
    LISTENERS = untrackListener(trackedListener);
  } else {
    console.warn('Input called with Wanakana unbind() had no listener registered.'); // eslint-disable-line no-console
  }
}

/**
 * Automagically replaces input values with converted text to kana
 * @param  {Object} event DOM event to listen to
 * @param  {defaultOptions} [options] user config overrides, default conversion is toKana()
 * @return {Function} event handler with bound options
 * @ignore
 */
function onInput(options) {
  var config = Object.assign({}, _constants.DEFAULT_OPTIONS, options);

  return function listener(event) {
    var input = event.target;

    if (ignoreMicrosoftIMEDoubleConsonant) {
      ignoreMicrosoftIMEDoubleConsonant = false;
      return;
    }

    var normalizedInputString = (0, _convertFullwidthCharsToASCII2.default)(input.value);
    var hiraOrKataString = setKanaType(normalizedInputString, config.IMEMode);
    var ensureIMEModeConfig = Object.assign({}, config, { IMEMode: true });
    var kanaTokens = (0, _toKana.splitIntoKana)(hiraOrKataString, ensureIMEModeConfig);
    var newText = kanaTokens.map(function (token) {
      return token[2];
    }).join('');

    if (normalizedInputString !== newText) {
      var selectionEnd = input.selectionEnd;

      input.value = newText;

      // Modern browsers
      if (input.setSelectionRange != null && typeof input.selectionStart === 'number') {
        if (selectionEnd === 0) {
          input.setSelectionRange(0, 0);
        } else {
          input.setSelectionRange(input.value.length, input.value.length);
          var kanaLength = 0;
          for (var index = 0; index < kanaTokens.length; index += 1) {
            var currentToken = kanaTokens[index];
            var tokenEnd = currentToken[1];
            var tokenKana = currentToken[2];
            kanaLength += tokenKana.length;
            if (tokenEnd >= selectionEnd) {
              input.setSelectionRange(kanaLength, kanaLength);
              break;
            }
          }
        }
        return;
      }
      // < IE 9
      if (input.createTextRange != null) {
        input.focus();
        var range = input.createTextRange();
        range.collapse(false);
        range.select();
      }
    }
  };
}

/**
 * Sets a flag on compositionupdate for a once-off ignore in onInput
 * see https://github.com/WaniKani/WanaKana/issues/48
 * @param  {object} event compositionupdate event
 */
function onCompositionUpdate(event) {
  var data = event.data || event.detail && event.detail.data; // have to use custom event with detail in tests
  var finalTwoChars = data && data.slice(-2) || '';
  var isFirstLetterN = finalTwoChars[0] === 'n';
  var isDoubleConsonant = (0, _convertFullwidthCharsToASCII2.default)(finalTwoChars).split('').every(_isCharConsonant2.default);

  ignoreMicrosoftIMEDoubleConsonant = !isFirstLetterN && isDoubleConsonant;
}

function trackListener(listener, id) {
  return LISTENERS.concat({
    id: id,
    handler: listener
  });
}

function findListener(input) {
  return input && LISTENERS.find(function (_ref) {
    var id = _ref.id;
    return id === input.getAttribute('data-wanakana-id');
  });
}

function untrackListener(_ref2) {
  var targetId = _ref2.id;

  return LISTENERS.filter(function (_ref3) {
    var id = _ref3.id;
    return id !== targetId;
  });
}

// easy way to still use `toKana` to handle IME input - but with forced conversion type
function setKanaType(input, flag) {
  switch (true) {
    case flag === 'toHiragana':
      return input.toLowerCase();
    case flag === 'toKatakana':
      return input.toUpperCase();
    default:
      return input;
  }
}