/*
Cette page traite l'inventaire d'un rayon ou d'une liste personnalisée de produits.
Un objet 'shelf' peut donc ici être un rayon, ou une liste personnalisée.

Sémantiquement, ici  :
  list_to_process représente la liste des produits à inventorier
  list_processed la liste des produit déjà inventoriés
*/

var validation_msg = $('#validation_msg'),
    inventory_validated_msg = $('#inventory_validated'),
    process_all_items_msg = $('#process_all_items_msg'),
    faq_content = $("#FAQ_modal_content"),
    issues_reporting = $("#issues_reporting"),
    add_product_form = $("#add_product_form"),
    add_product_input = $("#add_product_input");

var shelf,
    parent_location = '/shelfs',
    originView = "shelf", // or custom_list (create from order view)
    list_to_process = [],
    table_to_process,
    table_processed,
    editing_item = null, // Store the item currently being edited
    editing_origin, // Keep track of where editing_item comes from
    processed_row_counter = 0, // Keep count of the order the item were added in processed list
    search_chars = [],
    user_comments = '',
    adding_product = false; // True if modal to add a product is open


/* UTILS */

// polyfill to check for safe integers: Number method not supported by all browsers
Number.isInteger = Number.isInteger || function(value) {
    return typeof value === 'number' &&
    isFinite(value) &&
    Math.floor(value) === value;
};
if (!Number.MAX_SAFE_INTEGER) {
    Number.MAX_SAFE_INTEGER = 9007199254740991; // Math.pow(2, 53) - 1;
}
Number.isSafeInteger = Number.isSafeInteger || function (value) {
    return Number.isInteger(value) && Math.abs(value) <= Number.MAX_SAFE_INTEGER;
};

function back() {
    document.location.href = parent_location;
}

// Directly send a line to edition when barcode is read
function select_product_from_bc(barcode) {
    if (editing_item == null) {
        var found = null;

        $.each(list_to_process, function(i, e) {
            if (e.barcode == barcode) {
                found = e;
                editing_origin = 'to_process';
            }
        });

        if (typeof shelf != 'undefined' && typeof shelf.list_processed != 'undefined') {
            $.each(shelf.list_processed, function(i, e) {
                if (e.barcode == barcode) {
                    found = e;
                    editing_origin = 'processed';
                }
            });
        }

        if (found !== null) {
            setLineEdition(found);
            if (editing_origin === 'to_process') {
                let row = table_to_process.row($('tr#'+found.id));

                remove_from_toProcess(row);
            } else {
                let row = table_processed.row($('tr#'+found.id));

                remove_from_processed(row);
            }
        } else {
            console.log('Code barre introuvable');
        }
    }
}

/*
  To make an element blink:
  Call this function on an element so blinking is handled
  Then simply add 'blink_me' class on the element to make it blink
*/
function handle_blinking_effect(element) {
    element.addEventListener('animationend', onAnimationEnd);
    element.addEventListener('webkitAnimationEnd', onAnimationEnd);

    function onAnimationEnd(e) {
        element.classList.remove('blink_me');
    }
}


/* EDITION */

// When edition event is fired
function edit_event(clicked) {
    // Remove from origin table
    var row_data = null;

    if (editing_origin == 'to_process') {
        let row = table_to_process.row(clicked.parents('tr'));

        row_data = row.data();

        remove_from_toProcess(row);
    } else {
        let row = table_processed.row(clicked.parents('tr'));

        row_data = row.data();

        remove_from_processed(row);
    }

    // Product goes to editing
    setLineEdition(row_data);

    // Reset search
    $('#search_input').val('');
    $('table.dataTable').DataTable()
        .search('')
        .draw();
    search_chars = [];
}

