/**
 *    Copyright (C) 2015 Deciso B.V.
 *
 *    All rights reserved.
 *
 *    Redistribution and use in source and binary forms, with or without
 *    modification, are permitted provided that the following conditions are met:
 *
 *    1. Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *
 *    2. Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 *    THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 *    INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 *    AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *    AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 *    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *    POSSIBILITY OF SUCH DAMAGE.
 *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *
 *    User interface shared components, requires opnsense.js for supporting functions.
 */

 /**
  * format bytes
  * @param bytes number of bytes to format
  * @param decimals decimal places
  * @return string
  */
 function byteFormat(bytes, decimals)
 {
     if (decimals == undefined) {
        decimals = 0;
     }
     var kb = 1024;
     var ndx = Math.floor( Math.log(bytes) / Math.log(kb) );
     var fileSizeTypes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
     return (bytes / Math.pow(kb, ndx)).toFixed(decimals) + ' ' + fileSizeTypes[ndx];
 }

/**
 * save form to server
 * @param url endpoint url
 * @param formid parent id to grep input data from
 * @param disable_dialog don't show input validation message box on failure
 */
function saveFormToEndpoint(url,formid,callback_ok, disable_dialog) {
    disable_dialog = disable_dialog || false;
    var data = getFormData(formid);
    ajaxCall(url=url,sendData=data,callback=function(data,status){
        if ( status == "success") {
            // update field validation
            handleFormValidation(formid,data['validations']);

            // if there are validation issues, update our screen and show a dialog.
            if (data['validations'] != undefined) {
                if (!disable_dialog) {
                    // validation message box is optional, form is already updated using handleFormValidation
                    BootstrapDialog.show({
                        type:BootstrapDialog.TYPE_WARNING,
                        title: 'Input validation',
                        message: 'Please correct validation errors in form',
                        buttons: [{
                            label: 'Dismiss',
                            action: function(dialogRef){
                                dialogRef.close();
                            }
                        }]

                    });
                }
            } else if ( callback_ok != undefined ) {
                // execute callback function
                callback_ok();
            }

        } else {
            // error handling, show internal errors
            // Normally the form should only return validation issues, if other things go wrong throw an error.
            BootstrapDialog.show({
                type: BootstrapDialog.TYPE_ERROR,
                title: 'save',
                message: 'Unable to save data, an internal error occurred.<br> ' +
                'Response from server was: <br> <small>'+JSON.stringify(data)+'</small>'
            });
        }

    });
}

/**
 * standard data mapper to map json request data to forms on this page
 * @param data_get_map named array containing form names and source url's to get data from {'frm_example':"/api/example/settings/get"};
 * @return promise object, resolves when all are loaded
 */
function mapDataToFormUI(data_get_map) {
    var dfObj = new $.Deferred();

    // calculate number of items for deferred object to resolve
    var data_map_seq = 1;
    var data_map_count = 0;
    $.each(data_get_map, function(){
        data_map_count += 1;
    });

    var collected_data = {};
    $.each(data_get_map, function(data_index, data_url) {
        ajaxGet(url=data_url,sendData={}, callback=function(data, status) {
            if (status == "success") {
                $("form").each(function( index ) {
                    if ( $(this).attr('id') && $(this).attr('id').split('-')[0] == data_index) {
                        // related form found, load data
                        setFormData($(this).attr('id'), data);
                        collected_data[$(this).attr('id')] = data;
                    }
                });
            }
            if (data_map_seq == data_map_count) {
                dfObj.resolve(collected_data);
            }
            data_map_seq += 1;
        });
    });

    return dfObj;
}

/**
 * update service status buttons in user interface
 */
function updateServiceStatusUI(status) {

    var status_html = '';

    if (status == "running") {
        status_html += '<span class="btn btn-success">' ;
    } else if (status == "stopped") {
        status_html += '<span class="btn btn-danger">' ;
    } else {
        status_html += '<span class="btn">' ;
    }

    status_html += '<span class="glyphicon glyphicon-play"  data-placement="bottom"></span> </span>&nbsp;';

    $('#service_status_container').html(status_html);
}

/**
 * reformat all tokenizers on this document
 */
