;(function (define) {
    'use strict';
    define([
            'jquery',
            'utility',
            'underscore',
            'underscore.string',
            'backbone',
            'js/student_account/models/LoginModel',
            'js/student_account/models/PasswordResetModel',
            'js/student_account/models/RegisterModel',
            'js/student_account/views/LoginView',
            'js/student_account/views/PasswordResetView',
            'js/student_account/views/RegisterView',
            'js/student_account/views/InstitutionLoginView',
            'js/student_account/views/HintedLoginView',
            'js/vendor/history'
        ],
        function($, utility, _, _s, Backbone, LoginModel, PasswordResetModel, RegisterModel, LoginView,
                 PasswordResetView, RegisterView, InstitutionLoginView, HintedLoginView) {

        if (_.isUndefined(_s)) {
            _s = _.str;
        }

        return Backbone.View.extend({
            tpl: '#access-tpl',
            events: {
                'click .form-toggle': 'toggleForm'
            },
            subview: {
                login: {},
                register: {},
                passwordHelp: {},
                institutionLogin: {},
                hintedLogin: {}
            },
            nextUrl: '/dashboard',
            // The form currently loaded
            activeForm: '',

            initialize: function( options ) {

                /* Mix non-conflicting functions from underscore.string
                 * (all but include, contains, and reverse) into the
                 * Underscore namespace
                 */
                _.mixin( _s.exports() );

                this.tpl = $(this.tpl).html();

                this.activeForm = options.initial_mode || 'login';

                this.thirdPartyAuth = options.third_party_auth || {
                    currentProvider: null,
                    providers: []
                };

                this.thirdPartyAuthHint = options.third_party_auth_hint || null;

                if (options.login_redirect_url) {
                    // Ensure that the next URL is internal for security reasons
                    if ( ! window.isExternal( options.login_redirect_url ) ) {
                        this.nextUrl = options.login_redirect_url;
                    }
                }

                this.formDescriptions = {
                    login: options.login_form_desc,
                    register: options.registration_form_desc,
                    reset: options.password_reset_form_desc,
                    institution_login: null,
                    hinted_login: null
                };

                this.platformName = options.platform_name;

                // The login view listens for 'sync' events from the reset model
                this.resetModel = new PasswordResetModel({}, {
                    method: 'GET',
                    url: '#'
                });

                this.render();

                // Once the third party error message has been shown once,
                // there is no need to show it again, if the user changes mode:
                this.thirdPartyAuth.errorMessage = null;
            },

            render: function() {
                $(this.el).html( _.template( this.tpl, {
                    mode: this.activeForm
                }));

                this.postRender();

                return this;
            },

            postRender: function() {
                //get & check current url hash part & load form accordingly
                if (Backbone.history.getHash() === 'forgot-password-modal') {
                    this.resetPassword();
                }
                this.loadForm(this.activeForm);

            },

            loadForm: function( type ) {
                var loadFunc = _.bind( this.load[type], this );
                loadFunc( this.formDescriptions[type] );
            },

            load: {
                login: function( data ) {
                    var model = new LoginModel({}, {
                        method: data.method,
                        url: data.submit_url
                    });

                    this.subview.login =  new LoginView({
                        fields: data.fields,
                        model: model,
                        resetModel: this.resetModel,
                        thirdPartyAuth: this.thirdPartyAuth,
                        platformName: this.platformName
                    });

                    // Listen for 'password-help' event to toggle sub-views
                    this.listenTo( this.subview.login, 'password-help', this.resetPassword );

                    // Listen for 'auth-complete' event so we can enroll/redirect the user appropriately.
                    this.listenTo( this.subview.login, 'auth-complete', this.authComplete );

                },

                reset: function( data ) {
                    this.resetModel.ajaxType = data.method;
                    this.resetModel.urlRoot = data.submit_url;

                    this.subview.passwordHelp = new PasswordResetView({
                        fields: data.fields,
                        model: this.resetModel
                    });

                    // Listen for 'password-email-sent' event to toggle sub-views
                    this.listenTo( this.subview.passwordHelp, 'password-email-sent', this.passwordEmailSent );

                    // Focus on the form
                    $('.password-reset-form').focus();
                },

                register: function( data ) {
                    var model = new RegisterModel({}, {
                        method: data.method,
                        url: data.submit_url
                    });

                    this.subview.register =  new RegisterView({
                        fields: data.fields,
                        model: model,
                        thirdPartyAuth: this.thirdPartyAuth,
                        platformName: this.platformName
                    });

                    // Listen for 'auth-complete' event so we can enroll/redirect the user appropriately.
                    this.listenTo( this.subview.register, 'auth-complete', this.authComplete );
                },

                institution_login: function ( unused ) {
                    this.subview.institutionLogin =  new InstitutionLoginView({
                        thirdPartyAuth: this.thirdPartyAuth,
                        platformName: this.platformName,
                        mode: this.activeForm
                    });

                    this.subview.institutionLogin.render();
                },

                hinted_login: function ( unused ) {
                    this.subview.hintedLogin =  new HintedLoginView({
                        thirdPartyAuth: this.thirdPartyAuth,
                        hintedProvider: this.thirdPartyAuthHint,
                        platformName: this.platformName
                    });

                    this.subview.hintedLogin.render();
                }
            },

            passwordEmailSent: function() {
                var $loginAnchorElement = $('#login-anchor');
                this.element.hide( $(this.el).find('#password-reset-anchor') );
                this.element.show( $loginAnchorElement );
                this.element.scrollTop( $loginAnchorElement );
            },

            resetPassword: function() {
                window.analytics.track('edx.bi.password_reset_form.viewed', {
                    category: 'user-engagement'
                });

                this.element.hide( $(this.el).find('#login-anchor') );
                this.loadForm('reset');
                this.element.scrollTop( $('#password-reset-anchor') );
            },

            toggleForm: function( e ) {
                var type = $(e.currentTarget).data('type'),
                    $form = $('#' + type + '-form'),
                    $anchor = $('#' + type + '-anchor'),
                    queryParams = url('?'),
                    queryStr = queryParams.length > 0 ? '?' + queryParams : '';

                e.preventDefault();

                window.analytics.track('edx.bi.' + type + '_form.toggled', {
                    category: 'user-engagement'
                });

                // Load the form. Institution login is always refreshed since it changes based on the previous form.
                if ( !this.form.isLoaded( $form ) || type == 'institution_login') {
                    this.loadForm( type );
                }
                this.activeForm = type;

                this.element.hide( $(this.el).find('.submission-success') );
                this.element.hide( $(this.el).find('.form-wrapper') );
                this.element.show( $form );
                this.element.scrollTop( $anchor );

                // Update url without reloading page
                if (type != 'institution_login') {
                    History.pushState( null, document.title, '/' + type + queryStr );
                }
                analytics.page( 'login_and_registration', type );

                // Focus on the form
                $('#' + type).focus();
            },

            /**
             * Once authentication has completed successfully:
             *
             * If we're in a third party auth pipeline, we must complete the pipeline.
             * Otherwise, redirect to the specified next step.
             *
             */
            authComplete: function() {
                if (this.thirdPartyAuth && this.thirdPartyAuth.finishAuthUrl) {
                    this.redirect(this.thirdPartyAuth.finishAuthUrl);
                    // Note: the third party auth URL likely contains another redirect URL embedded inside
                } else {
                    this.redirect(this.nextUrl);
                }
            },

            /**
             * Redirect to a URL.  Mainly useful for mocking out in tests.
             * @param  {string} url The URL to redirect to.
             */
            redirect: function( url ) {
                window.location.replace(url);
            },

            form: {
                isLoaded: function( $form ) {
                    return $form.html().length > 0;
                }
            },

            /* Helper method to toggle display
             * including accessibility considerations
             */
            element: {
                hide: function( $el ) {
                    $el.addClass('hidden');
                },

                scrollTop: function( $el ) {
                    // Scroll to top of selected element
                    $('html,body').animate({
                        scrollTop: $el.offset().top
                    },'slow');
                },

                show: function( $el ) {
                    $el.removeClass('hidden');
                }
            }
        });
    });
}).call(this, define || RequireJS.define);