// Set edition area
function setLineEdition(item) {
    var edition_input = $('#edition_input');

    editing_item = item;
    $('#product_name').text(editing_item.name);
    $('#product_uom').text(editing_item.uom_id[1]);

    if (editing_item.uom_id[0] == 1) { // Unit
        edition_input.attr('type', 'number').attr('step', 1)
            .attr('max', 9999);
    } else {
        edition_input.attr('type', 'number').attr('step', 0.001)
            .attr('max', 9999);
    }
    // If item is reprocessed, set input with value
    if (editing_origin == 'processed') {
        edition_input.val(editing_item.qty);
    }

    edition_input.focus();

    // Make edition area blink when edition button clicked
    container_edition.classList.add('blink_me');
}

// Clear edition
function clearLineEdition() {
    editing_item = null;

    $('#product_name').text('');
    $('#edition_input').val('');
    $('#search_input').focus();
}

// Validate product edition
function validateEdition(form) {
    if (editing_item != null) {
        if (editProductInfo(editing_item)) {
            clearLineEdition();
        }
    }
}

/*
 * Update a product info and add it to processed items.
 * If 'value' is set, use it as new value.
*/
function editProductInfo (productToEdit, value = null) {
    // If 'value' parameter not set, get value from edition input
    var newValue = (value == null) ? parseFloat($('#edition_input').val()
        .replace(',', '.')) : value;

    // If uom is unit, prevent float
    if (productToEdit.uom_id[0] == 1 && !Number.isSafeInteger(newValue)) {
        alert('Vous ne pouvez pas rentrer de chiffre à virgule pour des produits à l\'unité');

        return false;
    }

    productToEdit.qty = newValue;

    add_to_processed(productToEdit);

    // Update local storage
    localStorage.setItem(originView + "_" + shelf.id, JSON.stringify(shelf));

    return true;
}


/* LISTS HANDLING */

// Init Data & listeners
function initLists() {
    if ('list_processed' in shelf) {
    // Remove processed items from items to process
        for (processed_item of shelf.list_processed) {
            var index_in_toProcess = list_to_process.findIndex(x => x.id == processed_item.id);

            if (index_in_toProcess > -1) {
                list_to_process.splice(index_in_toProcess, 1);
            }
        }
    } else {
        shelf.list_processed = [];
    }

    // Init table for items to process
    var columns_to_process = [
        {data:"id", title: "id", visible: false},
        {data:"name", title:"Produit", width: "60%"},
        {data:"uom_id.1", title:"Unité de mesure", className:"dt-body-center"},
        {
            title:"Renseigner qté",
            defaultContent: "<a class='btn' id='process_item' href='#'><i class='far fa-edit'></i></a>", "className":"dt-body-center",
            orderable: false
        }
    ];

    if (originView == 'custom_list') {
        columns_to_process.splice(1, 0, {data:"shelf_sortorder", title:"Rayon", className:"dt-body-center"});
    }

    table_to_process = $('#table_to_process').DataTable({
        data: list_to_process,
        columns: columns_to_process,
        rowId : "id",
        order: [
            [
                0,
                "asc"
            ]
        ],
        scrollY: "28vh",
        scrollCollapse: true,
        paging: false,
        dom: 'lrtip', // Remove the search input from that table
        language: {url : '/static/js/datatables/french.json'}
    });


    // Init table for processed items
    var columns_processed = [
        {data:"row_counter", title:"row_counter", "visible": false},
        {data:"id", title: "id", visible: false},
        {data:"name", title:"Produit", width: "60%"},
        {data:"qty", title:"Qté", className:"dt-body-center"},
        {data:"uom_id.1", title:"Unité de mesure", className:"dt-body-center"},
        {
            title:"Modifier qté",
            defaultContent: "<a class='btn' id='reprocess_item' href='#'><i class='far fa-edit'></i></a>", "className":"dt-body-center",
            orderable: false
        }
    ];

    if (originView == 'custom_list') {
        columns_processed.splice(2, 0, {data:"shelf_sortorder", title:"Rayon", className:"dt-body-center"});
    }

    table_processed = $('#table_processed').DataTable({
        data: shelf.list_processed,
        columns: columns_processed,
        rowId : "id",
        order: [
            [
                0,
                "desc"
            ]
        ],
        scrollY: "28vh",
        scrollCollapse: true,
        paging: false,
        dom: 'lrtip', // Remove the search input from that table
        language: {url : '/static/js/datatables/french.json'}
    });


    /* Listeners on tables & search input */

    // Edit line from items to process
    $('#table_to_process tbody').on('click', 'a#process_item', function () {
    // Prevent editing mutiple lines at a time
        if (editing_item == null) {
            editing_origin = "to_process";
            edit_event($(this));
        }
    });

    // Edit line from items processed
    $('#table_processed tbody').on('click', 'a#reprocess_item', function () {
    // Prevent editing mutiple lines at a time
        if (editing_item == null) {
            editing_origin = "processed";
            edit_event($(this));
        }
    });

    // Search input for both tables
    $('#search_input').on('keyup', function () {
        $('table.dataTable')
            .DataTable()
            .search(jQuery.fn.DataTable.ext.type.search.string(this.value)) // search without accents (see DataTable plugin)
            .draw();
    });

    // Cancel line editing
    $('#edition_cancel').on('click', function () {
        if (editing_item != null) {
            if (editing_origin == "to_process") {
                add_to_toProcess(editing_item);
            } else if (editing_origin == "processed") {
                add_to_processed(editing_item, false);
            }

            clearLineEdition();
        }
    });
}

