
/**
 * @param {string} servicename
 * @return {Element}
**/
function createSlashAutocompleteHeader(servicename) {
    var lh = document.createElement("lh");
    lh.textContent = servicename;
    lh.className = R.klass.commands.header;
    return lh;
}

/**
 * @param {Command|{names: Array<string>!, desc: string!, usage: string!,category: string!, exec: Function!}|string} cmd
 * @param {Element=} imgSpan
 * @return {Element}
**/
function createSlashAutocompleteDom(cmd, imgSpan) {
    var li = document.createElement("li")
        ,name = document.createElement("span")

    name.className = R.klass.commands.name;

    if (typeof cmd === "string") {
        if (imgSpan) {
            li.appendChild(imgSpan);
        }
        name.textContent = cmd;
        li.appendChild(name);
    } else {
        var usage = document.createElement("span")
            ,desc = document.createElement("span");

        name.textContent = cmd.name;

        usage.textContent = cmd.usage;
        desc.textContent = cmd.desc;
        usage.className = R.klass.commands.usage;
        desc.className = R.klass.commands.desc;
        li.appendChild(name);
        li.appendChild(usage);
        li.appendChild(desc);
    }

    li.dataset.input = name.textContent;
    li.className = R.klass.commands.item;
    return li;
}

function autoComplete(inputDom) {
    var now = Date.now(),
        slashDom = document.getElementById(R.id.message.slashComplete);

    if (slashDom.dataset.cursor)
        delete slashDom.dataset.cursor;
    var /** @type {Array<Chatter|Room|Command|{names: Array<string>!, desc: string!, usage: string!, category: string!, exec: Function!}|{name: string, provider: string, emojiSpan: Element}>} */
        commands = [],
        /** @const @type {string} */
        input = inputDom.value;
    if (inputDom.selectionStart === inputDom.selectionEnd && inputDom.selectionStart) {
        var start = inputDom.selectionStart,
            end = inputDom.selectionEnd;
        for (; start && input[start -1] !== ' '; start--) {}
        for (var valueLen = input.length; end < valueLen && input[end] !== ' '; end++) {}
        if (start !== end && end -start -1 > 0) {
            if (input[start] === '#') {
                var channels = SELECTED_CONTEXT.getChatContext().channels,
                    inputStr = input.substr(start +1, end -start -1);
                for (var i in channels) {
                    if (channels[i].name.length >= inputStr.length && channels[i].name.substr(0, inputStr.length) === inputStr)
                        commands.push(channels[i]);
                }
            } else if (input[start] === '@') {
                var users = SELECTED_ROOM instanceof PrivateMessageRoom ? SELECTED_CONTEXT.getChatContext().users : SELECTED_ROOM.users,
                    inputStr = input.substr(start +1, end -start -1);
                for (var i in users) {
                    var userName = users[i].getName();
                    if (userName.length >= inputStr.length && userName.substr(0, inputStr.length) === inputStr)
                        commands.push(users[i]);
                }
            } else if (input[start] === ':' && window['searchEmojis']) {
                var inputCmd = input.substr(start +1, end -start -1),
                    emojiList = window['searchEmojis'](inputCmd);

                for (var emojiCode in emojiList) {
                    var domEmoji = window['makeEmoji'](emojiCode, false),
                        domParent = document.createElement("span");

                    domParent.appendChild(domEmoji);
                    domParent.className = R.klass.emoji.small;
                    commands.push({
                        name: ':' +emojiCode +':',
                        emojiSpan: domParent,
                        provider: CURRENT_EMOJI_PROVIDER.name
                    });
                }
                for (var i in SELECTED_CONTEXT.getChatContext().emojis.data) {
                    if (i.length >= inputCmd.length && i.substr(0, inputCmd.length) === inputCmd) {
                        var emojiSpan = document.createElement("span");
                        emojiSpan.className = R.klass.emoji.small;
                        emojiSpan.appendChild(makeEmojiDom(i));
                        commands.push({
                            name: ':' +i +':',
                            emojiSpan: emojiSpan,
                            provider: "custom"
                        });
                    }
                }
            }
            if (commands.length)
                slashDom.dataset.cursor = JSON.stringify([start, end]);
        }
    }
    if (!commands.length && input[0] === '/') {
        var endCmd = input.indexOf(' '),
            inputFinished = endCmd !== -1;
        endCmd = endCmd === -1 ? input.length : endCmd;
        var inputCmd = input.substr(0, endCmd);

        if (inputFinished) {
            var currentClientCmd = CLIENT_COMMANDS.getCommand(inputCmd);
            if (currentClientCmd)
                commands.push(currentClientCmd);
        } else {
            commands = CLIENT_COMMANDS.getCommandsStartingWith(inputCmd);
            slashDom.dataset.cursor = JSON.stringify([0, inputDom.selectionEnd]);
        }
        var availableCommands = (SELECTED_CONTEXT ? SELECTED_CONTEXT.getChatContext().commands.data : {});
        for (var currentCmdId in availableCommands) {
            var currentCmd = availableCommands[currentCmdId];
            if ((!inputFinished && currentCmd.name.substr(0, endCmd) === inputCmd) ||
                (inputFinished && currentCmd.name === inputCmd))
                commands.push(currentCmd);
        }
        commands.sort(function(a, b) {
            return a.category.localeCompare(b.category) || a.name.localeCompare(b.name);
        });
    }
    slashDom.textContent = '';
    if (commands.length) {
        var slashFrag = document.createDocumentFragment(),
            prevService;
        for (var i =0, nbCmd = commands.length; i < nbCmd; i++) {
            var command = commands[i];
            if (command instanceof Chatter) {
                if (!prevService) {
                    prevService = true;
                    slashFrag.appendChild(createSlashAutocompleteHeader(locale.members));
                }
                var span = document.createElement("span");
                span.className = R.klass.commands.userIcon;
                span.style.backgroundImage = "url(\"" +command.getSmallIcon() +"\")";
                slashFrag.appendChild(createSlashAutocompleteDom('@' +command.getName(), span));
            } else if (command instanceof Room) {
                if (!prevService) {
                    prevService = true;
                    slashFrag.appendChild(createSlashAutocompleteHeader(locale.channels));
                }
                slashFrag.appendChild(createSlashAutocompleteDom('#' +command.name));
            } else if (command.emojiSpan) {
                if (prevService !== command.provider) {
                    prevService = command.provider;
                    slashFrag.appendChild(createSlashAutocompleteHeader(command.provider));
                }
                slashFrag.appendChild(createSlashAutocompleteDom(command.name, command.emojiSpan));
            } else {
                if (prevService !== command.category) {
                    prevService = command.category;
                    slashFrag.appendChild(createSlashAutocompleteHeader(command.category));
                }
                slashFrag.appendChild(createSlashAutocompleteDom(command));
            }
        }
        slashDom.appendChild(slashFrag);
    }
}

