import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
import CodeMirror, { Pos } from 'codemirror';
import 'codemirror/addon/hint/anyword-hint';
var anywordHint = CodeMirror.hint.anyword;

CodeMirror.hint.javascript = function (instance, options) {
  var _getTokenInfo = getTokenInfo(instance),
      cursor = _getTokenInfo.cursor,
      token = _getTokenInfo.token,
      empty = _getTokenInfo.empty;

  if (!/[\w.'"`]$/.test(token.string)) {
    return empty;
  }

  var result = anywordHint(instance, options) || empty;
  result.list = options.snippets.filter(function (snippet) {
    return startWith(snippet.prefix || snippet, token.string);
  }).concat(result.list);

  if (token.type === 'string') {
    var start = {
      line: cursor.line,
      ch: token.start + 1
    };
    var prefix = instance.getLine(cursor.line).substr(start.ch, cursor.ch - start.ch);
    result.list = getCompleteNames(options.files, start, prefix).concat(result.list);
  }

  result.list = uniquify(result.list);
  return result;
};

var htmlHint = CodeMirror.hint.html;

CodeMirror.hint.html = function (instance, options) {
  var _getTokenInfo2 = getTokenInfo(instance),
      cursor = _getTokenInfo2.cursor,
      token = _getTokenInfo2.token,
      empty = _getTokenInfo2.empty;

  if (token.type === null) {
    return empty;
  }

  if (token.type === 'tag bracket' && token.string === '>') {
    return empty;
  }

  var result = htmlHint(instance, options) || empty;

  if (token.type === 'string') {
    var start = {
      line: cursor.line,
      ch: token.start + 1
    };
    var prefix = instance.getLine(cursor.line).substr(start.ch, cursor.ch - start.ch);
    result.list = getCompleteNames(options.files, start, prefix).concat(result.list);
  }

  result.list = uniquify(result.list);
  return result;
};

var cssHint = CodeMirror.hint.css;

CodeMirror.hint.css = function (instance, options) {
  var _getTokenInfo3 = getTokenInfo(instance),
      cursor = _getTokenInfo3.cursor,
      token = _getTokenInfo3.token,
      empty = _getTokenInfo3.empty;

  if (token.type === null) {
    return empty;
  }

  var result = cssHint(instance, options) || empty;

  if (token.type === 'string') {
    var start = new Pos(cursor.line, token.start);
    result.list = getCompleteNames(options.files, start, token.string).concat(result.list);
  }

  result.list = uniquify(result.list);
  return result;
};

CodeMirror.hint.markdown = function (instance, options) {
  var _getTokenInfo4 = getTokenInfo(instance),
      cursor = _getTokenInfo4.cursor,
      token = _getTokenInfo4.token,
      from = _getTokenInfo4.from,
      to = _getTokenInfo4.to,
      empty = _getTokenInfo4.empty;

  if (token.type === 'string url') {
    var start = {
      line: cursor.line,
      ch: token.string[0] === '(' ? token.start + 1 : token.start
    };
    var prefix = instance.getLine(cursor.line).substr(start.ch, cursor.ch - start.ch);
    return {
      list: getCompleteNames(options.files, start, prefix),
      from: from,
      to: to
    };
  }

  if (!/[A-Za-z.'"`([]$/.test(token.string)) {
    return empty;
  }

  var result = empty;
  result.list = options.snippets.filter(function (snippet) {
    return startWith(snippet.prefix, token.string);
  }).concat(result.list);
  result.list = uniquify(result.list);
  return result;
};

CodeMirror.hint.glsl = function (instance, options) {
  var _getTokenInfo5 = getTokenInfo(instance),
      token = _getTokenInfo5.token,
      empty = _getTokenInfo5.empty;

  if (token.type === null) {
    return empty;
  }

  return CodeMirror.hint.anyword(instance, options);
};

function getCompleteNames(files, from) {
  var prefix = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
  return files.filter(function (file) {
    return startWith(file.name, prefix);
  }).map(function (file) {
    return {
      text: file.name,
      from: from
    };
  });
}

function startWith(text, needle) {
  if (typeof text !== 'string' || typeof needle !== 'string') {
    return false; // fix patch of https://rollbar.com/HackforPlay/portal/items/1308
  }

  return text.toLowerCase().indexOf(needle.toLowerCase()) === 0;
}

function getTokenInfo(instance) {
  var cursor = instance.getCursor();
  var token = instance.getTokenAt(cursor);
  var from = {
    line: cursor.line,
    ch: token.start
  };
  var to = {
    line: cursor.line,
    ch: cursor.ch
  };
  var empty = {
    list: [],
    from: from,
    to: to
  };
  return {
    cursor: cursor,
    token: token,
    from: from,
    to: to,
    empty: empty
  };
} // 同じ文字列または text に同じ文字列が入っているオブジェクトを排除する


function uniquify(array) {
  var result = [];
  var textArray = array.map(function (item) {
    return typeof item.text === 'string' ? item.text : item;
  });
  var _iteratorNormalCompletion = true;
  var _didIteratorError = false;
  var _iteratorError = undefined;

  try {
    for (var _iterator = textArray.entries()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
      var _step$value = _slicedToArray(_step.value, 2),
          index = _step$value[0],
          text = _step$value[1];

      // indexOf で配列内の最初に出てくるインデックスを取得
      // index と一致するなら配列内の最初の要素, 条件に合うものだけ push すればユニークになる
      if (index === textArray.indexOf(text)) {
        result.push(array[index]);
      }
    }
  } catch (err) {
    _didIteratorError = true;
    _iteratorError = err;
  } finally {
    try {
      if (!_iteratorNormalCompletion && _iterator.return != null) {
        _iterator.return();
      }
    } finally {
      if (_didIteratorError) {
        throw _iteratorError;
      }
    }
  }

  return result;
}