// Add a line to the 'items to process' list
function add_to_toProcess(product) {
    // Add to list
    list_to_process.push(product);

    // Add to table (no data binding...)
    var rowNode = table_to_process.row.add(product).draw(false)
        .node();

    // Blinking effect on newly added row
    handle_blinking_effect(rowNode);
    $(rowNode).addClass('blink_me');
}

// Remove a line from the 'items to process' list
function remove_from_toProcess(row) {
    item = row.data();

    // Remove from list
    var index = list_to_process.indexOf(item);

    if (index > -1) {
        list_to_process.splice(index, 1);
    }

    // Remove from table
    row.remove().draw();
}

// Add a line to the 'items processed' list
function add_to_processed(product, withCounter = true) {
    // Add to list
    shelf.list_processed.push(product);

    // Add a counter to display first the last row added
    if (withCounter) {
        product.row_counter = processed_row_counter;
        processed_row_counter++;
    }

    // Add to table (no data binding...)
    var rowNode = table_processed.row.add(product).draw(false)
        .node();

    // Handle blinking efect for newly added row
    handle_blinking_effect(rowNode);
    $(rowNode).addClass('blink_me');
}

// Remove a line from 'items processed'
function remove_from_processed(row) {
    let item = row.data();

    // Remove from list
    let index = shelf.list_processed.indexOf(item);

    if (index > -1) {
        shelf.list_processed.splice(index, 1);
    }

    //Remove from table
    row.remove().draw();
}


/* ACTIONS */

// Set the quantity to 0 for all the remaining unprocessed items
function confirmProcessAllItems() {
    openModal();

    // Iterate over all rows in table of items to process
    table_to_process.rows().every(function (rowIdx, tableLoop, rowLoop) {
        var data = this.data();

        editProductInfo(data, 0);
    });

    // Reset data
    list_to_process = [];
    table_to_process.rows().remove()
        .draw();

    closeModal();
}

// Verifications before processing
function pre_send() {
    if (list_to_process.length > 0 || editing_item != null) {
        alert('Il reste des produits à compter. Si ces produits sont introuvables, cliquez sur "Il n\'y a plus de produits à compter".');
    } else {
        if (shelf.inventory_status != '')
            validation_msg.find('.validation_msg_step2').show();

        openModal(validation_msg.html(), send, 'Confirmer', false);
    }
}

