// (C) Copyright 2020 Hewlett-Packard Enterprise Company, L.P.
define(['hp/core/Sidebar',
    'hp/model/DevelopmentSettings',
    'hp/core/LinkTargetBuilder',
    'hp/core/Localizer',
    'hp/core/Style',
    'hp/view/DialogView',
    'hp/model/UploadManager',
    'text!hpPages/core/upload-cancel-confirmation.html',
    'jquery',
    'modernizr',
    'hp/lib/date',
    'hp/lib/jquery.hpStatus',
    'hp/lib/jquery.hpSafeClone',
    'hp/lib/jquery.hpTimestamp',
    'hp/lib/jquery.hpTooltip',
    'hp/lib/jquery.hpUtilizationMeter'],
function (sidebar, settings, linkTargetBuilder, localizer, style, DialogView, UploadManager, cancel_confirm_content) {
"use strict";

    var Uploads = (function () {

        var INFOBAR = '#hp-info-bar';
        var CONTROL = '#hp-upload-control';
        var CONTROL_COUNT = '#hp-upload-control-new-count';
        var NEW_COUNT = '#hp-upload-new-count';
        var FLYOUT = '#hp-upload-flyout';
        var CONTENTS = FLYOUT + ' .hp-flyout-contents';
        var LIST = '#hp-flyout-uploads';
        var TEMPLATE = '#hp-flyout-upload-template';
        var CANCEL_DIALOG_QUESTION = '#upload-cancel-confirmation-question';
        var BODY = '#hp-body-div';
        var ACTIVE = 'hp-active';
        var NEW = 'hp-new';
        var SELECTED = 'hp-selected';
        var CHANGING = 'changing';
        var TAB = 9;
        var ESCAPE = 27;
        var UP_ARROW = 38;
        var DOWN_ARROW = 40;

        /**
         * @constructor
         * @type {Uploads}
         */
        function Uploads() {

            var template = null;
            var isIe8or9 = false;
            var handlersList = [];
            
            function stopMouseCapture() {
                $(BODY).off('mouseup', stopMouseCapture);
            }
            
            function onMouseDown() {
                $(BODY).on('mouseup', stopMouseCapture);
            }
            
            function onFlyoutClick(event) {
                //click event within the flyout should not close 
                //the flyout unless user clicked on a link
                if (event.target.tagName !== "A") {
                    event.preventDefault();
                    event.stopPropagation();
                }
            }
            
            var deselectRow = function() {}; // forward reference for Sonar
            var selectRow = function() {}; // forward reference for Sonar
            
            /*
             * Selects the next row.  Used by key listeners
             */
            function nextRow() {
                var rows = $(FLYOUT + ' .hp-fileupload');
                rows.each(function (index, row) {
                    if ($(row).hasClass(SELECTED) &&
                        rows.length > (index + 1)) {
                        deselectRow();
                        selectRow($(rows[index+1]));
                        return false;
                    }
                });
            }

            /*
             * Selects the previous row.  Used by key listeners
             */
            function previousRow() {
                var rows = $(FLYOUT + ' .hp-fileupload');
                rows.each(function (index, row) {
                    if ($(row).hasClass(SELECTED) && index > 0) {
                        deselectRow();
                        selectRow($(rows[index-1]));
                        return false;
                    }
                });
            }
            
            function onKeypress(ev) {
                var keyCode = (ev.which ? ev.which : ev.keyCode);
                if (keyCode === ESCAPE || keyCode === TAB) {
                    deselectRow();
                } else if (keyCode === DOWN_ARROW) {
                    nextRow();
                    ev.preventDefault();
                } else if (keyCode === UP_ARROW) {
                    previousRow();
                    ev.preventDefault();
                }
            }
            
            
            /*
             * Deselects the row.  Used by key and mouse listeners.  Collapses the detail flyout
             */            
            deselectRow = function () {
                var row = $(FLYOUT + ' .hp-fileupload.hp-selected');
                $(row).off('mousedown', onMouseDown);
                $('.hp-full', row).off('click', onFlyoutClick);
                $('.hp-full', row).off('scroll', stopMouseCapture);
                $(row).removeClass(SELECTED);
                $(BODY).off('click', deselectRow);
                $(document).off('keydown', onKeypress);
            };

            /*
             * Selects the row.  Used by key and mouse listeners.  Expands the detail flyout
             */               
            selectRow = function (row) {
                $(row).addClass(SELECTED);
                $(row).on('mousedown', onMouseDown);
                // click event within the flyout should not close the flyout
                $('.hp-full', row).on('click', onFlyoutClick);
                // scroll event of flyout needs to stop capturing the mousemove
                $('.hp-full', row).on('scroll', stopMouseCapture);
                // position next to upload, unless it would be off the bottom
                if (row.position().top + $('.hp-full', row).outerHeight() >
                    $(CONTENTS).position().top + $(CONTENTS).height() + 10) {
                    $('.hp-full', row).css('top',
                        Math.max(0, $(CONTENTS).position().top +
                            $(CONTENTS).height() -
                            $('.hp-full', row).outerHeight()));
                } else {
                    $('.hp-full', row).css('top', row.position().top);
                }
                $(document).on('keydown', onKeypress);
                // delay to avoid flickering
                setTimeout(function () {$(BODY).on('click', deselectRow);}, 50);
            };
            
            function onClickRow(event) {
                var row = $(this).closest('.hp-fileupload');
                var add = ! row.hasClass('hp-selected');
                deselectRow();
                if (add) {
                    selectRow(row);
                }
            }
            
            
            function removeCompletedRows() {
                var rows = $(FLYOUT + ' .hp-fileupload');
                rows.each(function (index, row) {
                    var id = '#'+ row.id;
                    if ($(id + ' .hp-status-ok').length > 0 || 
                        $(id + ' .hp-status-error').length > 0 ||
                        $(id + ' .hp-status-disabled').length > 0) {
                        $(row).remove();
                    }
                });
                UploadManager.clean();
            }            
            
            /*
             * Updates the count, toggles the upload icon and infobar according to the current upload status
             */
            function updateUploadProgressComponents() {
                var count = 0;
                $.each(UploadManager.getUploadList(), function(index, upldr) {
                    if (upldr.isUploading()) {
                        count++;
                    }
                });
                $(CONTROL_COUNT).text(count);
                $(NEW_COUNT).text(count);
                if (count > 0) {
                    $(INFOBAR).removeAttr("style");
                    $(INFOBAR).addClass('hp-active');
                    $(CONTROL_COUNT).addClass(ACTIVE);
                    $(CONTROL).closest('li').removeAttr("style");
                } else {
                    $(INFOBAR).removeClass('hp-active');
                    $(INFOBAR).attr("style", "display: none;");
                    $(CONTROL_COUNT).removeClass(ACTIVE);
                    if (!$(FLYOUT).hasClass(ACTIVE)) {
                        $(CONTROL).closest('li').attr("style", "display: none;");
                        removeCompletedRows();
                    }
                }
            }

            function updateRow(row, data) {
                if(!data.status) {
                    data.status = CHANGING;
                }
                if (data.status === CHANGING && data.upload) {
                    var progressTime;
                    
                    if (isIe8or9) {
                        progressTime = data.upload.getElapsedTime();
                    } else  {
                        var elapsed = (data.upload.getElapsedTime() / 1000) | 0;;
                        var remaining = (data.upload.getRemainingTime() / 1000) | 0;
                        // meter: current value, min value, max value
                        $('.hp-progress', row).hpUtilizationMeter(elapsed, 0, elapsed + remaining);
                        progressTime = data.upload.getRemainingTime();
                    }
                    $('.hp-details', row).removeAttr('date-timestamp');
                    // If the upload hasn't started yet, put a non-zero value so the progress bar is shown as starting
                    $('.hp-details', row).text((new Date(0)).toISOString() + '/' + 
                        (progressTime <= 0 ? (new Date(1)).toISOString() : (new Date(progressTime)).toISOString()));
                    $('.hp-details', row).hpTimestamp();
                    var timestamp = $('.hp-details', row).text();
                    $('.hp-message', row).text(localizer.getString(
                        'core.file.upload.flyout.' + (isIe8or9 ? 'elapsed' : 'remaining'), [timestamp]));
                } else {
                    $('.hp-status', row).hpStatus(data.status);
                    $('.hp-close', row).off('click').remove();
                    $('.hp-actions', row).off('click').remove();
                    $('.hp-details', row).remove();
                    $('.hp-contents', row).remove();
                    $('.hp-progress', row).remove();
                }

                if (data.start) {
                    $('.hp-full .hp-timestamp', row).show().
                        text(style.beautifyTimestamp(data.start));
                } else {
                    $('.hp-full .hp-timestamp', row).text('').hide();
                }
            }
            
            function initRow(row, data) {
                row.attr('id', data.id);
                if (data.file) {
                    $('.hp-upload-message', row).text(data.file);
                    $('.hp-full .hp-upload-message', row).text(data.file);
                } else {
                    data.file = '';
                }
                
                // Set initial icons to spinning
                $('.hp-status', row).hpStatus(CHANGING);

                if (!isIe8or9) {
                    $('.hp-progress', row).hpUtilizationMeter();
                } else {
                    $('.hp-progress', row).remove();
                }

                var onClickCancel = function (ev) {
                    ev.preventDefault();
                    var dialog = null;
                    var upload = UploadManager.getUpload(row.attr('id'));
                    var contents = $(cancel_confirm_content);
                    localizer.localizeDom(contents);
                    $(CANCEL_DIALOG_QUESTION, contents).
                        text(localizer.getString('core.file.upload.cancel.confirmQuestion', [data.file]));
                    dialog = new DialogView({
                        contents: contents,
                        ok : function(){
                            upload.cancel();
                        }
                    });
                };
                
                $('.hp-close', row).on('click', onClickCancel);
                $('.hp-actions', row).text(
                    localizer.getString('core.file.upload.cancel.confirmTitle')).on('click', onClickCancel);

                // Finally, update the remaing part of the row
                updateRow(row, data);
            }

            /**
             * Completely hide flyout.
             */
            function hideSidebar(remove) {
                if ($(FLYOUT).hasClass(ACTIVE)) {
                    deselectRow();
                    $(FLYOUT).off('click', '.hp-fileupload', onClickRow);
                    $(CONTENTS).off('scroll', deselectRow);
                    if (remove) {
                        sidebar.remove($(FLYOUT));
                    }
                    $(FLYOUT).removeClass(ACTIVE);
                    $(CONTROL).removeClass(SELECTED);
                    updateUploadProgressComponents();
                }
            }
            
            /**
             * Put the flyout into the sidebar.
             */
            function showSidebar() {
                if (! $(FLYOUT).hasClass(ACTIVE)) {
                    $(FLYOUT).addClass(ACTIVE);
                    $(CONTROL).addClass(SELECTED);
                    sidebar.add($(FLYOUT));
                    $(FLYOUT).on('click', '.hp-fileupload', onClickRow);
                    $(CONTENTS).on('scroll', deselectRow);
                    $(LIST + ' > li.' + NEW).removeClass(NEW);
                    updateUploadProgressComponents();
                }
            }
            
            function onSidebarRemove(element) {
                if (element.attr('id') === $(FLYOUT).attr('id')) {
                    hideSidebar();
                }
            }
            
            function onSidebarAdd(element) {
                if (element.attr('id') === $(FLYOUT).attr('id')) {
                    showSidebar();
                }
            }
            
            /**
             * If the start time is not yet available, return the current time.
             */
            function getAdjustedUploadStartTime(upload) {
                var time = upload.getStartTimeStr();
                return time && time !== 0 ? time + '' : (new Date()).toISOString();
            }
            
            function onComplete(upload, data) {
                
                // unregsiter the events        
                var id = upload.getId();
                var handlers = handlersList[id];
                var row = $('#' + id);
                Object.keys(handlers).forEach(function (key) {                     
                     upload.off(key, handlers[key]);                     
                });
                delete handlersList[id];
                if (row) {
                    data.start = getAdjustedUploadStartTime(upload);
                    updateRow(row, data);
                }
                updateUploadProgressComponents();
            } 

            function onProgressChange(upload) {
                //var upload = UploadManager.getUpload(uploadId);
                var row = $('#' + upload.getId());
                if (row) {
                    updateRow(row, {
                        status: CHANGING,
                        start: getAdjustedUploadStartTime(upload),
                        upload: upload
                    });
                }
                updateUploadProgressComponents();
            }

            function updateUploadTimer() {               
                var lis = $(FLYOUT + ' .hp-fileupload');
                lis.each(function (index, li) {
                    if ($('#' + li.id + ' .hp-status-changing').length > 0) {
                        onProgressChange(UploadManager.getUpload(li.id));
                        return false;
                    }
                });
            }

            /**
             * @private
             * Add a file upload message to the list.
             * @param {Object} data 
             */
            function addToList(data) {
                var row = template.hpSafeClone();
                row.addClass(ACTIVE);
                initRow(row, data);
                if (! $(FLYOUT).hasClass(ACTIVE)) {
                    row.addClass(NEW);
                }
                $(LIST).prepend(row);
                updateUploadProgressComponents();
                $(FLYOUT).addClass('hp-notable');
            }
            
            function getErrorHandler(upload) {
                return function (uploadInfo) {
                    var data = {
                        status: 'error'
                    };
                    onComplete(upload, data);                    
                };
            }
            
           function getSuccessHandler(upload) {
                return function (uploadInfo) {
                    var data = {
                        status: 'ok'
                    };
                    onComplete(upload, data);                    
                };
            }
             
            function getCancelHandler(upload) {
                return function (uploadInfo) {
                    var data = {
                        status: 'disabled'
                    };
                    onComplete(upload, data);                    
                };
            }  
            
            function getProgressChangeHandler(upload)  {
                return function (uploadInfo) {  
                    onProgressChange(upload);                    
                };               
            }    
            
            function onUploadAdd(upload) {
                
                var handlers = {
                    "error" : getErrorHandler(upload),
                    "cancel" : getCancelHandler(upload),
                    "success" : getSuccessHandler(upload),
                    "progressChange" : getProgressChangeHandler(upload)
                 } ;
                // register events
                Object.keys(handlers).forEach(function (key) {                     
                     upload.on(key, handlers[key]);                     
                });                
                handlersList[upload.getId()] = handlers;
                addToList({
                    id: upload.getId(),
                    file: upload.getFiles()[0].name,
                    start: getAdjustedUploadStartTime(upload),
                    upload: upload
                });
                updateUploadProgressComponents();
            };
            
            this.init = function(banner, placement) {
                template = $(TEMPLATE, banner);
                template.remove().attr('id', '').removeClass('hp-template');
                
                if (! placement || placement === 'sidebar') {
                    $(CONTROL, banner).attr('tooltip',
                        localizer.getString('core.file.upload.control.tooltip')).
                        hpTooltip();
                    $(CONTROL, banner).click(function (ev) {
                        if (!$(CONTROL).hasClass(SELECTED)) {
                            showSidebar();
                        } else {
                            hideSidebar(true);
                        }
                    });
                    sidebar.on('sidebarAdd', onSidebarAdd);
                    sidebar.on('sidebarRemove', onSidebarRemove);
                } else if (placement === 'inline') {
                    $(CONTROL, banner).parent().hide();
                }

                updateUploadProgressComponents();
                // IE 8/9 does not fire onProgressChanged event
                if (typeof FormData === 'undefined') {
                    isIe8or9 = true;
                    setInterval(updateUploadTimer, 1000);
                }
                UploadManager.on('uploadAdd', onUploadAdd);
            };
        }

        return new Uploads();
    }());

    return Uploads;
});
