(function(context,$) {

    "use strict";

    context.JK = context.JK || {};
    context.JK.AccountProfileScreen = function(app) {
        var logger = context.JK.logger;
        var api = context.JK.Rest();
        var userId;
        var user = {};
        var recentUserDetail = null;
        var loadingCitiesData = false;
        var loadingRegionsData = false;
        var loadingCountriesData = false;
        var nilOptionText = 'n/a';

        function beforeShow(data) {
            userId = data.id;
        }

        function afterShow(data) {
            resetForm();
            renderAccountProfile();
        }

        function resetForm() {
            // remove all display errors
            $('#account-profile-content-scroller form .error-text').remove()
            $('#account-profile-content-scroller form .error').removeClass("error")
        }

        function populateAccountProfile(userDetail, instruments) {
            var template = context.JK.fillTemplate($('#template-account-profile').html(), {
                country: userDetail.country,
                region: userDetail.state,
                city: userDetail.city,
                first_name: userDetail.first_name,
                last_name: userDetail.last_name,
                user_instruments: userDetail.instruments,
                birth_date : userDetail.birth_date,
                gender: userDetail.gender
            });

            var content_root = $('#account-profile-content-scroller')
            content_root.html(template);

            // now use javascript to fix up values too hard to do with templating

            // set gender
            $('select[name=gender]', content_root).val(userDetail.gender)

            // set birth_date
            if(userDetail.birth_date) {
                var birthDateFields = userDetail.birth_date.split('-')
                var birthDateYear = birthDateFields[0];
                var birthDateMonth = birthDateFields[1];
                var birthDateDay = birthDateFields[2];

                $('select#user_birth_date_1i', content_root).val(parseInt(birthDateYear));
                $('select#user_birth_date_2i', content_root).val(parseInt(birthDateMonth));
                $('select#user_birth_date_3i', content_root).val(parseInt(birthDateDay));
            }

            // update instruments
            $.each(instruments, function(index, instrument) {

                var template = context.JK.fillTemplate($('#account-profile-instrument').html(), {
                    checked : isUserInstrument(instrument, userDetail.instruments) ? "checked=\"checked\"" :"",
                    description : instrument.description,
                    id : instrument.id
                })
                $('.instrument_selector', content_root).append(template)
            })
            // and fill in the proficiency for the instruments that the user can play
            if(userDetail.instruments) {
                $.each(userDetail.instruments, function(index, userInstrument) {
                    $('tr[data-instrument-id="' + userInstrument.instrument_id + '"] select.proficiency_selector', content_root).val(userInstrument.proficiency_level)
                })
            }
        }

        function isUserInstrument(instrument, userInstruments) {
            var isUserInstrument = false;
            if(!userInstruments) return false;

            $.each(userInstruments, function(index, userInstrument) {
                if(instrument.id == userInstrument.instrument_id) {
                    isUserInstrument = true;
                    return false;
                }
            })
            return isUserInstrument;
        }

        function populateAccountProfileLocation(userDetail, regions, cities) {
            populateRegions(regions, userDetail.state);
            populateCities(cities, userDetail.city);
        }


        function populateCountries(countries, userCountry) {

            var foundCountry = false;
            var countrySelect = getCountryElement()
            countrySelect.children().remove()

            var nilOption = $('<option value=""></option>');
            nilOption.text(nilOptionText);
            countrySelect.append(nilOption);

            $.each(countries, function(index, country) {
                if(!country) return;

                var option = $('<option></option>');
                option.text(country);
                option.attr("value", country);

                if(country == userCountry) {
                    foundCountry = true;
                }

                countrySelect.append(option)
            });

            if(!foundCountry) {
               // in this case, the user has a country that is not in the database
               // this can happen in a development/test scenario, but let's assume it can
               // happen in production too.
                var option = $('<option></option>');
                option.text(userCountry);
                option.attr("value", userCountry);
                countrySelect.append(option);
            }

            countrySelect.val(userCountry);
            countrySelect.attr("disabled", null)
        }


        function populateRegions(regions, userRegion) {
            var regionSelect = getRegionElement()
            regionSelect.children().remove()

            var nilOption = $('<option value=""></option>');
            nilOption.text(nilOptionText);
            regionSelect.append(nilOption);

            $.each(regions, function(index, region) {
                if(!region) return;

                var option = $('<option></option>')
                option.text(region)
                option.attr("value", region)

                regionSelect.append(option)
            })

            regionSelect.val(userRegion)
            regionSelect.attr("disabled", null)
        }

        function populateCities(cities, userCity) {
            var citySelect = getCityElement();
            citySelect.children().remove();

            var nilOption = $('<option value=""></option>');
            nilOption.text(nilOptionText);
            citySelect.append(nilOption);

            $.each(cities, function(index, city) {
                if(!city) return;

                var option = $('<option></option>')
                option.text(city)
                option.attr("value", city)

                citySelect.append(option)
            })

            citySelect.val(userCity)
            citySelect.attr("disabled", null)
        }

        /****************** MAIN PORTION OF SCREEN *****************/
            // events for main screen
        function events() {
            $('#account-profile-content-scroller').on('click', '#account-edit-profile-cancel', function(evt) { evt.stopPropagation(); navToAccount(); return false; } );
            $('#account-profile-content-scroller').on('click', '#account-edit-profile-submit', function(evt) { evt.stopPropagation(); handleUpdateProfile(); return false; } );
            $('#account-profile-content-scroller').on('submit', '#account-edit-email-form', function(evt) { evt.stopPropagation(); handleUpdateProfile(); return false; } );
            $('#account-profile-content-scroller').on('change', 'select[name=country]', function(evt) {  evt.stopPropagation(); handleCountryChanged(); return false; } );
            $('#account-profile-content-scroller').on('change', 'select[name=region]', function(evt) {  evt.stopPropagation(); handleRegionChanged(); return false; } );
            $('#account-profile-content-scroller').on('click', '#account-change-avatar', function(evt) {  evt.stopPropagation(); navToAvatar(); return false; } );
        }

        function regionListFailure(jqXHR, textStatus, errorThrown) {
            if(jqXHR.status == 422) {
                console.log("no regions found for country: " + recentUserDetail.country);
            }
            else {
                app.ajaxError(arguments);
            }
        }

        function cityListFailure(jqXHR, textStatus, errorThrown) {
            if(jqXHR.status == 422) {
                console.log("no cities found for country/region: " + recentUserDetail.country + "/" + recentUserDetail.state);
            }
            else {
                app.ajaxError(arguments);
            }
        }
        function renderAccountProfile() {

            $.when( api.getUserDetail(),
                    api.getInstruments())
                .done(function(userDetailResponse, instrumentsResponse) {
                    var userDetail = userDetailResponse[0];
                    recentUserDetail = userDetail // store userDetail for later
                    var instruments = instrumentsResponse[0];
                    // show page; which can be done quickly at this point
                    populateAccountProfile(userDetail, instruments);

                    var country = userDetail.country;

                    if(!country) {
                        // this case shouldn't happen because sign up makes you pick a location.  This is just 'in case', so that the UI is more error-resilient
                        country = 'US';
                    }

                    loadingCountriesData = true;
                    loadingRegionsData = true;
                    loadingCitiesData = true;

                    // make the 3 slower requests, which only matter if the user wants to affect their ISP or location

                    api.getCountries()
                        .done(function(countries) { populateCountries(countries["countries"], userDetail.country); } )
                        .fail(app.ajaxError)
                        .always(function() { loadingCountriesData = false; })

                    var country = userDetail.country;
                    var state = userDetail.state;

                    if(country) {
                        api.getRegions( { country: country } )
                            .done(function(regions) { populateRegions(regions["regions"], userDetail.state); } )
                            .fail(regionListFailure)
                            .always(function() { loadingRegionsData = false; })

                            if(state) {
                                api.getCities( { country: country, region: state })
                                    .done(function(cities) {
                                        populateCities(cities["cities"], userDetail.city)
                                    })
                                    .fail(cityListFailure)
                                    .always(function() { loadingCitiesData = false;})
                            }
                    }


                })
        }

        function navToAccount() {
            resetForm();
            window.location = '#/account';
        }

        function navToAvatar() {
            resetForm();
            window.location = '#/account/profile/avatar';
        }

        function handleUpdateProfile() {

            resetForm();

            var country = getCountryElement().val();
            var region = getRegionElement().val();
            var city = getCityElement().val();
            var firstName = getFirstNameElement().val();
            var lastName = getLastNameElement().val();
            var gender = getGenderElement().val()
            var birthDate = getBirthDate();
            var instruments = getInstrumentsValue();

            postUpdateProfile({
                country: country,
                state: region,
                city: city,
                first_name: firstName,
                last_name: lastName,
                gender: gender,
                birth_date: birthDate,
                instruments: instruments
            })
            .done(postUpdateProfileSuccess)
            .fail(postUpdateProfileFailure)
        }

        function postUpdateProfile(options) {

            var url = "/api/users/" + context.JK.currentUserId;
            return $.ajax({
                type: "POST",
                dataType: "json",
                contentType: 'application/json',
                url: url,
                data: JSON.stringify(options),
                processData: false
            });
        }

        function postUpdateProfileSuccess(response) {
            app.notify(
                {   title: "Profile Changed",
                    text: "You have updated your profile successfully."
                },
                { no_cancel: true });
        }

        function postUpdateProfileFailure(xhr, textStatus, errorMessage) {

            var errors = JSON.parse(xhr.responseText)

            if(xhr.status == 422) {

                var first_name = context.JK.format_errors("first_name", errors);
                var last_name = context.JK.format_errors("last_name", errors);
                var country = context.JK.format_errors("country", errors);
                var state = context.JK.format_errors("state", errors);
                var city = context.JK.format_errors("city", errors);
                var birth_date = context.JK.format_errors("birth_date", errors);
                var gender = context.JK.format_errors("birth_date", errors);
                var instruments = context.JK.format_errors("musician_instruments", errors)

                if(first_name != null) {
                    getFirstNameElement().closest('div.field').addClass('error').end().after(first_name);
                }

                if(last_name != null) {
                    getLastNameElement().closest('div.field').addClass('error').end().after(last_name);
                }

                if(country != null) {
                    getCountryElement().closest('div.field').addClass('error').end().after(country);
                }

                if(state != null) {
                    getRegionElement().closest('div.field').addClass('error').end().after(state);
                }

                if(city != null) {
                    getCityElement().closest('div.field').addClass('error').end().after(city);
                }

                if(birth_date != null) {
                    getYearElement().closest('div.field').addClass('error').end().after(birth_date);
                }

                if(gender != null) {
                    getGenderElement().closest('div.field').addClass('error').end().after(gender);
                }

                if(instruments != null) {
                    getInstrumentsElement().closest('div.field').addClass('error').append(instruments);
                }
            }
            else {
                app.ajaxError(xhr, textStatus, errorMessage)
            }
        }

        function handleCountryChanged() {
            var selectedCountry = getCountryElement().val()
            var selectedRegion = getRegionElement().val()
            var cityElement = getCityElement();

            updateRegionList(selectedCountry, getRegionElement());
        }

        function updateRegionList(selectedCountry, regionElement) {
            // only update region
            if (selectedCountry) {
                // set city disabled while updating
                regionElement.attr('disabled', true);
                loadingRegionsData = true;

                regionElement.children().remove()
                regionElement.append($('<option value=""></option>').text('loading...'))

                api.getRegions({ country: selectedCountry })
                    .done(getRegionsDone)
                    .fail(app.ajaxError)
                    .always(function () {
                        loadingRegionsData = false;
                    })
            }
            else {
                regionElement.children().remove()
                regionElement.append($('<option value=""></option>').text(nilOptionText))
            }
        }

        function updateCityList(selectedCountry, selectedRegion, cityElement) {
            console.log("updating city list: selectedCountry %o, selectedRegion %o", selectedCountry, selectedRegion);

            // only update cities
            if (selectedCountry && selectedRegion) {
                // set city disabled while updating
                cityElement.attr('disabled', true);
                loadingCitiesData = true;

                cityElement.children().remove()
                cityElement.append($('<option value=""></option>').text('loading...'))

                api.getCities({ country: selectedCountry, region: selectedRegion })
                    .done(getCitiesDone)
                    .fail(app.ajaxError)
                    .always(function () {
                        loadingCitiesData = false;
                    })
            }
            else {
                cityElement.children().remove()
                cityElement.append($('<option value=""></option>').text(nilOptionText))
            }
        }

        function handleRegionChanged() {
            var selectedCountry = getCountryElement().val()
            var selectedRegion = getRegionElement().val()
            var cityElement = getCityElement();

            updateCityList(selectedCountry, selectedRegion, cityElement);
        }

        function getCitiesDone(data) {
            populateCities(data['cities'], recentUserDetail.city);
        }

        function getRegionsDone(data) {
            populateRegions(data['regions'], recentUserDetail.state);
            updateCityList(getCountryElement().val(), getRegionElement().val(), getCityElement());
        }

        function getCountryElement() {
            return $('#account-profile-content-scroller select[name=country]');
        }

        function getRegionElement() {
            return $('#account-profile-content-scroller select[name=region]');
        }

        function getCityElement() {
            return $('#account-profile-content-scroller select[name=city]');
        }

        function getFirstNameElement() {
            return $('#account-profile-content-scroller input[name=first_name]');
        }

        function getLastNameElement() {
            return $('#account-profile-content-scroller input[name=last_name]');
        }

        function getGenderElement() {
            return $('#account-profile-content-scroller select[name=gender]');
        }

        function getMonthElement() {
            return $('#account-profile-content-scroller select#user_birth_date_2i');
        }

        function getDayElement() {
            return $('#account-profile-content-scroller select#user_birth_date_3i');
        }

        function getYearElement() {
            return $('#account-profile-content-scroller select#user_birth_date_1i');
        }

        function getInstrumentsElement() {
            return $('#account-profile-content-scroller .instrument_selector');
        }


        function getBirthDate() {
            var month = getMonthElement().val()
            var day =   getDayElement().val()
            var year =  getYearElement().val()

            if(month != null && month.length > 0 && day != null && day.length > 0 && year != null && year.length > 0) {
                return month + "-" + day + "-" + year;
            }
            else {
                return null;
            }
        }

        // looks in instrument_selector parent element, and gathers up all
        // selected elements, and the proficiency level declared
        function getInstrumentsValue() {
            var instrumentsParentElement = getInstrumentsElement();

            var instruments = []
            $('input[type=checkbox]:checked', instrumentsParentElement).each(function(i) {

                var instrumentElement = $(this).closest('tr');
                // traverse up to common parent of this instrument, and pick out proficiency selector
                var proficiency = $('select.proficiency_selector', instrumentElement).val()

                instruments.push({
                    instrument_id: instrumentElement.attr('data-instrument-id'),
                    proficiency_level: proficiency,
                    priority : i
                })
            });

            return instruments;
        }

        function initialize() {
            var screenBindings = {
                'beforeShow': beforeShow,
                'afterShow': afterShow
            };
            app.bindScreen('account/profile', screenBindings);
            events();
        }

        this.initialize = initialize;
        this.beforeShow = beforeShow;
        this.afterShow = afterShow;
        return this;
    };

})(window,jQuery);