// Proceed with inventory: send the request to the server
function send() {
    if (is_time_to('submit_inv_qties')) {
        // Loading on
        var wz = $('#main-waiting-zone').clone();

        wz.find('.msg').text("Patience, cela peut prendre de nombreuses minutes s'il y a une centaine de produits");
        openModal(wz.html());

        // Add user comments to data sent to server
        shelf.user_comments = user_comments;

        var url = "../do_" + originView + "_inventory";
        var call_begin_at = new Date().getTime();

        $.ajaxSetup({ headers: { "X-CSRFToken": getCookie('csrftoken') } });
        $.ajax({
            type: "PUT",
            url: url,
            dataType: "json",
            traditional: true,
            contentType: "application/json; charset=utf-8",
            data: JSON.stringify(shelf),
            success: function(data) {
                // If step 1, display additionnal message in validation popup
                if (shelf.inventory_status == '') {
                    inventory_validated_msg.find('#step1_validated').show();
                }

                if (typeof data.res.inventory != 'undefined') {
                    if (typeof data.res.inventory.missed != 'undefined' && data.res.inventory.missed.length > 0) {
                        $('#products_missed_container').show();
                        for (p of data.res.inventory.missed) {
                            $('ul#products_missed_list').append('<li>'+ p.product.name +'</li>');
                        }
                    }
                }

                var msg = (originView == 'shelf') ? 'Retour à la liste des rayons' : 'Retour';

                openModal(inventory_validated_msg.html(), back, msg, true, false);

                // Go back to list if modal closed
                $('#modal_closebtn_top').on('click', back);
                $('#modal_closebtn_bottom').on('click', back);

                // Clear local storage before leaving
                localStorage.removeItem(originView + '_' + shelf.id);
            },
            error: function(jqXHR, textStatus) { // 500 error has been thrown or web server sent a timeout
                if (jqXHR.status == 504) {
                    /*
                        django is too long to respond.
                        Let it the same time laps before asking if the process is well done
                    */
                    var now = new Date().getTime();

                    setTimeout(
                        function() {
                            $.ajax({
                                type: 'GET',
                                url: '../inventory_process_state/' + shelf.id,
                                success: function(rData) {
                                    if ('res' in rData && 'state' in rData.res) {
                                        // Verification for step 2 only ; step 1 is always fast
                                        if (shelf.inventory_status == 'step1_done' && rData.res.state != 'step1_done') {
                                            // shelf inventory has been already done
                                            localStorage.removeItem(originView + '_' + shelf.id);
                                            closeModal();
                                            back();
                                        } else {
                                            console.log('Still in process : need to call recursively to make other calls');
                                        }
                                    } else {
                                        console.log(rData);
                                    }
                                }
                            });
                        }
                        , now - call_begin_at
                    );

                } else if (jqXHR.status == 500) {
                    var message = "Erreur lors de la sauvegarde des données. " +
                                  "Pas de panique, les données de l'inventaire n'ont pas été perdues ! " +
                                  "Merci de contacter un salarié et de réessayer plus tard.";

                    if (typeof jqXHR.responseJSON != 'undefined' && typeof jqXHR.responseJSON.error != 'undefined') {
                        //console.log(jqXHR.responseJSON.error);

                        if ('busy' in jqXHR.responseJSON) {
                            message = "Inventaire en cours de traitement.";
                        } else if (jqXHR.responseJSON.error == 'FileExistsError') {
                            //step1 file has been found => previous request succeeded
                            message = "Les données avaient déjà été transmises....";
                            // Clear local storage before leaving
                            localStorage.removeItem(originView + '_' + shelf.id);
                        }
                    }
                    closeModal();
                    alert(message);
                    back();
                }
            }
        });
    } else {
        alert('Clic reçu il y a moins de 5 secondes. La demande est en cours de traitement.');
    }

}

function exit_adding_product() {
    $('input.add_product_input').val('');
    adding_product = false;
}

// Add a product that's not in the list
function open_adding_product() {
    if (originView == 'shelf') {
        adding_product = true;

        openModal(add_product_form.html(), do_add_product, 'Valider', false, true, exit_adding_product);
        $('input.add_product_input').focus();
    }
}

