;(function (define, undefined) {
'use strict';
define([
    'jquery', 'underscore', 'annotator_1.2.9', 'js/edxnotes/utils/utils'
], function ($, _, Annotator, Utils) {
    var _t = Annotator._t;

    /**
     * The original _setupDynamicStyle uses a very expensive call to
     * Util.maxZIndex(...) that sets the z-index of .annotator-adder,
     * .annotator-outer, .annotator-notice, .annotator-filter. We set these
     * values in annotator.min.css instead and do nothing here.
     */
    Annotator.prototype._setupDynamicStyle = function() { };

    Annotator.frozenSrc = null;

    /**
     * Modifies Annotator.Plugin.Auth.haveValidToken to make it work with a new
     * token format.
     **/
    Annotator.Plugin.Auth.prototype.haveValidToken = function() {
        return (
            this._unsafeToken &&
            this._unsafeToken.sub &&
            this._unsafeToken.exp &&
            this._unsafeToken.iat &&
            this.timeToExpiry() > 0
        );
    };

    /**
     * Modifies Annotator.Plugin.Auth.timeToExpiry to make it work with a new
     * token format.
     **/
    Annotator.Plugin.Auth.prototype.timeToExpiry = function() {
        var now = new Date().getTime() / 1000,
            expiry = this._unsafeToken.exp,
            timeToExpiry = expiry - now;

        return (timeToExpiry > 0) ? timeToExpiry : 0;
    };


    Annotator.Plugin.Tags.prototype.updateField = _.compose(
        function() {
            // Add screen reader label for edit mode. Note that the id of the tags element will not always be "1".
            // It depends on the number of annotatable components on the page.
            var tagsField = $("li.annotator-item >input", this.annotator.editor.element).attr('id');
            if ($("label.sr[for='"+ tagsField + "']", this.annotator.editor.element).length === 0) {
                $('<label class="sr" for='+ tagsField +'>' + _t('Tags (space-separated)') + '</label>').insertBefore(
                    $('#'+tagsField, this.annotator.editor.element)
                );
            }
            return this;
        },
        Annotator.Plugin.Tags.prototype.updateField
    );

    Annotator.Plugin.Tags.prototype.updateViewer = _.compose(
        function() {
            // Add ARIA information for viewing mode.
            $('div.annotator-tags', this.wrapper).attr({
                'role': 'region',
                'aria-label': 'tags'
            });
            return this;
        },
        Annotator.Plugin.Tags.prototype.updateViewer
    );

    /**
     * Modifies Annotator.highlightRange to add "tabindex=0" and role="link"
     * attributes to the <span class="annotator-hl"> markup that encloses the
     * note. These are then focusable via the TAB key and are accessible to
     * screen readers.
     **/
    Annotator.prototype.highlightRange = _.compose(
        function (results) {
            $('.annotator-hl', this.wrapper).attr({
                'tabindex': 0,
                'role': 'link'
            });
            return results;
        },
        Annotator.prototype.highlightRange
    );

    /**
     * Modifies Annotator.destroy to unbind click.edxnotes:freeze from the
     * document and reset isFrozen to default value, false.
     **/
    Annotator.prototype.destroy = _.compose(
        Annotator.prototype.destroy,
        function () {
            // We are destroying the instance that has the popup visible, revert to default,
            // unfreeze all instances and set their isFrozen to false
            if (this === Annotator.frozenSrc) {
                this.unfreezeAll();
            } else {
                // Unfreeze only this instance and unbound associated 'click.edxnotes:freeze' handler
                $(document).off('click.edxnotes:freeze' + this.uid);
                this.isFrozen = false;
            }

            if (this.logger && this.logger.destroy) {
                this.logger.destroy();
            }
            // Unbind onNoteClick from click
            this.viewer.element.off('click', this.onNoteClick);
            this.wrapper.off('click', '.annotator-hl');
        }
    );

    /**
     * Modifies Annotator.Viewer.html template to make viewer div focusable.
     * Also adds a close button and necessary i18n attributes to all buttons.
    **/
        Annotator.Viewer.prototype.html = {
        element: [
            '<div class="annotator-outer annotator-viewer">',
                '<ul class="annotator-widget annotator-listing" tabindex="-1"></ul>',
            '</div>'
        ].join(''),
        item: [
            '<li class="annotator-annotation annotator-item">',
                '<span class="annotator-controls">',
                    '<a href="#" title="', _t('View as webpage'), '" class="annotator-link">',
                        _t('View as webpage'),
                    '</a>',
                    '<button class="annotator-edit">',
                        _t('Edit'),
                        '<span class="sr">', _t('Note'), '</span>',
                    '</button>',
                    '<button class="annotator-delete">',
                        _t('Delete'),
                        '<span class="sr">', _t('Note'), '</span>',
                    '</button>',
                    '<button class="annotator-close">',
                        _t('Close'),
                        '<span class="sr">', _t('Note'), '</span>',
                    '</button>',
                '</span>',
            '</li>'
        ].join('')
    };

    /**
     * Overrides Annotator._setupViewer to add a "click" event on viewer and to
     * improve line breaks.
     **/
    Annotator.prototype._setupViewer = function () {
        var self = this;
        this.viewer = new Annotator.Viewer({readOnly: this.options.readOnly});
        this.viewer.element.on('click', _.bind(this.onNoteClick, this));
        this.viewer.hide()
            .on("edit", this.onEditAnnotation)
            .on("delete", this.onDeleteAnnotation)
            .addField({
                load: function (field, annotation) {
                    if (annotation.text) {
                        $(field).html(Utils.nl2br(Annotator.Util.escape(annotation.text)));
                    } else {
                        $(field).html('<i>' + _t('No Comment') + '</i>');
                    }
                    return self.publish('annotationViewerTextField', [field, annotation]);
                }
            })
            .element.appendTo(this.wrapper).bind({
                "mouseover": this.clearViewerHideTimer,
                "mouseout":  this.startViewerHideTimer
            });
        return this;
    };

    Annotator.Editor.prototype.isShown = Annotator.Viewer.prototype.isShown;

    /**
     * Modifies Annotator.Editor.html template to add tabindex = -1 to
     * form.annotator-widget and reverse order of Save and Cancel buttons.
     **/
    Annotator.Editor.prototype.html = [
        '<div class="annotator-outer annotator-editor">',
            '<form class="annotator-widget" tabindex="-1">',
                '<ul class="annotator-listing"></ul>',
                '<div class="annotator-controls">',
                    '<button class="annotator-save">',
                        _t('Save'),
                        '<span class="sr">', _t('Note'), '</span>',
                    '</button>',
                    '<button class="annotator-cancel">',
                        _t('Cancel'),
                        '<span class="sr">', _t('Note'), '</span>',
                    '</button>',
                '</div>',
            '</form>',
        '</div>'
    ].join('');


    /**
     * Modifies Annotator.Editor.show, in the case of a keydown event, to remove
     * focus from Save button and put it on form.annotator-widget instead.
     *
     * Also add a sr label for note textarea.
     **/
    Annotator.Editor.prototype.show = _.compose(
        function (event) {
            // Add screen reader label for the note area. Note that the id of the tags element will not always be "0".
            // It depends on the number of annotatable components on the page.
            var noteField = $("li.annotator-item >textarea", this.element).attr('id');
            if ($("label.sr[for='"+ noteField + "']", this.element).length === 0) {
                $('<label class="sr" for='+ noteField +'>' + _t('Note') + '</label>').insertBefore(
                    $('#'+noteField, this.element)
                );
            }

            if (event.type === 'keydown') {
                this.element.find('.annotator-save').removeClass(this.classes.focus);
                this.element.find('form.annotator-widget').focus();
            }
        },
        Annotator.Editor.prototype.show
    );

    /**
     * Removes the textarea keydown event handler as it triggers 'processKeypress'
     * which hides the viewer on ESC and saves on ENTER. We will define different
     * behaviors for these in /plugins/accessibility.js
     **/
    delete Annotator.Editor.prototype.events["textarea keydown"];

    /**
     * Modifies Annotator.onHighlightMouseover to avoid showing the viewer if the
     * editor is opened.
     **/
    Annotator.prototype.onHighlightMouseover = _.wrap(
        Annotator.prototype.onHighlightMouseover,
        function (func, event) {
            // Do nothing if the editor is opened.
            if (this.editor.isShown()) {
                return false;
            }
            return func.call(this, event);
        },
        Annotator.prototype._setupViewer
    );

    /**
     * Modifies Annotator._setupWrapper to add a "click" event on '.annotator-hl'.
     **/
    Annotator.prototype._setupWrapper = _.compose(
        function () {
            this.element.on('click', '.annotator-hl', _.bind(this.onHighlightClick, this));
            return this;
        },
        Annotator.prototype._setupWrapper
    );

    $.extend(true, Annotator.prototype, {
        isFrozen: false,
        uid: _.uniqueId(),

        onHighlightClick: function (event) {
            event.stopPropagation();
            if (!this.editor.isShown()) {
                this.unfreezeAll();
                this.onHighlightMouseover.call(this, event);
                Annotator.frozenSrc = this;
                this.freezeAll();
            }
        },

        onNoteClick: function (event) {
            var target = $(event.target);
            event.stopPropagation();
            Annotator.Util.preventEventDefault(event);

            if (!(target.is('.annotator-delete') || target.is('.annotator-close'))) {
                Annotator.frozenSrc = this;
                this.freezeAll();
            } else if (target.is('.annotator-close')) {
                this.viewer.hide();
            }
        },

        freeze: function () {
            if (!this.isFrozen) {
                // Remove default events
                this.removeEvents();
                this.viewer.element.unbind('mouseover mouseout');
                this.uid = _.uniqueId();
                $(document).on('click.edxnotes:freeze' + this.uid, _.bind(this.unfreeze, this));
                this.isFrozen = true;
            }
            return this;
        },

        unfreeze: function () {
            if (this.isFrozen) {
                // Add default events
                this.addEvents();
                this.viewer.element.bind({
                    'mouseover': this.clearViewerHideTimer,
                    'mouseout':  this.startViewerHideTimer
                });
                this.viewer.hide();
                $(document).off('click.edxnotes:freeze' + this.uid);
                this.isFrozen = false;
                Annotator.frozenSrc = null;
            }
            return this;
        },

        freezeAll: function () {
            _.invoke(Annotator._instances, 'freeze');
            return this;
        },

        unfreezeAll: function () {
            _.invoke(Annotator._instances, 'unfreeze');
            return this;
        },

        showFrozenViewer: function (annotations, location) {
            this.showViewer(annotations, location);
            this.freezeAll();
            return this;
        }
    });
});
}).call(this, define || RequireJS.define);
