define(["js/views/validation", "codemirror", "js/models/course_update",
        "common/js/components/views/feedback_prompt", "common/js/components/views/feedback_notification",
        "js/views/course_info_helper", "js/utils/modal", "js/utils/date_utils"],
    function(ValidatingView, CodeMirror, CourseUpdateModel, PromptView, NotificationView,
        CourseInfoHelper, ModalUtils, DateUtils) {

    'use strict';
    var CourseInfoUpdateView = ValidatingView.extend({

        // collection is CourseUpdateCollection
        events: {
            "click .new-update-button" : "onNew",
            "click #course-update-view .save-button" : "onSave",
            "click #course-update-view .cancel-button" : "onCancel",
            "click .post-actions > .edit-button" : "onEdit",
            "click .post-actions > .delete-button" : "onDelete"
        },

        initialize: function() {
            this.template = this.loadTemplate('course_info_update');
            this.render();
            // when the client refetches the updates as a whole, re-render them
            this.listenTo(this.collection, 'reset', this.render);
            this.listenTo(this.collection, 'invalid', this.handleValidationError);
        },

        render: function () {
            // iterate over updates and create views for each using the template
            var updateEle = this.$el.find("#course-update-list");
            // remove and then add all children
            $(updateEle).empty();
            var self = this;
            this.collection.each(function (update, index) {
                try {
                    CourseInfoHelper.changeContentToPreview(
                        update, 'content', self.options['base_asset_url']);
                    // push notification is always disabled for existing updates
                    var newEle = self.template({ updateModel : update, push_notification_enabled : false });
                    $(updateEle).append(newEle);
                    DateUtils.setupDatePicker("date", self, index);
                    update.isValid();
                } catch (e) {
                    // ignore
                }
            });
            this.$el.find(".new-update-form").hide();
            return this;
        },

        collectionSelector: function(uid) {
            return "course-update-list li[name=" + uid + "]";
        },

        setAndValidate: function(attr, value, event) {
            if (attr === 'date') {
                // If the value to be set was typed, validate that entry rather than the current datepicker value
                if (this.dateEntry(event).length > 0) {
                    value = DateUtils.parseDateFromString(this.dateEntry(event).val());
                    if (value && isNaN(value.getTime())) {
                        value = "";
                    }
                }
                value = $.datepicker.formatDate("MM d, yy", value);
            }
            var targetModel = this.collection.get(this.$currentPost.attr('name'));
            var prevValue = targetModel.get(attr);
            if (prevValue !== value) {
                targetModel.set(attr, value);
                this.validateModel(targetModel);
            }
        },

        handleValidationError : function(model, error) {
            var ele = this.$el.find('#course-update-list li[name=\"'+model.cid+'\"]');
            $(ele).find('.message-error').remove();
            for (var field in error) {
                if (error.hasOwnProperty(field)) {
                    $(ele).find('#update-date-'+model.cid).parent().append(
                        this.errorTemplate({message : error[field]})
                    );
                    $(ele).find('.date-display').parent().append(this.errorTemplate({message : error[field]}));
                }
            }
            $(ele).find('.save-button').addClass('is-disabled');
        },

        validateModel: function(model) {
            if (model.isValid()) {
                var ele = this.$el.find('#course-update-list li[name=\"' + model.cid + '\"]');
                $(ele).find('.message-error').remove();
                $(ele).find('.save-button').removeClass('is-disabled');
            }
        },

        onNew: function(event) {
            event.preventDefault();
            var self = this;
            // create new obj, insert into collection, and render this one ele overriding the hidden attr
            var newModel = new CourseUpdateModel();
            this.collection.add(newModel, {at : 0});

            var $newForm = $(
                this.template({
                    updateModel : newModel,
                    push_notification_enabled : this.options.push_notification_enabled
                })
            );

            var updateEle = this.$el.find("#course-update-list");
            $(updateEle).prepend($newForm);

            var $textArea = $newForm.find(".new-update-content").first();
            this.$codeMirror = CodeMirror.fromTextArea($textArea.get(0), {
                mode: "text/html",
                lineNumbers: true,
                lineWrapping: true
            });

            $newForm.addClass('editing');
            this.$currentPost = $newForm.closest('li');

            // Variable stored for unit test.
            this.$modalCover = ModalUtils.showModalCover(false, function() {
                // Binding empty function to prevent default hideModal.
            });

            DateUtils.setupDatePicker("date", this, 0);
        },

        onSave: function(event) {
            event.preventDefault();
            var targetModel = this.eventModel(event);
            targetModel.set({
                // translate short-form date (for input) into long form date (for display)
                date : $.datepicker.formatDate("MM d, yy", new Date(this.dateEntry(event).val())),
                content : this.$codeMirror.getValue(),
                push_notification_selected : this.push_notification_selected(event)
            });
            // push change to display, hide the editor, submit the change
            var saving = new NotificationView.Mini({
                title: gettext('Saving')
            });
            saving.show();
            var ele = this.modelDom(event);
            targetModel.save({}, {
                success: function() {
                    saving.hide();
                },
                error: function() {
                    ele.remove();
                }
            });
            this.closeEditor(false);

            analytics.track('Saved Course Update', {
                'course': course_location_analytics,
                'date': this.dateEntry(event).val(),
                'push_notification_selected': this.push_notification_selected(event)
            });
        },

        onCancel: function(event) {
            event.preventDefault();
            // Since we're cancelling, the model should be using it's previous attributes
            var targetModel = this.eventModel(event);
            targetModel.set(targetModel.previousAttributes());
            this.validateModel(targetModel);
            // Hide the editor
            $(this.editor(event)).hide();
            // targetModel will be lacking an id if it was newly created
            this.closeEditor(!targetModel.id);
        },

        onEdit: function(event) {
            event.preventDefault();
            var self = this;
            this.$currentPost = $(event.target).closest('li');
            this.$currentPost.addClass('editing');

            $(this.editor(event)).show();
            var $textArea = this.$currentPost.find(".new-update-content").first();
            var targetModel = this.eventModel(event);
            // translate long-form date (for viewing) into short-form date (for input)
            if (targetModel.get('date') && targetModel.isValid()) {
                $(this.dateEntry(event)).val($.datepicker.formatDate("mm/dd/yy", new Date(targetModel.get('date'))));
            }
            else {
                $(this.dateEntry(event)).val("MM/DD/YY");
            }
            this.$codeMirror = CourseInfoHelper.editWithCodeMirror(
                targetModel, 'content', self.options['base_asset_url'], $textArea.get(0));

            // Variable stored for unit test.
            this.$modalCover = ModalUtils.showModalCover(false,
                function() {
                    self.closeEditor(false);
                }
            );

            // Ensure validity is marked appropriately
            targetModel.isValid();
        },

        onDelete: function(event) {
            event.preventDefault();

            var self = this;
            var targetModel = this.eventModel(event);
            var confirm = new PromptView.Warning({
                title: gettext('Are you sure you want to delete this update?'),
                message: gettext('This action cannot be undone.'),
                actions: {
                    primary: {
                        text: gettext('OK'),
                        click: function () {
                            analytics.track('Deleted Course Update', {
                                'course': course_location_analytics,
                                'date': self.dateEntry(event).val()
                            });
                            self.modelDom(event).remove();
                            var deleting = new NotificationView.Mini({
                                title: gettext('Deleting')
                            });
                            deleting.show();
                            targetModel.destroy({
                                success: function (model, response) {
                                    self.collection.fetch({
                                        success: function() {
                                            self.render();
                                            deleting.hide();
                                        },
                                        reset: true
                                    });
                                }
                            });
                            confirm.hide();
                        }
                    },
                    secondary: {
                        text: gettext('Cancel'),
                        click: function() {
                            confirm.hide();
                        }
                    }
                }
            });
            confirm.show();
        },

        closeEditor: function(removePost) {
            var targetModel = this.collection.get(this.$currentPost.attr('name'));

            // If the model was never created (user created a new update, then pressed Cancel),
            // we wish to remove it from the DOM.
            if(removePost) {
                this.$currentPost.remove();
            }
            else {
                // close the modal and insert the appropriate data
                this.$currentPost.removeClass('editing');
                this.$currentPost.find('.date-display').html(targetModel.get('date'));
                this.$currentPost.find('.date').val(targetModel.get('date'));

                var content = CourseInfoHelper.changeContentToPreview(
                    targetModel, 'content', this.options['base_asset_url']);
                try {
                    // just in case the content causes an error (embedded js errors)
                    this.$currentPost.find('.update-contents').html(content);
                    this.$currentPost.find('.new-update-content').val(content);
                } catch (e) {
                    // ignore but handle rest of page
                }
                this.$currentPost.find('form').hide();
                this.$currentPost.find('.CodeMirror').remove();

                // hide the push notification checkbox for subsequent edits to the Post
                var push_notification_ele = this.$currentPost.find(".new-update-push-notification");
                if (push_notification_ele) {
                    push_notification_ele.hide();
                }
            }

            ModalUtils.hideModalCover(this.$modalCover);
            this.$codeMirror = null;
        },

        // Dereferencing from events to screen elements
        eventModel: function(event) {
            // not sure if it should be currentTarget or delegateTarget
            return this.collection.get($(event.currentTarget).attr("name"));
        },

        modelDom: function(event) {
            return $(event.currentTarget).closest("li");
        },

        editor: function(event) {
            var li = $(event.currentTarget).closest("li");
            if (li) {
                return $(li).find("form").first();
            }
        },

        dateEntry: function(event) {
            var li = $(event.currentTarget).closest("li");
            if (li) {
                return $(li).find(".date").first();
            }
        },

        push_notification_selected: function(event) {
            var push_notification_checkbox;
            var li = $(event.currentTarget).closest("li");
            if (li) {
                push_notification_checkbox = li.find(".new-update-push-notification .toggle-checkbox");
                if (push_notification_checkbox) {
                    return push_notification_checkbox.is(":checked");
                }
            }
        }
    });

    return CourseInfoUpdateView;
}); // end define()