function do_add_product() {
    prod_data = {
        barcode: $('input.add_product_input').val()
    };

    openModal();
    $.ajaxSetup({ headers: { "X-CSRFToken": getCookie('csrftoken') } });
    $.ajax({
        type: "POST",
        url: "../"+shelf.id+"/add_product",
        dataType: "json",
        traditional: true,
        contentType: "application/json; charset=utf-8",
        data: JSON.stringify(prod_data),
        success: function(data) {
            exit_adding_product();
            closeModal();
            alert('Produit ajouté !');
            location.reload();
        },
        error: function(data) {
            if (typeof data.responseJSON != 'undefined') {
                console.log(data.responseJSON);
            }

            exit_adding_product();
            closeModal();

            msg = "";
            if (typeof data.responseJSON.res != 'undefined' && typeof data.responseJSON.res.msg != 'undefined') {
                msg = " (" + data.responseJSON.res.msg + ")";
            }
            alert("Impossible d'ajouter le produit au rayon." + msg);
        }
    });
}


function openFAQ() {
    openModal(faq_content.html(), function() {}, 'Compris !', true, false);
}

function openIssuesReport() {
    openModal(issues_reporting.html(), saveIssuesReport, 'Confirmer');

    var textarea = $("#issues_report");

    textarea.val(user_comments);
    textarea.focus();
}

function saveIssuesReport() {
    user_comments = $('#issues_report').val();
    $('#search_input').focus();
}


/* INIT */

// Get shelf data from server if not in local storage
function get_shelf_data() {
    $.ajaxSetup({ headers: { "X-CSRFToken": getCookie('csrftoken') } });

    var url = (originView == 'shelf') ? '../' + shelf.id : '../get_custom_list_data?id=' + shelf.id;

    $.ajax({
        type: 'GET',
        url: url,
        dataType:"json",
        traditional: true,
        contentType: "application/json; charset=utf-8",
        success: function(data) {
            shelf = data.res;
            init();
        },
        error: function(data) {
            if (typeof data.responseJSON != 'undefined' && typeof data.responseJSON.error != 'undefined') {
                console.log(data.responseJSON.error);
            }
            alert('Les données n\'ont pas pu être récupérées, réessayez plus tard.');
        }
    });
}

