var MentionExtension = MediumEditor.Extension.extend({
    name: 'mediumMention',
    init: function() {
        this.subscribe('editableKeyup', this.handleKeyup.bind(this));
        this.subscribe('editableKeydown', this.handleKeydown.bind(this));
        this.subscribe('blur', this.cancel.bind(this));
    },
    isEditMode: function() {
        return !this.base.origElements.parentNode.classList.contains('read-mode');
    },
    cancel: function() {
        if (this.isEditMode()) {
            this.hidePanel();
            this.reset();
        }
    },
    handleKeydown: function(e) {
        var code = e.keyCode ? e.keyCode : e.which;

        if (this.mentionPanel && code === MediumEditor.util.keyCode.ENTER) {
            e.preventDefault();
        }
    },
    handleKeyup: function(e) {
        var code = e.keyCode ? e.keyCode : e.which;
        var isSpace = code === MediumEditor.util.keyCode.SPACE;
        var isBackspace = code === MediumEditor.util.keyCode.BACKSPACE;

        if (this.mentionPanel) {
            this.keyDownMentionPanel(e);
        }

        var moveKeys = [37, 38, 39, 40];

        if (moveKeys.indexOf(code) !== -1) {
            return;
        }

        this.selection = this.document.getSelection();

        if (isBackspace && this.selection.focusNode.nodeName.toLowerCase() === 'p') {
            return;
        }

        if (!isSpace && this.selection.rangeCount === 1) {
            var endChar = this.selection.getRangeAt(0).startOffset;
            var textContent = this.selection.focusNode.textContent;

            textContent = textContent.substring(0, endChar);
            this.word = this.getLastWord(textContent);

            if (this.word.length > 1 && ['@', '#', ':'].indexOf(this.word[0]) != -1) {
                this.wrap();
                this.showPanel();

                MediumEditor.selection.select(
                  this.document,
                  this.wordNode.firstChild,
                  this.word.length
                );

                return;
            }
        } else if (isSpace) {
            this.cancelMentionSpace();
        }

        this.hidePanel();
    },
    reset: function() {
        this.wordNode = null;
        this.word = null;
        this.selection = null;
    },
    cancelMentionSpace: function() {
        if (this.wordNode && this.wordNode.nextSibling) {
            var textNode = this.document.createTextNode('');
            textNode.textContent = this.word + '\u00A0';

            this.wordNode.parentNode.replaceChild(textNode, this.wordNode);

            MediumEditor.selection.select(this.document, textNode, this.word.length + 1);
        }

        this.reset();
    },
    wrap: function() {
        var range = this.selection.getRangeAt(0).cloneRange();

        if (range.startContainer.parentNode.nodeName.toLowerCase() === 'a') {
            var parentLink = range.startContainer.parentNode.parentNode;
            var textNode = this.document.createTextNode(range.startContainer.parentNode.innerText);

            parentLink.replaceChild(textNode, range.startContainer.parentNode);

            this.selection.removeAllRanges();

            range = document.createRange();

            range.setStart(textNode, textNode.length);
            range.setEnd(textNode, textNode.length);

            this.selection.addRange(range);
        }

        if (!range.startContainer.parentNode.classList.contains('mention')) {
            this.wordNode = this.document.createElement('span');
            this.wordNode.classList.add('mention');

            range.setStart(range.startContainer, this.selection.getRangeAt(0).startOffset - this.word.length);
            range.surroundContents(this.wordNode);

            this.selection.removeAllRanges();
            this.selection.addRange(range);

            //move cursor to old position
            range.setStart(range.startContainer, range.endOffset);
            range.setStart(range.endContainer, range.endOffset);
            this.selection.removeAllRanges();
            this.selection.addRange(range);
        } else {
            this.wordNode = range.startContainer.parentNode;
        }
    },
    refreshPositionPanel: function() {
        var bound = this.wordNode.getBoundingClientRect();

        this.mentionPanel.style.top = this.window.pageYOffset + bound.bottom + 'px';
        this.mentionPanel.style.left = this.window.pageXOffset + bound.left + 'px';
    },
    selectMention: function(item) {
        if (item.image) {
            var img = document.createElement('img');
            img.src = item.image;

            this.wordNode.parentNode.replaceChild(img, this.wordNode);
            this.wordNode = img;
        } else {
            var link = document.createElement('a');

            link.setAttribute('href', item.url);

            if (item.ref) {
                link.innerText = '#' + item.ref + '-' + item.subject;
            } else {
                link.innerText = '@' + item.username;
            }

            this.wordNode.parentNode.replaceChild(link, this.wordNode);
            this.wordNode = link;
        }

        var textNode = this.document.createTextNode('');
        textNode.textContent = '\u00A0';

        this.wordNode.parentNode.insertBefore(textNode, this.wordNode.nextSibling);
        MediumEditor.selection.select(this.document, textNode, 1);

        var target = this.base.getFocusedElement();

        this.base.events.updateInput(target, {
          target: target,
          currentTarget: target
        });

        this.hidePanel();
        this.reset();
    },
    showPanel: function() {
        if(document.querySelectorAll('.medium-editor-mention-panel').length) {
            this.refreshPositionPanel();
            this.getItems(this.word, this.renderPanel.bind(this));
            return;
        }

        var  el = this.document.createElement('div');
        el.classList.add('medium-editor-mention-panel');
        this.mentionPanel = el;
        this.getEditorOption('elementsContainer').appendChild(el);

        this.refreshPositionPanel();
        this.getItems(this.word, this.renderPanel.bind(this));
    },
    keyDownMentionPanel: function(e) {
        var code = e.keyCode ? e.keyCode : e.which;
        var active = this.mentionPanel.querySelector('.active');

        this.wordNode = document.querySelector('span.mention');

        if(!active) {
            return;
        }

        if (code === MediumEditor.util.keyCode.ENTER) {
            e.preventDefault();
            e.stopPropagation();

            var event = document.createEvent('HTMLEvents');
            event.initEvent('mousedown', true, false);

            active.dispatchEvent(event);

            return;
        }

        active.classList.remove('active');

        if (code === 38) {
            if(active.previousSibling) {
                active.previousSibling.classList.add('active');
            } else {
                active.parentNode.lastChild.classList.add('active');
            }
        } else if (code === 40) {
            if(active.nextSibling) {
                active.nextSibling.classList.add('active');
            } else {
                active.parentNode.firstChild.classList.add('active');
            }
        }
    },
    renderPanel: function(items) {
        this.mentionPanel.innerHTML = '';

        if (!items.length) return;

        var ul = this.document.createElement('ul');

        ul.classList.add('medium-mention');

        items.forEach(function(it) {
            var li = this.document.createElement('li');

            if (it.image) {
                var img = this.document.createElement('img');

                img.src = it.image;
                li.appendChild(img);

                var textNode = document.createTextNode('');
                textNode.textContent = ' ' + it.name;

                li.appendChild(textNode);

            } else if (it.ref) {
                li.innerText = '#' + it.ref + ' - ' + it.subject;
            } else {
                li.innerText = '@' + it.username;
            }

            li.addEventListener('mousedown', this.selectMention.bind(this, it));

            ul.appendChild(li);
        }.bind(this));

        ul.firstChild.classList.add('active');

        this.mentionPanel.appendChild(ul);
    },
    hidePanel: function() {
        if (this.mentionPanel) {
            this.mentionPanel.parentNode.removeChild(this.mentionPanel);
            this.mentionPanel = null;
        }
    },
    getLastWord: function(text) {
        var n = text.split(' ');
        return n[n.length - 1].trim();
    }
});
