(function(context,$) {

    "use strict";

    context.JK = context.JK || {};
    context.JK.AccountProfileAvatarScreen = function(app) {
        var self = this;
        var logger = context.JK.logger;
        var EVENTS = context.JK.EVENTS;
        var rest = context.JK.Rest();
        var user = {};
        var tmpUploadPath = null;
        var userDetail = null;
        var avatar;
        var selection = null;
        var targetCropSize = 88;
        var largerCropSize = 200;
        var updatingAvatar = false;
        var userDropdown;

        function beforeShow(data) {
        }


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

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

        function populateAvatar(userDetail) {
            self.userDetail = userDetail;
            rest.getFilepickerPolicy()
                .done(function(filepicker_policy) {
                    var template= context.JK.fillTemplate($('#template-account-profile-avatar').html(), {
                        "fp_apikey" : gon.fp_apikey,
                        "data-fp-store-path" : createStorePath(userDetail) + createOriginalFilename(userDetail),
                        "fp_policy" : encodeURIComponent(filepicker_policy.policy),
                        "fp_signature" : encodeURIComponent(filepicker_policy.signature)
                    });
                    $('#account-profile-avatar-content-scroller').html(template);


                    var currentFpfile = determineCurrentFpfile();
                    var currentCropSelection = determineCurrentSelection(userDetail);
                    renderAvatar(currentFpfile, currentCropSelection ? JSON.parse(currentCropSelection) : null);
                })
                .error(app.ajaxError);

        }

        // events for main screen
        function events() {
            // wire up main panel clicks
            $('#account-profile-avatar-content-scroller').on('click', '#account-edit-avatar-upload', function(evt) { evt.stopPropagation(); handleFilePick(); return false; } );
            $('#account-profile-avatar-content-scroller').on('click', '#account-edit-avatar-delete', function(evt) { evt.stopPropagation(); handleDeleteAvatar(); return false; } );
            $('#account-profile-avatar-content-scroller').on('click', '#account-edit-avatar-cancel', function(evt) { evt.stopPropagation(); navToEditProfile(); return false; } );            
            enableSubmits()
            //$('#account-profile-avatar-content-scroller').on('change', 'input[type=filepicker-dragdrop]', function(evt) { evt.stopPropagation(); afterImageUpload(evt.originalEvent.fpfile); return false; } );
        }

        function enableSubmits() {
          $('#account-profile-avatar-content-scroller').on('click', '#account-edit-avatar-submit', function(evt) { evt.stopPropagation(); handleUpdateAvatar(); return false; } );
          $("#account-edit-avatar-submit").removeClass("disabled")
        }

        function disableSubmits() {
          $("#account-edit-avatar-submit").addClass("disabled")
          $("#account-edit-avatar-submit").off("click")
        }

        function handleDeleteAvatar() {

            if(self.updatingAvatar) {
                // protect against concurrent update attempts
                return;
            }

            self.updatingAvatar = true;
            renderAvatarSpinner();

            rest.deleteAvatar()
                .done(function() {
                    removeAvatarSpinner({ delete:true });
                    deleteAvatarSuccess(arguments);
                    selection = null;
                })
                .fail(function() {
                    app.ajaxError(arguments);
                    $.cookie('original_fpfile', null);
                    self.updatingAvatar = false;
                })
                .always(function() {

                })
        }

        function deleteAvatarSuccess(response) {

            renderAvatar(null, null);
            userDropdown.loadMe();

            rest.getUserDetail()
                .done(function(userDetail) {
                    self.userDetail = userDetail;
                })
                .error(app.ajaxError)
                .always(function() {
                    self.updatingAvatar = false;
                })
        }

        function handleFilePick() {

            rest.getFilepickerPolicy()
                .done(function(filepickerPolicy) {
                    renderAvatarSpinner();
                    filepicker.setKey(gon.fp_apikey);
                    filepicker.pickAndStore({
                            mimetype: 'image/*',
                            maxSize: 10000*1024,
                            policy: filepickerPolicy.policy,
                            signature: filepickerPolicy.signature
                            }, { path: createStorePath(self.userDetail), access: 'public'  },
                        function(fpfiles) {
                            removeAvatarSpinner();
                            afterImageUpload(fpfiles[0]);
                        }, function(fperror) {
                            removeAvatarSpinner();

                            if(fperror.code != 101) { // 101 just means the user closed the dialog
                                alert("unable to upload file: " + JSON.stringify(fperror))
                            }
                        })
                })
                .fail(app.ajaxError);

        }
        function renderAvatarScreen() {

            rest.getUserDetail()
                .done(populateAvatar)
                .error(app.ajaxError)
        }

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

        function renderAvatarSpinner() {
            var avatarSpace = $('#account-profile-avatar-content-scroller .account-profile-avatar .avatar-space');
            // if there is already an image tag, we only obscure it.

            var avatar = $('img.preview_profile_avatar', avatarSpace);

            var spinner = $('<div class="spinner spinner-large"></div>')
            if(avatar.length === 0) {
                avatarSpace.prepend(spinner);
            }
            else {
                // in this case, just style the spinner to obscure using opacity, and center it
                var jcropHolder = $('.jcrop-holder', avatarSpace);
                spinner.width(jcropHolder.width());
                spinner.height(jcropHolder.height());
                spinner.addClass('op50');
                var jcrop = avatar.data('Jcrop');
                if(jcrop) {
                    jcrop.disable();
                }
                avatarSpace.append(spinner);
            }
        }

        function removeAvatarSpinner(options) {
            var avatarSpace = $('#account-profile-avatar-content-scroller .account-profile-avatar .avatar-space');

            if(options && options.delete) {
                avatarSpace.children().remove();
            }

            var spinner = $('.spinner-large', avatarSpace);
            spinner.remove();
            var avatar = $('img.preview_profile_avatar', avatarSpace);
            var jcrop = avatar.data('Jcrop')
            if(jcrop) {
                jcrop.enable();
            }
        }

        function renderAvatar(fpfile, storedSelection) {

            // clear out
            var avatarSpace = $('#account-profile-avatar-content-scroller .account-profile-avatar .avatar-space');

            if(!fpfile) {
                renderNoAvatar(avatarSpace);
            }
            else {
                rest.getFilepickerPolicy({handle: fpfile.url})
                    .done(function(filepickerPolicy) {
                        avatarSpace.children().remove();
                        renderAvatarSpinner();

                        var photo_url = fpfile.url + '?signature=' + filepickerPolicy.signature + '&policy=' + filepickerPolicy.policy;
                        avatar = new Image();
                        $(avatar)
                            .load(function(e) {
                                removeAvatarSpinner();

                                avatar = $(this);
                                avatarSpace.append(avatar);
                                var width = avatar.naturalWidth();
                                var height = avatar.naturalHeight();

                                if(storedSelection) {
                                    var left = storedSelection.x;
                                    var right = storedSelection.x2;
                                    var top = storedSelection.y;
                                    var bottom = storedSelection.y2;
                                }
                                else {
                                    if(width < height) {
                                        var left = width * .25;
                                        var right = width * .75;
                                        var top = (height / 2) - (width / 4);
                                        var bottom = (height / 2) + (width / 4);
                                    }
                                    else {
                                        var top = height * .25;
                                        var bottom = height * .75;
                                        var left = (width / 2) - (height / 4);
                                        var right = (width / 2) + (height / 4);
                                    }
                                }

                                // jcrop only works well with px values (not percentages)
                                // so we get container, and work out a decent % ourselves
                                var container = $('#account-profile-avatar-content-scroller');

                                avatar.Jcrop({
                                    aspectRatio: 1,
                                    boxWidth: container.width() * .75,
                                    boxHeight: container.height() * .75,
                                    // minSelect: [targetCropSize, targetCropSize], unnecessary with scaling involved
                                    setSelect: [ left, top, right, bottom ],
                                    trueSize: [width, height],
                                    onRelease: onSelectRelease,
                                    onSelect: onSelect,
                                    onChange: onChange
                                });
                            })
                            .error(function() {
                                // default to no avatar look of UI
                                renderNoAvatar(avatarSpace);
                            })
                            .attr('src', photo_url)
                            .attr('alt', 'profile avatar')
                            .addClass('preview_profile_avatar');
                    })
                    .fail(app.ajaxError);
            }
        }

        function afterImageUpload(fpfile) {

            $.cookie('original_fpfile', JSON.stringify(fpfile));

            renderAvatar(fpfile, null);
        }

        function renderNoAvatar(avatarSpace) {
            // no avatar found for account

            removeAvatarSpinner();

            var noAvatarSpace = $('<div></div>');
            noAvatarSpace.addClass('no-avatar-space');
            noAvatarSpace.text('Please upload a photo');
            avatarSpace.append(noAvatarSpace);
        }

        function handleUpdateAvatar(event) {
            disableSubmits()
            if(self.updatingAvatar) {
                // protect against concurrent update attempts
                return;
            }

            if(selection) {
                var currentSelection = selection;
                self.updatingAvatar = true;
                renderAvatarSpinner();

                logger.debug("Converting...");

                // we convert two times; first we crop to the selected region,
                // then we scale to 88x88 (targetCropSize X targetCropSize), which is the largest size we use throughout the site.
                var fpfile = determineCurrentFpfile();
                rest.getFilepickerPolicy({ handle: fpfile.url, convert: true })
                    .done(function(filepickerPolicy) {
                        filepicker.setKey(gon.fp_apikey);
                        filepicker.convert(fpfile, {
                                crop: [
                                    Math.round(currentSelection.x),
                                    Math.round(currentSelection.y),
                                    Math.round(currentSelection.w),
                                    Math.round(currentSelection.w)],
                                fit: 'crop',
                                format: 'jpg',
                                quality: 90,
                                policy: filepickerPolicy.policy,
                                signature: filepickerPolicy.signature
                            }, { path: createStorePath(self.userDetail) + 'cropped-' + new Date().getTime() + '.jpg', access: 'public' },
                            function(cropped) {
                                logger.debug("converting cropped");
                                rest.getFilepickerPolicy({handle: cropped.url, convert: true})
                                    .done(function(filepickerPolicy) {
                                        filepicker.convert(cropped, {
                                                height: targetCropSize,
                                                width: targetCropSize,
                                                fit: 'scale',
                                                format: 'jpg',
                                                quality: 75,
                                                policy: filepickerPolicy.policy,
                                                signature: filepickerPolicy.signature
                                            },  { path: createStorePath(self.userDetail), access: 'public' },
                                            function(scaled) {
                                                filepicker.convert(cropped, {
                                                        height: largerCropSize,
                                                        width: largerCropSize,
                                                        fit: 'scale',
                                                        format: 'jpg',
                                                        quality: 75,
                                                        policy: filepickerPolicy.policy,
                                                        signature: filepickerPolicy.signature
                                                    },  { path: createStorePath(self.userDetail) + 'large.jpg', access: 'public' },
                                                    function(scaledLarger) {
                                                        logger.debug("converted and scaled final image %o", scaled);
                                                        rest.updateAvatar({
                                                            original_fpfile: determineCurrentFpfile(),
                                                            cropped_fpfile: scaled,
                                                            cropped_large_fpfile: scaledLarger,
                                                            crop_selection: currentSelection
                                                        })
                                                        .done(updateAvatarSuccess)
                                                        .fail(app.ajaxError)
                                                        .always(function() { removeAvatarSpinner(); self.updatingAvatar = false;})
                                                    },
                                                    function(fperror) {
                                                        alert("unable to scale larger selection. error code: " + fperror.code);
                                                        removeAvatarSpinner();
                                                        self.updatingAvatar = false;
                                                    });
                                            },
                                            function(fperror) {
                                                alert("unable to scale selection. error code: " + fperror.code);
                                                removeAvatarSpinner();
                                                self.updatingAvatar = false;
                                            })
                                    })
                                    .fail(app.ajaxError);
                            },
                            function(fperror) {
                                alert("unable to crop selection. error code: " + fperror.code);
                                removeAvatarSpinner();
                                self.updatingAvatar = false;
                            }
                        );
                    })
                    .fail(app.ajaxError);
            }
            else {
                app.notify(
                    {   title: "Upload an Avatar First",
                        text: "To update your avatar, first you must upload an image using the UPLOAD button"
                    },
                    null,
                    true);
            }  
            enableSubmits()          
        }

        function updateAvatarSuccess(response) {            
            $.cookie('original_fpfile', null);

            self.userDetail = response;

            // notify any listeners that the avatar changed
            // userDropdown.loadMe();
            // $('.avatar_large img').trigger('avatar_changed', [self.userDetail.photo_url]);
            $(document).triggerHandler(EVENTS.USER_UPDATED, response);
            app.notify(
                {   title: "Avatar Changed",
                    text: "You have updated your avatar successfully."
                },
                null,
                true);
        }

        function onSelectRelease(event) {
        }

        function onSelect(event) {
            selection = event;
        }

        function onChange(event) {
        }

        function createStorePath(userDetail) {

            return gon.fp_upload_dir + '/' + userDetail.id + '/'
        }

        function createOriginalFilename(userDetail) {
            // get the s3
            var fpfile = userDetail.original_fpfile ? JSON.parse(userDetail.original_fpfile) : null;
            return 'original_avatar.jpg'
        }

        // retrieves a file that has not yet been used as an avatar (uploaded, but not cropped)
        function getWorkingFpfile() {
            return JSON.parse($.cookie('original_fpfile'))
        }

        function determineCurrentFpfile() {
            // precedence is as follows:
            // * tempOriginal: if set, then the user is working on a new upload
            // * storedOriginal: if set, then the user has previously uploaded and cropped an avatar
            // * null: neither are set above

            var tempOriginal = getWorkingFpfile();
            var storedOriginal = self.userDetail.original_fpfile ? JSON.parse(self.userDetail.original_fpfile) : null;

            return tempOriginal ? tempOriginal : storedOriginal;
        }

        function determineCurrentSelection(userDetail) {
            // if the cookie is set, don't use the storage selection, just default to null
            return $.cookie('original_fpfile') == null ? userDetail.crop_selection : null;
        }

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

            userDropdown = userDropdownInstance;
        }

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

})(window,jQuery);