// Init page : to be launched when shelf data is here
function init() {
    // Products passed at page loading
    // TODO: get products by ajax for better ui experience (? -> warning js at loading)
    // TODO : What happens if products are being put or removed from the self before the end of the inventory ?
    //console.log(shelf)
    list_to_process = products;
    initLists();

    // Set DOM
    if (originView == "shelf") {
        $('#shelf_name').text(shelf.name + ' (numéro ' + shelf.sort_order + ')');
    } else {
        $('#page_title').text("Inventaire du");
        $('#shelf_name').text(shelf.datetime_created);

        $("#add_product_to_shelf").hide();
    }

    if (shelf.inventory_status == "") { // Step 1
    // Header
        $('#header_step_one').addClass('step_one_active');

        // Container items to process
        $('#container_left').css('border', '3px solid #212529');

        // Container processed items
        $('#container_right').css('border', '3px solid #0275D8');

        // Edition
        $('#edition_header').text('Quantité en rayon');

        // Validation button
        // $('#validation_button').html("<button class='btn--primary full_width_button' id='validate_inventory'>J'ai fini de compter</button>")
        $('#validate_inventory').addClass('btn--primary');
        $('#add_product_to_shelf').addClass('btn--inverse');
    } else { // Step 2
        $('#header_step_two').addClass('step_two_active');

        var check_icon = document.createElement('i');

        check_icon.className = 'far fa-check-circle';
        $('#header_step_one_content').append(check_icon);

        // Containers
        $('#container_left').css('border', '3px solid #0275D8');
        $('#container_right').css('border', '3px solid #5CB85C');

        // Edition
        $('#edition_header').text('Quantité en réserve');

        // Validation button
        $('#validate_inventory').addClass('btn--success');
        $('#add_product_to_shelf').addClass('btn--primary');
    }


    // Buttons Listeners
    $(document).on('click', 'button#validate_inventory', pre_send);
    $(document).on('click', 'button#add_product_to_shelf', open_adding_product);
    $(document).on('click', 'button#open_issues_report', openIssuesReport);
    $(document).on('click', 'button#open_faq', openFAQ);
    $(document).on('click', 'button#process_all_items', function (e) {
        openModal(process_all_items_msg.html(), confirmProcessAllItems, 'Confirmer', false);
    });

    // Action at modal closing
    $(document).on('click', 'a#modal_closebtn_top', exit_adding_product);


    // Load FAQ modal content
    faq_content.load("/shelfs/shelf_inventory_FAQ");

    // Handle blinking effect on edition area
    var container_edition = document.querySelector('#container_edition');

    handle_blinking_effect(container_edition);

    // Disable mousewheel on an input number field when in focus
    $('#edition_input').on('focus', function (e) {
        $(this).on('wheel.disableScroll', function (e) {
            e.preventDefault();
            /*
        Option to possibly enable page scrolling when mouse over the input, but :
          - deltaY is not in pixels in Firefox
          - movement not fluid on other browsers

      var scrollTo = (e.originalEvent.deltaY) + $(document.documentElement).scrollTop();
      $(document.documentElement).scrollTop(scrollTo);
      */
        });
    })
        .on('blur', function (e) {
            $(this).off('wheel.disableScroll');
        });

    // client-side validation of numeric inputs, optionally replacing separator sign(s).
    $("input.number").on("keydown", function (e) {
        // allow function keys and decimal separators
        if (
        // backspace, delete, tab, escape, enter, comma and .
            $.inArray(e.keyCode, [
                46,
                8,
                9,
                27,
                13,
                110,
                188,
                190
            ]) !== -1 ||
          // Ctrl/cmd+A, Ctrl/cmd+C, Ctrl/cmd+X
          ($.inArray(e.keyCode, [
              65,
              67,
              88
          ]) !== -1 && (e.ctrlKey === true || e.metaKey === true)) ||
          // home, end, left, right
          (e.keyCode >= 35 && e.keyCode <= 39)) {

            /*
          // optional: replace commas with dots in real-time (for en-US locals)
          if (e.keyCode === 188) {
              e.preventDefault();
              $(this).val($(this).val() + ".");
          }

          // optional: replace decimal points (num pad) and dots with commas in real-time (for EU locals)
          if (e.keyCode === 110 || e.keyCode === 190) {
              e.preventDefault();
              $(this).val($(this).val() + ",");
          }
          */

            return;
        }
        // block any non-number
        if ((e.shiftKey || (e.keyCode < 48 || e.keyCode > 57)) && (e.keyCode < 96 || e.keyCode > 105)) {
            e.preventDefault();
        }
    });

    // Barcode reader: listen for 13 digits read in a very short time
    $('#search_input').keypress(function(e) {
        if (e.which >= 48 && e.which <= 57) {
            search_chars.push(String.fromCharCode(e.which));
        }
        if (search_chars.length >= 13) {
            var barcode = search_chars.join("");

            if (!isNaN(barcode)) {
                search_chars = [];
                setTimeout(function() {
                    document.getElementById('search_input').value = '';
                    $('table.dataTable').DataTable()
                        .search('')
                        .draw();

                    // If modal to add a product is open
                    if (adding_product) {
                        $('input.add_product_input').val(barcode);
                        do_add_product();
                    } else {
                        select_product_from_bc(barcode);
                    }
                }, 300);
            }
        }
    });
}


$(document).ready(function() {
    // Get Route parameter
    var pathArray = window.location.pathname.split('/');

    shelf = {id: pathArray[pathArray.length-1]};

    // Working on a shelf
    if (pathArray.includes('shelf_inventory')) {
        originView = 'shelf';
        parent_location = '/shelfs';
    } else {
        originView = 'custom_list';
        parent_location = '/inventory/custom_lists';
    }

    // Get shelf data from local storage
    if (Modernizr.localstorage) {
        var stored_shelf = JSON.parse(localStorage.getItem(originView + '_' + shelf.id));

        if (stored_shelf != null) {
            shelf = stored_shelf;
            init();
        } else {
            // Get shelf info if not coming from shelves list
            get_shelf_data();
        }
    } else {
        get_shelf_data();
    }

});
