/*global CodeMirror */

import MarkerManager from 'ghost/mixins/marker-manager';
import mobileCodeMirror from 'ghost/utils/codemirror-mobile';
import setScrollClassName from 'ghost/utils/set-scroll-classname';
import codeMirrorShortcuts from 'ghost/utils/codemirror-shortcuts';

var onChangeHandler,
    onScrollHandler,
    Codemirror;

codeMirrorShortcuts.init();

onChangeHandler = function (cm, changeObj) {
    var line,
        component = cm.component;

    // fill array with a range of numbers
    for (line = changeObj.from.line; line < changeObj.from.line + changeObj.text.length; line += 1) {
        component.checkLine.call(component, line, changeObj.origin);
    }

    // Is this a line which may have had a marker on it?
    component.checkMarkers.call(component);

    cm.component.set('value', cm.getValue());

    component.sendAction('typingPause');
};

onScrollHandler = function (cm) {
    var scrollInfo = cm.getScrollInfo(),
        component = cm.component;

    scrollInfo.codemirror = cm;

    // throttle scroll updates
    component.throttle = Ember.run.throttle(component, function () {
        this.set('scrollInfo', scrollInfo);
    }, 10);
};

Codemirror = Ember.TextArea.extend(MarkerManager, {
    focus: true,
    focusCursorAtEnd: false,

    setFocus: function () {
        if (this.get('focus')) {
            this.$().val(this.$().val()).focus();
        }
    }.on('didInsertElement'),

    didInsertElement: function () {
        Ember.run.scheduleOnce('afterRender', this, this.afterRenderEvent);
    },

    afterRenderEvent: function () {
        var self = this,
            codemirror;

        // replaces CodeMirror with TouchEditor only if we're on mobile
        mobileCodeMirror.createIfMobile();

        codemirror = this.initCodemirror();
        this.set('codemirror', codemirror);

        this.sendAction('setCodeMirror', this);

        if (this.get('focus') && this.get('focusCursorAtEnd')) {
            codemirror.execCommand('goDocEnd');
        }

        codemirror.eachLine(function initMarkers() {
            self.initMarkers.apply(self, arguments);
        });
    },

    // this needs to be placed on the 'afterRender' queue otherwise CodeMirror gets wonky
    initCodemirror: function () {
        // create codemirror
        var codemirror,
            self = this;

        codemirror = CodeMirror.fromTextArea(this.get('element'), {
            mode:           'gfm',
            tabMode:        'indent',
            tabindex:       '2',
            cursorScrollMargin: 10,
            lineWrapping:   true,
            dragDrop:       false,
            extraKeys: {
                Home:   'goLineLeft',
                End:    'goLineRight',
                'Ctrl-U': false,
                'Cmd-U': false,
                'Shift-Ctrl-U': false,
                'Shift-Cmd-U': false,
                'Ctrl-S': false,
                'Cmd-S': false,
                'Ctrl-D': false,
                'Cmd-D': false
            }
        });

        // Codemirror needs a reference to the component
        // so that codemirror originating events can propogate
        // up the ember action pipeline
        codemirror.component = this;

        // propagate changes to value property
        codemirror.on('change', onChangeHandler);

        // on scroll update scrollPosition property
        codemirror.on('scroll', onScrollHandler);

        codemirror.on('scroll', Ember.run.bind(Ember.$('.CodeMirror-scroll'), setScrollClassName, {
            target: Ember.$('.js-entry-markdown'),
            offset: 10
        }));

        codemirror.on('focus', function () {
            self.sendAction('onFocusIn');
        });

        return codemirror;
    },

    disableCodeMirror: function () {
        var codemirror = this.get('codemirror');

        codemirror.setOption('readOnly', 'nocursor');
        codemirror.off('change', onChangeHandler);
    },

    enableCodeMirror: function () {
        var codemirror = this.get('codemirror');

        codemirror.setOption('readOnly', false);

        // clicking the trash button on an image dropzone causes this function to fire.
        // this line is a hack to prevent multiple event handlers from being attached.
        codemirror.off('change', onChangeHandler);

        codemirror.on('change', onChangeHandler);
    },

    removeThrottle: function () {
        Ember.run.cancel(this.throttle);
    }.on('willDestroyElement'),

    removeCodemirrorHandlers: function () {
        // not sure if this is needed.
        var codemirror = this.get('codemirror');
        codemirror.off('change', onChangeHandler);
        codemirror.off('scroll');
    }.on('willDestroyElement'),

    clearMarkerManagerMarkers: function () {
        this.clearMarkers();
    }.on('willDestroyElement')
});

export default Codemirror;