(function(define, undefined) {
    'use strict';
    define([
        'underscore', 'annotator_1.2.9'
    ], function(_, Annotator) {
    /**
     * Modifies Annotator.Plugin.Store.annotationCreated to make it trigger a new
     * event `annotationFullyCreated` when annotation is fully created and has
     * an id.
     */
        Annotator.Plugin.Store.prototype.annotationCreated = _.compose(
        function(jqXhr) {
            return jqXhr.done(_.bind(function(annotation) {
                if (annotation && annotation.id) {
                    this.publish('annotationFullyCreated', annotation);
                }
            }, this));
        },
        Annotator.Plugin.Store.prototype.annotationCreated
    );

    /**
     * Adds the Events Plugin which emits events to capture user intent.
     * Emits the following events:
     * - 'edx.course.student_notes.viewed'
     *   [(user, note ID, datetime), (user, note ID, datetime)] - a list of notes.
     * - 'edx.course.student_notes.added'
     *   (user, note ID, note text, highlighted content, ID of the component annotated, datetime)
     * - 'edx.course.student_notes.edited'
     *   (user, note ID, old note text, new note text, highlighted content, ID of the component annotated, datetime)
     * - 'edx.course.student_notes.deleted'
     *   (user, note ID, note text, highlighted content, ID of the component annotated, datetime)
     **/
        Annotator.Plugin.Events = function() {
        // Call the Annotator.Plugin constructor this sets up the element and
        // options properties.
            Annotator.Plugin.apply(this, arguments);
        };

        _.extend(Annotator.Plugin.Events.prototype, new Annotator.Plugin(), {
            pluginInit: function() {
                _.bindAll(this,
                'annotationViewerShown', 'annotationFullyCreated', 'annotationEditorShown',
                'annotationEditorHidden', 'annotationUpdated', 'annotationDeleted'
            );

                this.annotator
                .subscribe('annotationViewerShown', this.annotationViewerShown)
                .subscribe('annotationFullyCreated', this.annotationFullyCreated)
                .subscribe('annotationEditorShown', this.annotationEditorShown)
                .subscribe('annotationEditorHidden', this.annotationEditorHidden)
                .subscribe('annotationUpdated', this.annotationUpdated)
                .subscribe('annotationDeleted', this.annotationDeleted);
            },

            destroy: function() {
                this.annotator
                .unsubscribe('annotationViewerShown', this.annotationViewerShown)
                .unsubscribe('annotationFullyCreated', this.annotationFullyCreated)
                .unsubscribe('annotationEditorShown', this.annotationEditorShown)
                .unsubscribe('annotationEditorHidden', this.annotationEditorHidden)
                .unsubscribe('annotationUpdated', this.annotationUpdated)
                .unsubscribe('annotationDeleted', this.annotationDeleted);
            },

            annotationViewerShown: function(viewer, annotations) {
            // Emits an event only when the annotation already exists on the
            // server. Otherwise, `annotation.id` is `undefined`.
                var data;
                annotations = _.reject(annotations, this.isNew);
                data = {
                    'notes': _.map(annotations, function(annotation) {
                        return {'note_id': annotation.id};
                    })
                };
                if (data.notes.length) {
                    this.log('edx.course.student_notes.viewed', data);
                }
            },

            annotationFullyCreated: function(annotation) {
                var data = this.getDefaultData(annotation);
                this.log('edx.course.student_notes.added', data);
            },

            annotationEditorShown: function(editor, annotation) {
                this.oldNoteText = annotation.text || '';
                this.oldTags = annotation.tags || [];
            },

            annotationEditorHidden: function() {
                this.oldNoteText = null;
                this.oldTags = null;
            },

            annotationUpdated: function(annotation) {
                var data, defaultData;
                if (!this.isNew(annotation)) {
                    defaultData = this.getDefaultData(annotation);
                    data = _.extend(
                    defaultData,
                    this.getText('old_note_text', this.oldNoteText, defaultData.truncated),
                    this.getTextArray('old_tags', this.oldTags, defaultData.truncated)
                );
                    this.log('edx.course.student_notes.edited', data);
                }
            },

            annotationDeleted: function(annotation) {
                var data;
            // Emits an event only when the annotation already exists on the
            // server.
                if (!this.isNew(annotation)) {
                    data = this.getDefaultData(annotation);
                    this.log('edx.course.student_notes.deleted', data);
                }
            },

            getDefaultData: function(annotation) {
                var truncated = [];
                return _.extend(
                    {
                        'note_id': annotation.id,
                        'component_usage_id': annotation.usage_id,
                        'truncated': truncated
                    },
                this.getText('note_text', annotation.text, truncated),
                this.getText('highlighted_content', annotation.quote, truncated),
                this.getTextArray('tags', annotation.tags, truncated)
            );
            },

            getText: function(fieldName, text, truncated) {
                var info = {},
                    limit = this.options.stringLimit;

                if (_.isNumber(limit) && _.isString(text) && text.length > limit) {
                    text = String(text).slice(0, limit);
                    truncated.push(fieldName);
                }

                info[fieldName] = text;

                return info;
            },

            getTextArray: function(fieldName, textArray, truncated) {
                var info = {}, limit = this.options.stringLimit, totalLength = 0, returnArray = [], i;

                if (_.isNumber(limit) && _.isArray(textArray)) {
                    for (i = 0; i < textArray.length; i++) {
                        if (_.isString(textArray[i]) && totalLength + textArray[i].length > limit) {
                            truncated.push(fieldName);
                            break;
                        }
                        totalLength += textArray[i].length;
                        returnArray[i] = textArray[i];
                    }
                }
                else {
                    returnArray = textArray;
                }

                info[fieldName] = returnArray;

                return info;
            },

        /**
         * If the model does not yet have an id, it is considered to be new.
         * @return {Boolean}
         */
            isNew: function(annotation) {
                return !_.has(annotation, 'id');
            },

            log: function(eventName, data) {
                this.annotator.logger.emit(eventName, data);
            }
        });
    });
}).call(this, define || RequireJS.define);
