require([
  'assets/libs/js/codemirror/lib/codemirror',
  'assets/libs/js/codemirror/addon/selection/active-line',
  'assets/libs/js/codemirror/addon/lint/lint',
  'assets/libs/js/codemirror/addon/hint/show-hint',
  'assets/libs/js/codemirror/addon/mode/simple',
], function (CodeMirror) {
    var WORD = /[\w$]+/, RANGE = 500;

    var functions = [
            "and()",
            "jump()",
            "or()",
            "sum()",
            "timer()",
            "truncate()",
            "xor()",
        ],
        variables = [
            "A1", "A2", "A3", "A4",
            "D1", "D2", "D3", "D4", "D5", "D6",
            "DI1", "DI2", "DI3", "DI4", "DI5", "DI6", "DI7",
            "AI1", "AI2",
        ];

    var compilationErrors;

    CodeMirror.registerHelper("hint", "fixed", function (editor, options) {
        var word = options && options.word || WORD;
        var range = options && options.range || RANGE;
        var cur = editor.getCursor(), curLine = editor.getLine(cur.line);
        var end = cur.ch, start = end;
        while (start && word.test(curLine.charAt(start - 1)))--start;
        var curWord = start != end && curLine.slice(start, end);

        var fullList = options && options.list || [];
        var list = [];
        var re = new RegExp(word.source, "g");
        //for (var dir = -1; dir <= 1; dir += 2) {
        //    var line = cur.line, endLine = Math.min(Math.max(line + dir * range, editor.firstLine()), editor.lastLine()) + dir;
        //    for (; line != endLine; line += dir) {
        //        var text = editor.getLine(line), m;
        for (var i = 0, len = fullList.length; i < len; i++) {
            var text = fullList[i];
            //while (m = re.exec(text)) {
            //    if (m[0] === curWord) continue;
            if ((!curWord || text.lastIndexOf(curWord, 0) == 0)) {
                //seen[m[0]] = true;
                list.push(text);
            }
            //}
        }

        return { list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end) };

        //var cur = editor.getCursor(),
        //    curLine = editor.getLine(cur.line);
        //var end = cur.ch, start = end;
        //while (start && word.test(curLine.charAt(start - 1)))--start;
        //var curWord = start != end && curLine.slice(start, end);

        //var filterList = [];
        //var fullList = options && options.list || [
        //    "hola",
        //    "chau",
        //];

        //var re = new RegExp(curLine, "g");

        //for (var i = 0, len = fullList.length; i < len; i++)
        //{
        //    var word = fullList[i];

        //    if (m = re.exec(word))
        //        filterList.push(word);
        //}

        //return {
        //    list: filterList,
        //    from: CodeMirror.Pos(cur.line, start),
        //    to: CodeMirror.Pos(cur.line, end),
        //};
    });

    CodeMirror.registerHelper("lint", "dot", function (text) {
        var found = [];

        if (compilationErrors) {
            for (var i = 0, len = compilationErrors.length; i < len; i++) {
                var comError = compilationErrors[i];

                found.push({
                    from: CodeMirror.Pos(comError.Line, 1),
                    to: CodeMirror.Pos(comError.Line, 1),
                    message: comError.Message,
                    severity: "error",
                });
            }

            //found.push({
            //    from: CodeMirror.Pos(0, 1),
            //    to: CodeMirror.Pos(0, 10),
            //    message: "Warning 1",
            //    severity: "warning",
            //});
        }

        return found;
    });

    CodeMirror.defineSimpleMode("dot", {
        // The start state contains the rules that are intially used
        start: [
          // The regex matches the token, the token property contains the type
          //{ regex: /"(?:[^\\]|\\.)*?"/, token: "string" },
          { regex: /^(A|D|AI|DI|)[0-9]+?/, token: "dot-variable" },
          //{ regex: /([0-9a-zA-Z]+)(\()(.+)(\))/, token: ["dot-variable", , "dot-variable", null, "dot-variable", ] },
          // You can match multiple tokens at once. Note that the captured
          // groups must span the whole string in this case
          //{regex: /(function)(\s+)([a-z$][\w$]*)/, token: ["keyword", null, "variable-2"]},
          // Rules are matched in the order in which they appear, so there is
          // no ambiguity between this one and the one above
          //{regex: /(?:function|var|return|if|for|while|else|do|this)\b/, token: "keyword"},
          //{regex: /true|false|null|undefined/, token: "atom"},
          //{regex: /0x[a-f\d]+|[-+]?(?:\.\d+|\d+\.?\d*)(?:e[-+]?\d+)?/i, token: "number"},
          //{regex: /\/\/.*/, token: "comment"},
          //{regex: /\/(?:[^\\]|\\.)*?\//, token: "variable-3"},
          // A next property will cause the mode to move to a different state
          //{regex: /\/\*/, token: "comment", next: "comment"},
          //{regex: /[-+\/*=<>!]+/, token: "operator"},
          // indent and dedent properties guide autoindentation
          //{regex: /[\{\[\(]/, indent: true},
          //{regex: /[\}\]\)]/, dedent: true},
          //{regex: /[a-z$][\w$]*/, token: "variable"},
          // You can embed other modes with the mode property. This rule
          // causes all code between << and >> to be highlighted with the XML
          // mode.
          //{regex: /<</, token: "meta", mode: {spec: "xml", end: />>/}}
        ],
        // The multi-line comment state.
        comment: [
          { regex: /.*?\*\//, token: "comment", next: "start" },
          { regex: /.*/, token: "comment" }
        ],
        // The meta property contains global information about the mode. It
        // can contain properties like lineComment, which are supported by
        // all modes, and also directives like dontIndentStates, which are
        // specific to simple modes.
        meta: {
            dontIndentStates: ["comment"],
            lineComment: "//"
        }
    });

    CodeMirror.commands.autocomplete = function (cm) {
        cm.showHint({
            hint: CodeMirror.hint.fixed,
            list: [].concat(functions, variables),
        });
    }

    return CodeMirror;
});