function formatTokenizersUI(){
    // remove old tokenizers (if any)
    $('div[class="tokenize Tokenize"]').each(function(){
        $(this).remove();
    });
    $('select[class="tokenize"]').each(function(){
        if ($(this).prop("size")==0) {
            maxDropdownHeight=String(36*5)+"px"; // default number of items

        } else {
            number_of_items = $(this).prop("size");
            maxDropdownHeight=String(36*number_of_items)+"px";
        }
        hint=$(this).data("hint");
        width=$(this).data("width");
        allownew=$(this).data("allownew");
        nbDropdownElements=$(this).data("nbdropdownelements");
        maxTokenContainerHeight=$(this).data("maxheight");

        $(this).tokenize({
            displayDropdownOnFocus: true,
            newElements: allownew,
            nbDropdownElements: nbDropdownElements,
            placeholder:hint
        });
        $(this).parent().find('ul[class="TokensContainer"]').parent().css("width",width);
        $(this).parent().find('ul[class="Dropdown"]').css("max-height", maxDropdownHeight);
        if ( maxDropdownHeight != undefined ) {
            $(this).parent().find('ul[class="TokensContainer"]').css("max-height", maxTokenContainerHeight);
        }
    });
}

/**
 * clear multiselect boxes on click event, works on standard and tokenized versions
 */
function addMultiSelectClearUI() {
    $('[id*="clear-options"]').each(function() {
        $(this).click(function() {
            var id = $(this).attr("for");
            BootstrapDialog.confirm({
                title: 'Deselect or remove all items ?',
                message: 'Deselect or remove all items ?',
                type: BootstrapDialog.TYPE_DANGER,
                closable: true,
                draggable: true,
                btnCancelLabel: 'Cancel',
                btnOKLabel: 'Yes',
                btnOKClass: 'btn-primary',
                callback: function(result) {
                    if(result) {
                        if ($('select[id="' + id + '"]').hasClass("tokenize")) {
                            // trigger close on all Tokens
                            $('select[id="' + id + '"]').parent().find('ul[class="TokensContainer"]').find('li[class="Token"]').find('a').trigger("click");
                        } else {
                            // remove options from selection
                            $('select[id="' + id + '"]').find('option').prop('selected',false);
                        }
                    }
                    // In case this modal was triggered from another modal, fix focus issues
                    $('.modal').on("hidden.bs.modal", function (e) {
                        if($('.modal:visible').length)
                        {
                            $('body').addClass('modal-open');
                        }
                    });
                }
            });
        });
    });
}

/**
 * setup form help buttons
 */
function initFormHelpUI() {
    // handle help messages show/hide
    $("a[class='showhelp']").click(function (event) {
        $("*[for='" + $(this).attr('id') + "']").toggleClass("hidden show");
        event.preventDefault();
    });

    // handle all help messages show/hide
    $('[id*="show_all_help"]').click(function(event) {
        $('[id*="show_all_help"]').toggleClass("fa-toggle-on fa-toggle-off");
        $('[id*="show_all_help"]').toggleClass("text-success text-danger");
        if ($('[id*="show_all_help"]').hasClass("fa-toggle-on")) {
            $('[for*="help_for"]').addClass("show");
            $('[for*="help_for"]').removeClass("hidden");
        } else {
            $('[for*="help_for"]').addClass("hidden");
            $('[for*="help_for"]').removeClass("show");
        }
        event.preventDefault();
    });
}

/**
 * handle advanced show/hide
 */
function initFormAdvancedUI() {
    $('[data-advanced*="true"]').hide(function(){
        $('[data-advanced*="true"]').after("<tr data-advanced='hidden_row'></tr>"); // the table row is added to keep correct table striping
    });
    $('[id*="show_advanced"]').click(function() {
        $('[id*="show_advanced"]').toggleClass("fa-toggle-on fa-toggle-off");
        $('[id*="show_advanced"]').toggleClass("text-success text-danger");
        if ($('[id*="show_advanced"]').hasClass("fa-toggle-on")) {
            $('[data-advanced*="true"]').show();
            $('[data-advanced*="hidden_row"]').remove(); // the table row is deleted to keep correct table striping
        } else {
            $('[data-advanced*="true"]').after("<tr data-advanced='hidden_row'></tr>").hide(); // the table row is added to keep correct table striping
        }
    });
}

/**
 * standard remove items dialog, wrapper around BootstrapDialog
 */
function stdDialogRemoveItem(message, callback) {
    BootstrapDialog.confirm({
        title: 'Remove',
        message: message,
        type:BootstrapDialog.TYPE_DANGER,
        btnCancelLabel: 'Cancel',
        btnOKLabel: 'Yes',
        btnOKClass: 'btn-primary',
        callback: function(result) {
            if(result) {
                callback();
            }
        }
    });
}
