// (C) Copyright 2020 Hewlett-Packard Enterprise Company, L.P.

define(['hp/presenter/UploaderPresenter',
        'hp/core/Localizer',
        'hp/model/Session',
        'hp/core/Notifications',
        'hp/services/Log',
        'text!hpPages/core/upload_template.html',
        'text!hpPages/core/upload_kiosk_template.html',
        'jquery',
        'hp/view/FormUploader',
        'hp/lib/jquery.hpEllipsis',
        'hp/lib/jquery.hpProgressBar'],

function(Presenter, localizer, session, notifications, log, rawTemplate, kioskTemplate) {"use strict";
    var UploaderView = (function() {

        var SECTION = '.hp-upload-section';
        var PROGRESS = '.hp-upload-progress';
        var CANCEL = '.hp-upload-cancel';
        var DROP_BOX = '.hp-upload-dropbox';
        var UPLOAD = '.hp-upload-select';
        var FILE_CHOOSE = '.hp-upload-file-choose';
        var SEND = '.hp-upload-send';
        var PROGRESS_FILENAME = '.hp-upload-progress-filename';
        var PROGRESS_METER = '.hp-upload-progress-meter';
        var RESULT = '.hp-upload-result';
        var CONTROLS = '.hp-upload-controls';
        var SELECTED = '.hp-upload-selected';

        function UploaderView() {
            
            var presenter = new Presenter();
            var elem;
            var useForm = false;
            var customResult = false;
            var uploadCounter = 0; // give a unique id to each upload attempt.

            function injectExternalContent(id,method){
                if(method){
                    var content = method();
                    if(content){
                        var dest = $(id, elem);
                        $.each(content, function(index,value){
                            dest.append(value);
                        });
                    }
                }
            }
            
            function enableFileChooseButton(enabled) {
                if (enabled) {
                    return $(FILE_CHOOSE, elem).removeAttr('disabled').removeAttr('readonly');
                } else {
                    return $(FILE_CHOOSE, elem).attr('disabled', 'disabled').attr('readonly', true);
                }
            }
            
            function buildFormData() {
                var formData;
                if (! useForm) {
                    formData = new FormData();
                    formData.append("file", presenter.getModel().getFiles()[0]);
                }
                return formData;
            }

            function resetUploader(){
                // $(FORM, elem)[0].reset();
                $(FILE_CHOOSE, elem).attr('value','');
            }

            function noOpDragAndDrop(e) {
                e.stopPropagation();
                e.preventDefault();
            }
            
            function resetProgress() {
                // hides and resets the file upload progress bar
                $(PROGRESS, elem).hide();
                // Added the following to fix a problem in some browsers
                // (usually just chrome).  Sometimes the browser silently fails 
                // to update some DOM elements in the uploader status area. The
                // following line helps to reset the upload progress bar.
                $(PROGRESS_METER, elem).empty();
                $(PROGRESS_METER, elem).hpProgressBar(0);
            }

            function createNamesList(){
                var files = presenter.getFiles();
                var nameList = [];
                $.each(files, function(index,file){
                    nameList.push(file.name);
                });
                return nameList.join(', ');
            }

            function showDefaultSuccessMsg(){
                var msg = localizer.getString('core.upload.defaultSuccess', [createNamesList()]);
                $(RESULT, elem).empty().show().text(msg);
            }

            function uploadSuccess(data, uploadInfo) {
                var opts = presenter.getOptions();
                
                resetProgress();
                enableFileChooseButton(true);
                $(UPLOAD, elem).removeAttr('disabled');
                $(UPLOAD, elem).blur();
                $(DROP_BOX, elem).hide();
                if (! customResult) {
                    showDefaultSuccessMsg(data);
                } else {
                    $(RESULT, elem).show();
                }
                $(SELECTED, elem).hide();
                
                if(uploadInfo && opts.uploadSuccess) {
                    opts.uploadSuccess(data, uploadInfo);
                }
                resetUploader();
            }
            function uploadError(errorInfo, uploadInfo){
                var opts = presenter.getOptions();

                resetProgress();
                enableFileChooseButton(true);
                $(UPLOAD, elem).removeAttr('disabled');
                $(DROP_BOX, elem).show();
                $(RESULT, elem).hide();
                $(SELECTED, elem).hide();
                
                if(opts.uploadError) {
                    opts.uploadError(errorInfo, uploadInfo);
                }
                // wait until after calling error handler to clear file info.
                resetUploader();
            }
            function uploadAbort(){
                enableFileChooseButton(true);
                $(UPLOAD, elem).removeAttr('disabled');
                $(UPLOAD, elem).blur();
                resetProgress();
                $(DROP_BOX, elem).show();
                $(SELECTED, elem).hide();
            }

            function uploadSending(xhr){
                enableFileChooseButton(false);

                // bind the cancel button to the abort function
                $(CANCEL, elem).unbind('click');
                $(CANCEL, elem).bind('click', xhr.abort);
            }
            
            function uploadProgress(data){
                var progress = presenter.getProgress();
                $('progress', elem).show();
                $(PROGRESS_METER, elem).hpProgressBar((progress.value / progress.max) * 100);
            }

            function createFormOpts(optionsCallback, uploadInfo) {
                var options = optionsCallback ? optionsCallback(uploadInfo) : {};
                if (!options) {
                    options = {};
                }
                
                if (useForm) {
                    // IE8 and 9 don't have FormData and need to use the iframe transport
                    // The inputs need to be enabled or they don't get included in the submit
                    var inputs = enableFileChooseButton(true);
                    options.fileInput = inputs;
                    options.dataType = 'iframe json';
                }
                
                return options;
            }
            
            function doUpload() {
                var opts = presenter.getOptions();
                var files = presenter.getFiles();
                var fileName = files[0].name;
                var formData = buildFormData();
                var shouldAbort = false;
                var uploadInfo = {
                        id: uploadCounter++,
                        files: $.extend(true, {}, files)
                    };
                
                if(!opts.uploadUri){
                    log.error("Unable to upload file. The uploadUri has not been specified.");
                    return;
                }
                if(opts.beforeStart){
                    shouldAbort = opts.beforeStart(fileName, uploadInfo);
                }
                
                if (shouldAbort !== true) { // Checking against true allows opts.beforeStart to return undefined and continue
                    
                    $(SELECTED, elem).hide();
                    $(DROP_BOX, elem).hide();
                    $(PROGRESS, elem).show();
                    enableFileChooseButton(false);
                    $(UPLOAD, elem).attr('disabled', 'disabled');
                    $(PROGRESS_FILENAME, elem).text(fileName);
                    $(SEND, elem).attr('disabled','disabled');

                    var uri = opts.uploadUri;

                    presenter.upload(uri,formData, {
                        success : function(data) {
                            uploadSuccess(data, uploadInfo);
                        },
                        error : function(errorInfo) {
                            uploadError(errorInfo, uploadInfo);
                        },
                        beforeSend : function(data) {
                            uploadSending(data);
                            if(opts.beforeSend) {
                                opts.beforeSend(data, uploadInfo);
                            }
                        },
                        onAbort : function(data) {
                            uploadAbort();
                            if(opts.onCancel) {
                                opts.onCancel(data, uploadInfo);
                            }
                        },
                        progressHandler : function(data) {
                            uploadProgress(data);
                            if(opts.progressHandler) {
                                opts.progressHandler(data, uploadInfo);
                            }
                        },
                        optionsCallback : function() {
                            return createFormOpts(opts.optionsCallback, uploadInfo);
                        }
                    });
                }
            }
            
            /**
             * This method is the beginning of separating selecting files to upload from actually uploading them
             * This saves the files object.  A FormData object can then be created by appending the Files to it,
             *     like is currently done in drop.
             * This could also help w/ multiple files, by allowing a whole collection of files to be appended
             *     to a FormData object.
             * Like everything else this will have to be completely different on IE.
             * To support two part upload, a second "uploadSelected" method would be called. If the developer wanted
             *     instant this would call that.
             * There would need to be another button to support 2 part upload.
             */
            function selectForUpload(files){
                var opts = presenter.getOptions();
                presenter.setFiles(files);
                if(opts.onFileSelection){
                    // Don't uses the files passed into the method, because it is raw file objects
                    opts.onFileSelection(presenter.getFiles());
                }
                $(RESULT, elem).hide();

                if(!opts.twoPartUpload){
                    doUpload();
                }else{
                    $(SEND, elem).removeAttr('disabled').focus();
                    var msg = localizer.getString('core.upload.selectedFile',[createNamesList()]);
                    $(SELECTED, elem).empty().text(msg).show();
                    $(DROP_BOX, elem).hide();
                }
            }

            function drop(e) {
                var droppedFiles = null;
                var dataTransfer = null;
                
                if (e.originalEvent && e.originalEvent.dataTransfer) {
                    droppedFiles = e.originalEvent.dataTransfer.files;
                    dataTransfer = e.originalEvent.dataTransfer;
                } else if (e.dataTransfer) {
                    droppedFiles = e.dataTransfer.files;
                    dataTransfer = e.dataTransfer;
                }

                if (dataTransfer) {
                    $(RESULT, elem).hide();
                    $(DROP_BOX, elem).hide();
                    e.stopPropagation();
                    e.preventDefault();
                    var uploading = presenter.getIsUploading();
                    // only upload if something is not already uploading
                    if(!uploading) {
                        if (droppedFiles) {                         
                            if(droppedFiles.length > 0) {
                                selectForUpload(droppedFiles);
                            }
                        }
                        else {
                            // IE 8 and 9 don't have a way to drop files
                            $(DROP_BOX, elem).show();
                            var opts = presenter.getOptions();
                            if(opts && opts.uploadError){
                                opts.uploadError({
                                    message: localizer.getString('core.upload.error.noDrop'),
                                    errorMessage: localizer.getString('core.upload.error.noDrop'),
                                    resolution: '',
                                    recommendedActions: []
                                });
                            }
                        }
                    }
                }
            }
            
            function trimFilename(filepath) {
                // get rid of whitespace on the ends and pull of the filename from the end (allows either \ or / as separators.)
                var parts = $.trim(filepath).split(/[\\\/]/);
                return parts.length > 0 ? parts[parts.length - 1] : filepath;
            }
            
            function checkPending(){
                var opts = presenter.getOptions();
                var uploading = presenter.getIsUploading();
                if(!opts || !opts.pendingUri){
                    return;
                }
                if(!uploading) {
                    presenter.isPending(opts.pendingUri, {
                        success:function(data){
                            uploadSuccess(data, null);
                            if(opts && opts.pendingSuccess) {
                                opts.pendingSuccess(data);
                            }
                        },
                        error:function(errorInfo){
                            if(opts && opts.pendingError) {
                                opts.pendingError(errorInfo);
                            }
                        }
                    });
                }
            }

           function reset(blurButton){
                resetUploader();
                resetProgress();
                $(SELECTED, elem).hide();
                $(RESULT, elem).hide();
                enableFileChooseButton(true);
                $(UPLOAD, elem).removeAttr('disabled');
                $(SEND, elem).attr('disabled','disabled');
                $(DROP_BOX, elem).show();
                if(blurButton){
                    $(UPLOAD, elem).blur();
                }else{
                    $(UPLOAD, elem).focus();
                }
            }
           
            this.reset = reset;

            this.isFilePending = function(){
                return presenter.isUpgradeFilePending();
            };

            this.isUploading = function(){
                return presenter.getIsUploading();
            };

            this.getResults = function(){
                return presenter.getResults();
            };

            this.getError = function(){
                return presenter.getError();
            };

            this.isCanceled = function(){
                return presenter.getAborted();
            };

            this.getFiles = function(){
                return presenter.getFiles();
            };

            this.pause = function(){
            };
            this.resume = function(){
                checkPending();
            };

            this.uploadInit = function (opts) {
                var dropZoneTextKey = 'core.upload.dragAndDrop',
                    chooseButtonText = localizer.getString('core.upload.uploadFile');
                
                presenter.setOptions(opts);
                if(!opts || !opts.uploadBaseId){
                    log.error("Unable to create uploader, 'uploadBaseId' has not been specified");
                    return;
                }
                
                if (typeof FormData === 'undefined') {
                    // IE doesn't have FormData so we have to use the iframe transport in a form submit
                    useForm = true;
                }
                
                elem = $(opts.uploadBaseId);
                
                var template = $(session.isKioskMode() ? kioskTemplate : rawTemplate);
                localizer.localizeDom(template);
                elem.append(template);

                if (useForm) {
                    // hide the progress bar since we can't show progress with a form upload.
                    $(PROGRESS_METER, elem).hide();
                }
                
                if (opts.successContent){
                    customResult = true;
                    $(RESULT, elem).empty();
                    injectExternalContent(RESULT, opts.successContent);
                }
                
                injectExternalContent(CONTROLS, opts.extraButtons);

                $(SECTION, elem).bind('dragenter', noOpDragAndDrop);
                $(SECTION, elem).bind('dragexit', noOpDragAndDrop);
                $(SECTION, elem).bind('dragover', noOpDragAndDrop);
                $(SECTION, elem).bind('drop', drop);

                $(PROGRESS_FILENAME, elem).hpEllipsis();
                
                $(FILE_CHOOSE, elem).change(this, function() {
                    if(this.value) {
                        var files = $(FILE_CHOOSE, elem)[0].files;
                        if (!files) {
                            // probably IE8 or IE9
                            files = [{ name: trimFilename(this.value),
                                      size: undefined }]; // Not possible in IE<10 without ActiveX
                        }
                        selectForUpload(files);
                    } else {
                        $(PROGRESS, elem).hide();
                        enableFileChooseButton(true);
                        $(UPLOAD, elem).removeAttr('disabled');
                    }
                });

                if (opts.twoPartUpload){
                    $(SEND, elem).show().click(function(){
                        doUpload();
                    });
                    chooseButtonText = localizer.getString('core.upload.chooseFile');
                    $(UPLOAD, elem).attr('value', chooseButtonText);

                }
                else{
                    $(SEND, elem).hide();
                    $(SELECTED, elem).hide();
                }

                dropZoneTextKey = useForm ? 'core.upload.browse_only' : 'core.upload.dragAndDrop';
                $(DROP_BOX, elem).text(localizer.getString(dropZoneTextKey, [chooseButtonText]));
                reset();
                
                checkPending();
                if(opts.parentInit){
                    opts.parentInit();
                }
                //$(SELECTED, elem).show().hide();
            };
        }

        return UploaderView;
    }());
    return UploaderView;
});

