(function(define) {
    'use strict';
    define([
        'gettext', 'jquery', 'underscore', 'backbone', 'js/views/fields',
        'text!templates/fields/field_image.underscore',
        'backbone-super', 'jquery.fileupload'
    ], function(gettext, $, _, Backbone, FieldViews, field_image_template) {
        var ImageFieldView = FieldViews.FieldView.extend({

            fieldType: 'image',

            fieldTemplate: field_image_template,
            uploadButtonSelector: '.upload-button-input',

            titleAdd: gettext('Upload an image'),
            titleEdit: gettext('Change image'),
            titleRemove: gettext('Remove'),

            titleUploading: gettext('Uploading'),
            titleRemoving: gettext('Removing'),

            titleImageAlt: '',
            screenReaderTitle: gettext('Image'),

            iconUpload: '<span class="icon fa fa-camera" aria-hidden="true"></span>',
            iconRemove: '<span class="icon fa fa-remove" aria-hidden="true"></span>',
            iconProgress: '<span class="icon fa fa-spinner fa-pulse fa-spin" aria-hidden="true"></span>',

            errorMessage: gettext('An error has occurred. Refresh the page, and then try again.'),

            events: {
                'click .u-field-upload-button': 'clickedUploadButton',
                'click .u-field-remove-button': 'clickedRemoveButton',
                'click .upload-submit': 'clickedUploadButton',
                'focus .upload-button-input': 'showHoverState',
                'blur .upload-button-input': 'hideHoverState'
            },

            initialize: function(options) {
                this.options = _.extend({}, options);
                this._super(options);
                _.bindAll(this, 'render', 'imageChangeSucceeded', 'imageChangeFailed', 'fileSelected',
                          'watchForPageUnload', 'onBeforeUnload');
            },

            render: function() {
                this.$el.html(this.template({
                    id: this.options.valueAttribute,
                    inputName: (this.options.inputName || 'file'),
                    imageUrl: _.result(this, 'imageUrl'),
                    imageAltText: _.result(this, 'imageAltText'),
                    uploadButtonIcon: _.result(this, 'iconUpload'),
                    uploadButtonTitle: _.result(this, 'uploadButtonTitle'),
                    removeButtonIcon: _.result(this, 'iconRemove'),
                    removeButtonTitle: _.result(this, 'removeButtonTitle'),
                    screenReaderTitle: _.result(this, 'screenReaderTitle')
                }));
                this.delegateEvents();
                this.updateButtonsVisibility();
                this.watchForPageUnload();
                return this;
            },

            showHoverState: function() {
                this.$('.u-field-upload-button').addClass('button-visible');
            },

            hideHoverState: function() {
                this.$('.u-field-upload-button').removeClass('button-visible');
            },

            showErrorMessage: function(message) {
                return message;
            },

            imageUrl: function() {
                return '';
            },

            uploadButtonTitle: function() {
                if (this.isShowingPlaceholder()) {
                    return _.result(this, 'titleAdd');
                } else {
                    return _.result(this, 'titleEdit');
                }
            },

            removeButtonTitle: function() {
                return this.titleRemove;
            },

            isEditingAllowed: function() {
                return true;
            },

            isShowingPlaceholder: function() {
                return false;
            },

            setUploadButtonVisibility: function(state) {
                this.$('.u-field-upload-button').css('display', state);
            },

            setRemoveButtonVisibility: function(state) {
                this.$('.u-field-remove-button').css('display', state);
            },

            updateButtonsVisibility: function() {
                if (!this.isEditingAllowed() || !this.options.editable) {
                    this.setUploadButtonVisibility('none');
                }

                if (this.isShowingPlaceholder() || !this.options.editable) {
                    this.setRemoveButtonVisibility('none');
                }
            },

            clickedUploadButton: function() {
                $(this.uploadButtonSelector).fileupload({
                    url: this.options.imageUploadUrl,
                    type: 'POST',
                    add: this.fileSelected,
                    done: this.imageChangeSucceeded,
                    fail: this.imageChangeFailed
                });
            },

            clickedRemoveButton: function() {
                var view = this;
                this.setCurrentStatus('removing');
                this.setUploadButtonVisibility('none');
                this.showRemovalInProgressMessage();
                $.ajax({
                    type: 'POST',
                    url: this.options.imageRemoveUrl
                }).done(function() {
                    view.imageChangeSucceeded();
                }).fail(function(jqXHR) {
                    view.showImageChangeFailedMessage(jqXHR.status, jqXHR.responseText);
                });
            },

            imageChangeSucceeded: function() {
                this.$('.u-field-upload-button').removeClass('in-progress');
                this.render();
            },

            imageChangeFailed: function(e, data) {
            },

            showImageChangeFailedMessage: function(status, responseText) {
            },

            fileSelected: function(e, data) {
                if (_.isUndefined(data.files[0].size) || this.validateImageSize(data.files[0].size)) {
                    this.setCurrentStatus('uploading');
                    this.setRemoveButtonVisibility('none');
                    this.showUploadInProgressMessage();
                    data.submit();
                }
            },

            validateImageSize: function(imageBytes) {
                var humanReadableSize;
                if (imageBytes < this.options.imageMinBytes) {
                    humanReadableSize = this.bytesToHumanReadable(this.options.imageMinBytes);
                    this.showErrorMessage(
                        interpolate_text(
                            gettext('The file must be at least {size} in size.'), {size: humanReadableSize}
                        )
                    );
                    return false;
                } else if (imageBytes > this.options.imageMaxBytes) {
                    humanReadableSize = this.bytesToHumanReadable(this.options.imageMaxBytes);
                    this.showErrorMessage(
                        interpolate_text(
                            gettext('The file must be smaller than {size} in size.'), {size: humanReadableSize}
                        )
                    );
                    return false;
                }
                return true;
            },

            showUploadInProgressMessage: function() {
                this.$('.u-field-upload-button').addClass('in-progress');
                this.$('.upload-button-icon').html(this.iconProgress);
                this.$('.upload-button-title').html(this.titleUploading);
            },

            showRemovalInProgressMessage: function() {
                this.$('.u-field-remove-button').css('opacity', 1);
                this.$('.remove-button-icon').html(this.iconProgress);
                this.$('.remove-button-title').html(this.titleRemoving);
            },

            setCurrentStatus: function(status) {
                this.$('.image-wrapper').attr('data-status', status);
            },

            getCurrentStatus: function() {
                return this.$('.image-wrapper').attr('data-status');
            },

            watchForPageUnload: function() {
                $(window).on('beforeunload', this.onBeforeUnload);
            },

            onBeforeUnload: function() {
                var status = this.getCurrentStatus();
                if (status === 'uploading') {
                    return gettext('Upload is in progress. To avoid errors, stay on this page until the process is complete.');
                } else if (status === 'removing') {
                    return gettext('Removal is in progress. To avoid errors, stay on this page until the process is complete.');
                }
            },

            bytesToHumanReadable: function(size) {
                var units = [gettext('bytes'), gettext('KB'), gettext('MB')];
                var i = 0;
                while (size >= 1024) {
                    size /= 1024;
                    ++i;
                }
                return size.toFixed(1) * 1 + ' ' + units[i];
            }
        });

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