/**
 * @param {string} input
 * @param {boolean=} skipCommand
 * @return {boolean} true on recognized input
**/
function onTextEntered(input, skipCommand) {
    var success = true;
    if (EDITING) {
        editMsg(SELECTED_ROOM, input, EDITING);
        return true;
    }
    if (input[0] === '/' && skipCommand !== true) {
        var endCmd = input.indexOf(' '),
            cmd = input.substr(0, endCmd === -1 ? undefined : endCmd),
            args = endCmd === -1 ? "" : input.substr(endCmd),
            ctx = SELECTED_CONTEXT,
            cliCmdObject = CLIENT_COMMANDS.getCommand(cmd);

        if (cliCmdObject) {
            args = args.trim();
            cliCmdObject.exec(ctx, SELECTED_ROOM, args);
            return true;
        } else if (ctx) {
            var cmdObject = ctx.getChatContext().commands.data[cmd];

            if (cmdObject) {
                if (cmdObject.name === "/me") {
                    displayTmpMessage(SELECTED_ROOM, args, true);
                } else if (cmdObject.name === "/msg") {
                    args = args.trim();
                    var argParts = (/(\S+)\s+(.*)/).exec(args),
                        chan = SELECTED_CONTEXT.getRoom(argParts[1]);
                    if (chan)
                        displayTmpMessage(chan, argParts[2], false);
                }
                doCommand(SELECTED_ROOM, cmdObject, args);
                return true;
            }
        }
        return false;
    }
    var tmpMsg = displayTmpMessage(SELECTED_ROOM, input, false);
    sendMsg(SELECTED_ROOM, input, tmpMsg, REPLYING_TO);
    return true;
}

function focusInput() {
    document.getElementById(R.id.message.input).focus();
}

function updateInputRowCount(input) {
    var nbRows = 1;
    for (var i =0, nbChars = input.value.length; i < nbChars; i++)
        if (input.value[i] === '\n')
            nbRows++;
    input.rows = Math.min(5, nbRows);
    while (input.rows < 5 && input.scrollHeight > input.clientHeight) // FIXME very very ugly
        input.rows++;
}

function initMsgInput() {
    var lastKeyDown = 0,
        input = document.getElementById(R.id.message.input);

    input.addEventListener('input', function() {
        if (SELECTED_ROOM) {
            var now = Date.now();

            if (lastKeyDown + 3000 < now && (SELECTED_CONTEXT.getChatContext().self.presence || (SELECTED_ROOM instanceof PrivateMessageRoom))) {
                sendTyping(SELECTED_ROOM);
                lastKeyDown = now;
            }
            autoComplete(this);
            updateInputRowCount(this);
        }
    });

    input.addEventListener("keydown", function(e) {
        var
            /** @const */
            TAB_KEY = 9,
            /** @const */
            ENTER_KEY = 13;
        if (e.keyCode === TAB_KEY) {
            e.preventDefault();
            // FIXME cycle though propositions
            return false;
        } else if (e.keyCode === ENTER_KEY) {
            e.preventDefault();
            if (e.shiftKey || e.altKey || e.ctrlKey) {
                var selectionEnd = this.selectionEnd,
                    selectionStart = this.selectionStart;
                this.value = this.value.substr(0, selectionStart) +'\n' +this.value.substr(selectionEnd);
                updateInputRowCount(this);
                this.selectionStart = this.selectionEnd = selectionStart +1;
            } else {
                onMsgFormSubmit();
            }
            return false;
        }
    });

    document.getElementById(R.id.message.slashComplete).addEventListener("click", function(e) {
        if (SELECTED_ROOM) {
            var target = e.target;
            var cursor = this.dataset.cursor;
            if (cursor) {
                cursor = JSON.parse(cursor);
                while (target && target !== this) {
                    if (target.dataset.input) {
                        var inputElement = document.getElementById(R.id.message.input),
                            toAdd = target.dataset.input;

                        if (inputElement.value.length <= cursor[1])
                            toAdd += ' ';

                        inputElement.value = inputElement.value.substr(0, cursor[0]) +toAdd +inputElement.value.substr(cursor[1]);
                        inputElement.selectionStart = inputElement.selectionEnd = cursor[0] +toAdd.length;
                        autoComplete(inputElement);
                        inputElement.focus();
                        break;
                    }
                    target = target.parentElement;
                }
            }
        }
    });

}

