define([
    'jquery',
    'underscore',
    'gettext',
    'edx-ui-toolkit/js/utils/html-utils',
    'js/views/baseview',
    'js/models/asset',
    'js/views/paging',
    'js/views/asset',
    'js/views/paging_header',
    'common/js/components/views/paging_footer',
    'js/utils/modal',
    'common/js/components/utils/view_utils',
    'common/js/components/views/feedback_notification',
    'text!templates/asset-library.underscore',
    'jquery.fileupload-process',
    'jquery.fileupload-validate'
],
    function($, _, gettext, HtmlUtils, BaseView, AssetModel, PagingView, AssetView, PagingHeader, PagingFooter,
             ModalUtils, ViewUtils, NotificationView, asset_library_template) {
        var CONVERSION_FACTOR_MBS_TO_BYTES = 1000 * 1000;

        var AssetsView = BaseView.extend({
            // takes AssetCollection as model

            events: {
                'click .column-sort-link': 'onToggleColumn',
                'click .upload-button': 'showUploadModal',
                'click .filterable-column .nav-item': 'onFilterColumn',
                'click .filterable-column .column-filter-link': 'toggleFilterColumn'
            },

            typeData: ['Images', 'Documents'],

            allLabel: 'ALL',

            initialize: function(options) {
                options = options || {};

                BaseView.prototype.initialize.call(this);
                var collection = this.collection;
                this.pagingView = this.createPagingView();
                this.listenTo(collection, 'destroy', this.handleDestroy);
                ViewUtils.showLoadingIndicator();
                // set default file size for uploads via template var,
                // and default to static old value if none exists
                this.uploadChunkSizeInMBs = options.uploadChunkSizeInMBs || 10;
                this.maxFileSizeInMBs = options.maxFileSizeInMBs || 10;
                this.uploadChunkSizeInBytes = this.uploadChunkSizeInMBs * CONVERSION_FACTOR_MBS_TO_BYTES;
                this.maxFileSizeInBytes = this.maxFileSizeInMBs * CONVERSION_FACTOR_MBS_TO_BYTES;
                this.maxFileSizeRedirectUrl = options.maxFileSizeRedirectUrl || '';
                // error message modal for large file uploads
                this.largeFileErrorMsg = null;
            },

            PagingAssetView: PagingView.extend({
                renderPageItems: function() {
                    var self = this,
                        assets = this.collection,
                        hasAssets = this.collection.assetType !== '' || assets.length > 0,
                        tableBody = this.getTableBody();
                    tableBody.empty();
                    if (hasAssets) {
                        assets.each(
                            function(asset) {
                                var view = new AssetView({model: asset});
                                tableBody.append(view.render().el);
                            }
                        );
                    }
                    self.$('.assets-library').toggle(hasAssets);
                    self.$('.no-asset-content').toggle(!hasAssets);
                    return this;
                },

                getTableBody: function() {
                    var tableBody = this.tableBody;
                    if (!tableBody) {
                        ViewUtils.hideLoadingIndicator();

                        // Create the table
                        HtmlUtils.setHtml(
                            this.$el,
                            HtmlUtils.template(asset_library_template)({typeData: this.typeData})
                        );
                        tableBody = this.$('#asset-table-body');
                        this.tableBody = tableBody;
                        this.pagingHeader = new PagingHeader({view: this, el: $('#asset-paging-header')});
                        this.pagingFooter = new PagingFooter({collection: this.collection, el: $('#asset-paging-footer')});
                        this.pagingHeader.render();
                        this.pagingFooter.render();

                        // Hide the contents until the collection has loaded the first time
                        this.$('.assets-library').hide();
                        this.$('.no-asset-content').hide();
                    }
                    return tableBody;
                },

                onError: function() {
                    ViewUtils.hideLoadingIndicator();
                }
            }),

            createPagingView: function() {
                var pagingView = new this.PagingAssetView({
                    el: this.$el,
                    collection: this.collection
                });
                pagingView.registerSortableColumn('js-asset-name-col', gettext('Name'), 'display_name', 'asc');
                pagingView.registerSortableColumn('js-asset-date-col', gettext('Date Added'), 'date_added', 'desc');
                pagingView.registerFilterableColumn('js-asset-type-col', gettext('Type'), 'asset_type');
                pagingView.setInitialSortColumn('js-asset-date-col');
                pagingView.setInitialFilterColumn('js-asset-type-col');
                pagingView.setPage(1);
                return pagingView;
            },

            render: function() {
                this.pagingView.render();
                return this;
            },

            afterRender: function() {
                // Bind events with html elements
                $('li a.upload-button').on('click', _.bind(this.showUploadModal, this));
                $('.upload-modal .close-button').on('click', _.bind(this.hideModal, this));
                $('.upload-modal .choose-file-button').on('click', _.bind(this.showFileSelectionMenu, this));
                return this;
            },

            handleDestroy: function(model) {
                this.collection.fetch({reset: true}); // reload the collection to get a fresh page full of items
                analytics.track('Deleted Asset', {
                    'course': course_location_analytics,
                    'id': model.get('url')
                });
            },

            addAsset: function(model) {
                // Switch the sort column back to the default (most recent date added) and show the first page
                // so that the new asset is shown at the top of the page.
                this.pagingView.setInitialSortColumn('js-asset-date-col');
                this.pagingView.setInitialFilterColumn('js-asset-type-col');
                this.pagingView.setPage(1);

                analytics.track('Uploaded a File', {
                    'course': course_location_analytics,
                    'asset_url': model.get('url')
                });
            },

            onToggleColumn: function(event) {
                var columnName = event.target.id;
                this.pagingView.toggleSortOrder(columnName);
            },

            onFilterColumn: function(event) {
                this.openFilterColumn($(event.currentTarget));
                event.stopPropagation();
            },

            hideModal: function(event) {
                if (event) {
                    event.preventDefault();
                }
                $('.file-input').unbind('change.startUpload');
                ModalUtils.hideModal();
                if (this.largeFileErrorMsg) {
                    this.largeFileErrorMsg.hide();
                }
            },

            showUploadModal: function(event) {
                var self = this;
                event.preventDefault();
                self.resetUploadModal();
                ModalUtils.showModal();
                $('.modal-cover').on('click', self.hideModal);
                $('.file-input').bind('change', self.startUpload);
                $('.upload-modal .file-chooser').fileupload({
                    dataType: 'json',
                    type: 'POST',
                    maxChunkSize: self.uploadChunkSizeInBytes,
                    autoUpload: true,
                    progressall: function(event, data) {
                        var percentComplete = parseInt((100 * data.loaded) / data.total, 10);
                        self.showUploadFeedback(event, percentComplete);
                    },
                    maxFileSize: self.maxFileSizeInBytes,
                    maxNumberofFiles: 100,
                    done: function(event, data) {
                        self.displayFinishedUpload(data.result);
                    },
                    processfail: function(event, data) {
                        var filename = data.files[data.index].name;
                        var error = gettext('File {filename} exceeds maximum size of {maxFileSizeInMBs} MB')
                                    .replace('{filename}', filename)
                                    .replace('{maxFileSizeInMBs}', self.maxFileSizeInMBs);

                        // disable second part of message for any falsy value,
                        // which can be null or an empty string
                        if (self.maxFileSizeRedirectUrl) {
                            var instructions = gettext('Please follow the instructions here to upload a file elsewhere and link to it: {maxFileSizeRedirectUrl}')
                                    .replace('{maxFileSizeRedirectUrl}', self.maxFileSizeRedirectUrl);
                            error = error + ' ' + instructions;
                        }

                        self.largeFileErrorMsg = new NotificationView.Error({
                            'title': gettext('Your file could not be uploaded'),
                            'message': error
                        });
                        self.largeFileErrorMsg.show();

                        self.displayFailedUpload({
                            'msg': gettext('Max file size exceeded')
                        });
                    },
                    processdone: function(event, data) {
                        self.largeFileErrorMsg = null;
                    }
                });
            },

            showFileSelectionMenu: function(event) {
                event.preventDefault();
                if (this.largeFileErrorMsg) {
                    this.largeFileErrorMsg.hide();
                }
                $('.file-input').click();
            },

            startUpload: function(event) {
                var file = event.target.value;

                if (!this.largeFileErrorMsg) {
                    $('.upload-modal h1').text(gettext('Uploading'));
                    $('.upload-modal .file-name').text(file.substring(file.lastIndexOf('\\') + 1));
                    $('.upload-modal .choose-file-button').hide();
                    $('.upload-modal .progress-bar').removeClass('loaded').show();
                }
            },

            resetUploadModal: function() {
                // Reset modal so it no longer displays information about previously
                // completed uploads.
                var percentVal = '0%',
                    $progressFill = $('.upload-modal .progress-fill'),
                    $fileName = $('.upload-modal .file-name');

                $progressFill.width(percentVal);
                $progressFill.text(percentVal);
                $('.upload-modal .progress-bar').hide();

                $fileName.show();
                $fileName.text('');
                $('.upload-modal .choose-file-button').text(gettext('Choose File'));
                $('.upload-modal .embeddable-xml-input').val('');
                $('.upload-modal .embeddable').hide();

                this.largeFileErrorMsg = null;
            },

            showUploadFeedback: function(event, percentComplete) {
                var percentVal = percentComplete + '%',
                    $progressFill = $('.upload-modal .progress-fill');

                $progressFill.width(percentVal);
                $progressFill.text(percentVal);
            },

            openFilterColumn: function($this) {
                this.toggleFilterColumnState($this);
            },

            toggleFilterColumnState: function(menu, selected) {
                var $subnav = menu.find('.wrapper-nav-sub');
                var $title = menu.find('.title');
                var titleText = $title.find('.type-filter');
                var assettype = selected ? selected.data('assetfilter') : false;
                if (assettype) {
                    if (assettype === this.allLabel) {
                        titleText.text(titleText.data('alllabel'));
                    }
                    else {
                        titleText.text(assettype);
                    }
                }
                if ($subnav.hasClass('is-shown')) {
                    $subnav.removeClass('is-shown');
                    $title.removeClass('is-selected');
                } else {
                    $title.addClass('is-selected');
                    $subnav.addClass('is-shown');
                }
            },

            toggleFilterColumn: function(event) {
                event.preventDefault();
                var $filterColumn = $(event.currentTarget);
                this._toggleFilterColumn($filterColumn.data('assetfilter'), $filterColumn.text());
            },

            _toggleFilterColumn: function(assettype, assettypeLabel) {
                var collection = this.collection;
                var filterColumn = this.$el.find('.filterable-column');
                var resetFilter = filterColumn.find('.reset-filter');
                var title = filterColumn.find('.title');

                if (assettype === this.allLabel) {
                    collection.assetType = '';
                    resetFilter.hide();
                    title.removeClass('column-selected-link');
                } else {
                    collection.assetType = assettype;
                    resetFilter.show();
                    title.addClass('column-selected-link');
                }

                this.pagingView.filterableColumns['js-asset-type-col'].displayName = assettypeLabel;
                this.pagingView.selectFilter('js-asset-type-col');
                this.closeFilterPopup(this.$el.find(
                    '.column-filter-link[data-assetfilter="' + assettype + '"]'));
            },

            closeFilterPopup: function(element) {
                var $menu = element.parents('.nav-dd > .nav-item');
                this.toggleFilterColumnState($menu, element);
            },

            displayFinishedUpload: function(resp) {
                var asset = resp.asset,
                    $progressFill = $('.upload-modal .progress-fill');

                $('.upload-modal h1').text(gettext('Upload New File'));
                $('.upload-modal .embeddable-xml-input').val(asset.portable_url).show();
                $('.upload-modal .embeddable').show();
                $('.upload-modal .file-name').hide();
                $progressFill.text(resp.msg);
                $('.upload-modal .choose-file-button').text(gettext('Load Another File')).show();
                $progressFill.width('100%');

                this.addAsset(new AssetModel(asset));
            },

            displayFailedUpload: function(resp) {
                var $progressFill = $('.upload-modal .progress-fill');

                $('.upload-modal h1').text(gettext('Upload New File'));
                $('.upload-modal .embeddable-xml-input').hide();
                $('.upload-modal .embeddable').hide();
                $('.upload-modal .file-name').hide();
                $progressFill.text(resp.msg);
                $('.upload-modal .choose-file-button').text(gettext('Load Another File')).show();
                $progressFill.width('0%');
            }
        });

        return AssetsView;
    });
