(function(define, undefined) {
    'use strict';
    define([
        'gettext', 'jquery', 'underscore', 'js/edxnotes/views/note_group', 'js/edxnotes/views/tab_panel',
        'js/edxnotes/views/tab_view'
    ], function(gettext, $, _, NoteGroupView, TabPanelView, TabView) {
        var view = 'Tags';
        var TagsView = TabView.extend({
            scrollToTag: function(tagName) {
                var titleElement, displayedTitle;
                if (!this.tabModel.isActive()) {
                    this.tabModel.activate();
                }

                displayedTitle = this.contentView.titleMap[tagName.toLowerCase()];
                titleElement = this.$el.find('.tags-title').filter(
                function() { return $(this).text() === displayedTitle; }
            );
                $('html,body').animate(
                {scrollTop: titleElement.offset().top - 10},
                'slow',
                function() { titleElement.focus(); }
            );
            },

            initialize: function(options) {
                this.options = _.extend({}, options);
                TabView.prototype.initialize.call(this, options);
                _.bindAll(this, 'scrollToTag');
                this.options.scrollToTag = this.scrollToTag;
            },

            PanelConstructor: TabPanelView.extend({
                id: 'tags-panel',
                title: view,
            // Translators: this is a title shown before all Notes that have no associated tags. It is put within
            // brackets to differentiate it from user-defined tags, but it should still be translated.
                noTags: gettext('[no tags]'),  // User-defined tags cannot have spaces, so no risk of a collision.

                renderContent: function() {
                    var notesByTag = {},
                        noTags = this.noTags,
                        addNoteForTag, noteList, tags, i,
                        sortedTagNames, container, group, noteGroup, tagTitle, titleMap;

                // Iterate through all the notes and build up a dictionary structure by tag.
                // Note that the collection will be in most-recently updated order already.
                    addNoteForTag = function(note, tag) {
                        noteList = notesByTag[tag.toLowerCase()];
                        if (noteList === undefined) {
                            noteList = [];
                            notesByTag[tag.toLowerCase()] = noteList;
                        }
                    // If a note was tagged with the same tag more than once, don't add again.
                    // We can assume it would be the last element of the list because we iterate through
                    // all tags on a given note before moving on to the text note.
                        if (noteList.length === 0 || noteList[noteList.length - 1] !== note) {
                            noteList.push(note);
                        }
                    };

                    this.collection.each(function(note) {
                        tags = note.get('tags');
                        if (tags.length === 0) {
                            addNoteForTag(note, noTags);
                        } else {
                            for (i = 0; i < tags.length; i++) {
                                addNoteForTag(note, tags[i]);
                            }
                        }
                    });

                    sortedTagNames = Object.keys(notesByTag).sort(function(a, b) {
                    // "no tags" should always appear last
                        if (a === noTags) {
                            return 1;
                        } else if (b === noTags) {
                            return -1;
                        } else if (notesByTag[a].length > notesByTag[b].length) {
                            return -1;
                        } else if (notesByTag[a].length < notesByTag[b].length) {
                            return 1;
                        } else {
                            return a.toLowerCase() <= b.toLowerCase() ? -1 : 1;
                        }
                    });

                    container = document.createDocumentFragment();

                // Store map of titles for scrollToTag functionality.
                    this.titleMap = {};
                    titleMap = this.titleMap;

                    _.each(sortedTagNames, function(tagName) {
                        noteGroup = notesByTag[tagName];
                        var tagTitle = interpolate_text(
                        '{tagName} ({numberOfNotesWithTag})',
                        {tagName: tagName, numberOfNotesWithTag: noteGroup.length}
                    );
                        group = this.getGroup(tagTitle);
                        titleMap[tagName] = tagTitle;

                        group.addChild(this.getNotes(noteGroup));
                        container.appendChild(group.render().el);
                    }, this);

                    this.$el.append(container);
                    return this;
                },

                getGroup: function(tagName) {
                    var group = new NoteGroupView.GroupView({
                        displayName: tagName,
                        template: '<h3 class="tags-title sr-is-focusable" tabindex="-1"><%- displayName %></h3>',
                        className: 'note-group'
                    });
                    this.children.push(group);
                    return group;
                }
            }),

            tabInfo: {
            // Translators: 'Tags' is the name of the view (noun) within the Student Notes page that shows all
            // notes organized by the tags the student has associated with them (if any). When defining a
            // note in the courseware, the student can choose to associate 1 or more tags with the note
            // in order to group similar notes together and help with search.
                name: gettext('Tags'),
                identifier: 'view-tags',
                icon: 'fa fa-tag',
                view: view
            }
        });

        return TagsView;
    });
}).call(this, define || RequireJS.define);
