// Server API URLs
var serverInfo, serverNewBooking, serverResourceAvailability, serverValidateBooking, serverPackBooking, serverPayment, serverCheckout;
// AJAX requests
var ajjson=null, ajServerInfo=null;
// configuration variables from json
var urljson=null;
var config = {};    // data from json
var info = {};      // data from serverInfo
var eventid;     // string with id field from JSON
// booking variables
var bookingtoken;
var bookingnumber;
// pack variables
var pack;
var packtoken;
//var packBookings = new Array();
var packTotalAmount, packDepositAmount, packPaidAmount;
// calculator variables
var amounts = new Array();
var biggestAmount, smallestAmount, price, discount, deposit, totalAmount, depositAmount;
var prices = new Array();
var discounts = new Array();
var deposits = new Array();
// form variables
var pages;
var inputFields;
var availableFields; // output from server
var unavailableFields; // fields sold out
var formBooking;
var formConfirmation;
var formPack;
var formPackPayment;
// document language
var lang = document.documentElement.lang;
var searchParams;
// TEST mode
var test = false;

window.addEventListener('bodyContentLoaded', function() {
  //console.log('Dynamic body content is now fully injected.');
  
    searchParams = new URLSearchParams(window.location.search);
    // check if called from management
    if( searchParams.has("title")===true && searchParams.has("config")===true ) {
        eventtitle = searchParams.get("title");
        document.querySelector('meta[name="title"]').setAttribute('content', eventtitle);
        urljson = searchParams.get("config");
//console.log(urljson);
        document.querySelector('meta[name="config"]').setAttribute('content', urljson);
    }

    const img = document.getElementById('templo');
    if (img) {
        //console.log('Old src:', img.src);
        img.src = 'img/templosintra.png?' + Date.now();
        //console.log('New src:', img.src);
    } else {
        console.error('Image not found.');
    }

  // Your script logic that depends on the body:
  initializeDynamicFeatures();
});

function initializeDynamicFeatures() {
    // set current year
    document.getElementById("yearCurrent").innerHTML = new Date().getFullYear();
    // read meta and update form
    collection = document.getElementsByName("title");
    for (let i = 0; i < collection.length; i++) {
        collection[i].innerHTML = document.querySelector('meta[name="title"]').content.trim();
    }
    collection = document.getElementsByName("author");
    for (let i = 0; i < collection.length; i++) {
        collection[i].innerHTML = document.querySelector('meta[name="author"]').content.trim();
    }

    //
    // get URL parameters
    //
    const searchParams = new URLSearchParams(window.location.search);
    // check if there's a token in the URL (packtoken)
    if( searchParams.has("token")===true ) {
        packtoken = searchParams.get("token");
    }
    // check if it's a booking change
    if( searchParams.has("booking")===true ) {
        bookingnumber = searchParams.get("booking");
    }
    // check if TEST mode is enabled
    if( searchParams.has("test")===true ) {
        test = true;
    }

    //
    // Chained actions to prepare form
    //

    loadJSON()
    .then((data) => {
        //console.log(data)
        loadServerInfo()
            .then((data) => {
                //console.log(data)
                prepareForm();
            })
            .catch((error) => {
                console.log(error)
            })
    })
    .catch((error) => {
        console.log(error)
    })

    formBooking         = document.getElementById('formBooking');
    formConfirmation    = document.getElementById('formConfirmation');
    formPack            = document.getElementById('formPack');
    formPackPayment     = document.getElementById('formPackPayment');

    //
    // Form validation
    //

    formBooking.addEventListener('submit', function (event) {
        if (!formBooking.checkValidity()) {
            event.preventDefault()
            event.stopPropagation()
        } else {
            event.preventDefault();
            event.stopPropagation()
            // get input fields
            inputFields = convertFormToJSON(formBooking);
            // update confirmation modal
            $.each( inputFields, function( key, val ) {
                if( $( '#' + key + '_value' ).length ) {
                    $( '#formConfirmation' ).find( '[id="' + key + '_value"]' ).html(val);
                } else {
                    $( '#' + key ).children().each(function() {
                        if( $(this).attr('id') == key+'.'+val+'_option' ) {
                            $(this).removeClass("d-none");
                        }
                    });
                }
            });

            // show confirmation modal
            $('#modalConfirmation').modal('show');
        }
        formBooking.classList.add('was-validated')
    }, false)

    formConfirmation.addEventListener('submit', function (event) {
        /*
        if (!formBooking.checkValidity()) {
            event.preventDefault()
            event.stopPropagation()
        } else {
        */
            event.preventDefault();
            event.stopPropagation()
            // get input fields
            inputFields = convertFormToJSON(formBooking);
            if( searchParams.has("booking")===true ) {
                // change booking
                changeBooking();
            } else {
                // create new booking, validate it and add it to the pack
                newEventCandidateBooking()
                    .then((data) => {
                        //if( data.token===undefined ) return;
                        validateBooking()
                            .then((data) => {
                                /*
                                // Show/Hide forms
                                $('#formBooking').addClass("d-none");
                                $('#formPack').removeClass("d-none");
                                $('#formPayment').removeClass("d-none");
                                */
                                if( packtoken!==undefined && packtoken!='' ) {
                                    preparePack();
                                }
                            })
                            .catch((error) => {
                                console.log(error)
                            })
                    })
                .catch((error) => {
                console.log(error)
                })
            }
            /*
        }
        formBooking.classList.add('was-validated')
        */
    }, false)

    formPack.addEventListener('submit', function (event) {
        if (!formPack.checkValidity()) {
            event.preventDefault()
            event.stopPropagation()
        } else {
            event.preventDefault();
            event.stopPropagation()
            // Reset formBooking without validation
            resetFormWithoutValidation(formBooking);
            // Show/Hide forms
            $('#formBooking').removeClass("d-none");   
            $('#formPack').addClass("d-none");
            $('#formPackPayment').addClass("d-none");
            $('html, body').animate({scrollTop:0}, 'slow');
        }
        formPack.classList.add('was-validated')
    }, false)

    formPackPayment.addEventListener('submit', function (event) {
        if (!formPackPayment.checkValidity()) {
            event.preventDefault()
            event.stopPropagation()
        } else {
            event.preventDefault();
            event.stopPropagation()
            // Reset formBooking without validation
            resetFormWithoutValidation(formBooking);
            // request payment
            requestPayment();
        }
        formPackPayment.classList.add('was-validated')
    }, false)

}

//
// Change booking
//
function changeBooking() {
    // add event ID to form data
    inputFields.event = eventid;
    // add booking number to form data
    inputFields.booking = bookingnumber;
    // add language used in the form
    inputFields.lang = lang;
    if( test===true ) inputFields.test = test;
    $.ajax({
        type: "POST",
        url: serverChangeBooking,
        dataType: 'json',
        data: JSON.stringify( inputFields ),
        success: function(result){
            $('#formConfirmationButtons').addClass('d-none');
            $('#formConfirmationSuccess').removeClass('d-none');
            if (result.error) {
                // Server internal error
                $('#modalValidationSavedBookingError').removeClass("d-none");
                return;
            }
        },
        error: function (jqXHR, exception) {
            var msg = '';
            if (jqXHR.status === 0) {
                msg = 'Not connect.\n Verify Network.';
            } else if (jqXHR.status === 400) {
                msg = 'Valor do ano é inválido!';
            } else if (jqXHR.status === 403) {
                msg = 'Não foi possível criar o diretório!';
            } else if (jqXHR.status == 404) {
                msg = 'Requested page not found. [404]';
            } else if (jqXHR.status === 409) {
                msg = 'O diretório já existe!';
            } else if (jqXHR.status == 500) {
                msg = 'Internal Server Error [500].';
            } else {
                msg = 'Uncaught Error.\n' + jqXHR.responseText;
            }
        }
    });     
}


//
// Load respective configuration json
//

function loadJSON() {
    return new Promise((resolve, reject) => {
        if( urljson==null )
            jsonfile = "config.json";
        else
            jsonfile = urljson;
        $.ajax({
            cache: false,
            url: jsonfile,       //(getFileName().substring(0, getFileName().lastIndexOf('.')) + ".json"),
            cache: false,
            dataType: "json",
            success: function(data) {
//console.log(urljson + " loaded!");
                // set PHP servers that will receive/validate the booking
                let url_dream = window.location.protocol + "//"
                                + window.location.hostname
                                + window.location.pathname.substring(0, window.location.pathname.lastIndexOf("manage/" + data.path.booking + "/"));
//console.log(url_dream);
//console.log(data.path.controller.info);
                serverInfo                  = url_dream + data.path.controller.info.replace("server/event/", "server/manage/");
                serverNewBooking            = url_dream + data.path.controller.new.replace("server/event/", "server/manage/");
                serverChangeBooking         = url_dream + data.path.controller.change.replace("server/event/", "server/manage/");
                serverResourceAvailability  = url_dream + data.path.controller.available.replace("server/event/", "server/manage/");
                serverValidateBooking       = url_dream + data.path.controller.validate.replace("server/event/", "server/manage/");
                serverPackBooking           = url_dream + data.path.controller.pack.replace("server/event/", "server/manage/");
                serverPayment               = url_dream + data.path.controller.payment.replace("server/event/", "server/manage/");
                serverCheckout              = url_dream + data.path.controller.checkout.replace("server/event/", "server/manage/");
                // get event id
                eventid = data.id; //data.id.substring(data.id.indexOf('/') + 1);
                // get all configuration data
                config = data;
                resolve(data);
            },
            error: function (jqXHR, exception) {
                var msg = '';
                if (jqXHR.status === 0) {
                    msg = 'Not connect.\n Verify Network.';
                } else if (jqXHR.status === 400) {
                    msg = 'Valor do ano é inválido!';
                } else if (jqXHR.status === 403) {
                    msg = 'Não foi possível criar o diretório!';
                } else if (jqXHR.status == 404) {
                    msg = 'Requested page not found. [404]';
                } else if (jqXHR.status === 409) {
                    msg = 'O diretório já existe!';
                } else if (jqXHR.status == 500) {
                    msg = 'Internal Server Error [500].';
                } else {
                    msg = 'Uncaught Error.\n' + jqXHR.responseText;
                }
                reject(jqXHR);
            }
        });
    });
}

//
// Load further fields from server
//

function loadServerInfo() {
    return new Promise((resolve, reject) => {
        inputfields = {};
        inputfields.event = eventid;
        if( test===true ) inputfields.test = test;
        $.ajax({
            type: "POST",
            url: serverInfo,
            crossDomain: true,
            dataType: 'json',
            //data: '{"event":"' + eventid + '"}',
            data: JSON.stringify( inputfields ),
            success: function(data) {
                // check if event is open
                if ( data.error!==undefined ) {
                    // bookings closed
                    $('#modal' + data.error).modal('show');
                    return;
                }
                // get calculator
                if( data.calculator===undefined )
                    return;
                // get all info data (calculator, packs, etc)
                info = data;
                resolve(data);
            },
            error: function (jqXHR, exception) {
                var msg = '';
                if (jqXHR.status === 0) {
                    msg = 'Not connect.\n Verify Network.';
                } else if (jqXHR.status === 400) {
                    msg = 'Valor do ano é inválido!';
                } else if (jqXHR.status === 403) {
                    msg = 'Não foi possível criar o diretório!';
                } else if (jqXHR.status == 404) {
                    msg = 'Requested page not found. [404]';
                } else if (jqXHR.status === 409) {
                    msg = 'O diretório já existe!';
                } else if (jqXHR.status == 500) {
                    msg = 'Internal Server Error [500].';
                } else {
                    msg = 'Uncaught Error.\n' + jqXHR.responseText;
                }
                reject(jqXHR);
            }
        });
    });
}

//
// Prepare form
//

function prepareForm() {
      // setup form
    if( config.setup!==undefined )
        setupForm( config.setup );
    // set click handlers
    $.each( config.events.input, function( key, val ) {
        $( "input[name='" + key + "']" ).on( 'click', val, inputClickHandler );
    });
    // check if form is paginated
    if( info.booking.create[0].pages===undefined || info.booking.create[0].pages===false )
        pages = false;
    else
        pages = info.booking.create[0].pages;
    if( pages!==false ) {
        $("button[name='bNext']").click(function(event) {
            var tabindex = $('.nav-tabs .active').closest('li').index();
            var allvalid = true;
            var type;
            $.each( pages[tabindex], function( key, val) {
                type = $("input[name='" + val + "']").attr("type");
                if( type=="radio" && !$("input[name='" + val + "']:checked").val() ) {
                    allvalid = false;
                    $("input[name='" + val + "']").addClass("is-invalid");
                } else if( type=="text" && !$("input[name='" + val + "']").val() ) {
                    allvalid = false;
                    $("input[name='" + val + "']").addClass("is-invalid");
                }
            });
            if( allvalid===false ) {
                return;
            }
            const nextTabLinkEl = $('.nav-tabs .active').closest('li').next('li').find('button')[0];
            if( nextTabLinkEl!==undefined ) {
                const nextTab = new bootstrap.Tab(nextTabLinkEl);
                nextTab.show();
                $( "button[name='bPrevious']" ).removeClass("d-none");
                const nextnextTabLinkEl = $('.nav-tabs .active').closest('li').next('li').find('button')[0];
                if( nextnextTabLinkEl===undefined ) {
                    $( "button[name='bNext']" ).addClass("d-none");
                    $( "button[name='bSubmit']" ).removeClass("d-none");
                }
            }
        });
        $("button[name='bPrevious']").click(function(event) {
            const prevTabLinkEl = $('.nav-tabs .active').closest('li').prev('li').find('button')[0];
            if( prevTabLinkEl!==undefined ) {
                const prevTab = new bootstrap.Tab(prevTabLinkEl);
                prevTab.show();
                $( "button[name='bNext']" ).removeClass("d-none");
                $( "button[name='bSubmit']" ).addClass("d-none");
                const prevprevTabLinkEl = $('.nav-tabs .active').closest('li').prev('li').find('button')[0];
                if( prevprevTabLinkEl===undefined ) {
                    $( "button[name='bPrevious']" ).addClass("d-none");
                }
            }
        });
    } else
        $( "button[name='bSubmit']" ).removeClass("d-none");
    // set recalculate amounts event handler
    $.each( info.calculator, function( key, val ) {
        $.each( val, function( key2, val2 ) {
            $( "input[name='" + key2 + "']" ).on( 'click', val2, calculateAmounts );
        });  
    });
    // get pack token from URL (null if not present)
    if( packtoken!=null ) {
        preparePack();
        $('#formBooking').addClass("d-none");
        $('#formPack').removeClass("d-none");
        //$('#formPayment').removeClass("d-none");
        $('html, body').animate({scrollTop:0}, 'slow');
    }
    // check if there's a pack configuration
    if( info.pack===undefined ) {
        // disable button to submit a new booking
        $( "#formPackButtonNewBooking" ).addClass("d-none");
    } else
        $( "#formPackButtonNewBooking" ).removeClass("d-none");

    /*
    // SE test
    if(typeof(EventSource) !== "undefined") {
        var source = new EventSource("server/sse.php");
        source.onmessage = function(event) {
            document.getElementById("info").innerHTML += event.data + "<br>";
        };
        } else {
        document.getElementById("info").innerHTML = "Sorry, your browser does not support server-sent events...";
        }
    */
}

//
// New booking
//
function newEventCandidateBooking() {
    // add event ID to form data
    inputFields.event = eventid;
    // add language used in the form
    inputFields.lang = lang;
    // add token if it exists
    if( bookingtoken!==undefined ) inputFields.token = bookingtoken;
    if( test===true ) inputFields.test = test;
    return new Promise((resolve, reject) => {
        $.ajax({
            type: "POST",
            url: serverNewBooking,
            dataType: 'json',
            data: JSON.stringify( inputFields ),
            success: function(result){
                $('#modalConfirmation').modal('hide');
                if (result.error) {
                    // Server internal error
                    $('#modalValidationSavedBookingError').removeClass("d-none");
                    return;
                }
                if( result.token===undefined ) return;
                // store result data
                bookingtoken = result.token;
                resolve(result);
            },
            error: function (jqXHR, exception) {
                var msg = '';
                if (jqXHR.status === 0) {
                    msg = 'Not connect.\n Verify Network.';
                } else if (jqXHR.status === 400) {
                    msg = 'Valor do ano é inválido!';
                } else if (jqXHR.status === 403) {
                    msg = 'Não foi possível criar o diretório!';
                } else if (jqXHR.status == 404) {
                    msg = 'Requested page not found. [404]';
                } else if (jqXHR.status === 409) {
                    msg = 'O diretório já existe!';
                } else if (jqXHR.status == 500) {
                    msg = 'Internal Server Error [500].';
                } else {
                    msg = 'Uncaught Error.\n' + jqXHR.responseText;
                }
                reject(jqXHR);
            }
        });     
    });
}

//
// Validate booking
//

function validateBooking() {
    var validationRequest = {};
    validationRequest.event = inputFields.event;
    validationRequest.token    = bookingtoken;
    validationRequest.packtoken= packtoken;
    // add language used in the form
    validationRequest.lang = lang;
    if( test===true ) validationRequest.test = test;
    return new Promise((resolve, reject) => {
        $.ajax({
            type: "POST",
            url: serverValidateBooking,
            dataType: 'json',
            data: JSON.stringify( validationRequest ),
            success: function(result){
                $('#modalValidationSavedBooking').addClass("d-none");
                if (result.number===undefined) {
                    // Not all selected options are available
                    $('#modalValidationSavedBookingReview').removeClass("d-none");
                    getResourceAvailability();
                    return;
                }
                // store result data
                bookingnumber = result.number;
                packtoken     = result.packtoken;
                // update interface
                $('#bookingNumber').html(result.number);
                $('#formBooking').addClass("d-none");
                $('#formPack').removeClass("d-none");
                //$('#formPayment').removeClass("d-none");
                $('html, body').animate({scrollTop:0}, 'slow');
                // Fill bookings table
                $('#tablePack tbody').append('<tr><td>' + result.number + '</td><td>' + inputFields.datetimeUTC + '</td></tr>');
                $('#tablePackPayment tbody').append('<tr><td>' + result.number + '</td><td>' + inputFields.datetimeUTC + '</td></tr>');
                // Select payment method
                var paymentAmount = $( "input[name='t_Payment']:checked" ).val();
                if( paymentAmount == "full") {
                    $( "input[name='paymentAmount']" ).val(totalAmount);
                } else if ( paymentAmount == "minimum") {
                    $( "input[name='paymentAmount']" ).val(depositAmount);
                } else if ( paymentAmount == "other") {
                    $( "input[name='paymentAmount']" ).val($( "input[name='t_PaymentAmount']" ).val());
                } else {
                    // error
                    // use full amount
                    $( "input[name='paymentAmount']" ).val(totalAmount);
                }
                resolve(result);
            },
            error: function (jqXHR, exception) {
                var msg = '';
                if (jqXHR.status === 0) {
                    msg = 'Not connect.\n Verify Network.';
                } else if (jqXHR.status === 400) {
                    msg = 'Valor do ano é inválido!';
                } else if (jqXHR.status === 403) {
                    msg = 'Não foi possível criar o diretório!';
                } else if (jqXHR.status == 404) {
                    msg = 'Requested page not found. [404]';
                } else if (jqXHR.status === 409) {
                    msg = 'O diretório já existe!';
                } else if (jqXHR.status == 500) {
                    msg = 'Internal Server Error [500].';
                } else {
                    msg = 'Uncaught Error.\n' + jqXHR.responseText;
                }
                reject(jqXHR);
            }
        });     
    });
}

function requestPayment() {
    var paymentRequest = {};
    paymentRequest.event = eventid;
    if( info.pack!==undefined )
        paymentRequest.packtoken = packtoken;
    else
        paymentRequest.bookingnumber = bookingnumber;
    paymentFields = convertFormToJSON(formPackPayment);
    /*
    // check which payment amount is selected in the form
    var paymentAmount = $( "input[name='t_Payment']:checked" ).val();
    paymentRequest.paymentAmount = paymentAmount;
    if( paymentAmount == "full") {
        paymentRequest.amount = packTotalAmount - packPaidAmount;
    } else if ( paymentAmount == "minimum") {
        paymentRequest.amount = packDepositAmount - packPaidAmount;
    } else if ( paymentAmount == "other") {
        paymentRequest.amount = parseFloat($( "input[name='t_PaymentAmount']" ).val()).toFixed(2);
    } else {
        // error
        return;
    }
        */
    paymentRequest.paymentFields = paymentFields;
    paymentRequest.title = document.querySelector('meta[name="title"]').content.trim();
    paymentRequest.language = lang;
    if( test===true ) paymentRequest.test = test;
    $.ajax({
        type: "POST",
        url: serverPayment,
        dataType: 'json',
        data: JSON.stringify( paymentRequest ),
        success: function(manifest){
            $('#formPack').addClass("d-none");
            $('#formPackPayment').addClass("d-none");
            $('#formEasypay').removeClass("d-none");
            $('#easypay-checkout').html('');
            $('html, body').animate({scrollTop:0}, 'slow');
//console.log(manifest);
            // Reset formPayment without validation
            resetFormWithoutValidation(formPackPayment);
            let checkoutLang;
            if( config.language[lang]!==undefined && config.language[lang].easypayCheckout!==undefined )
                checkoutLang = config.language[lang].easypayCheckout;
            else
                checkoutLang = "pt_PT";
            // Check if TEST mode is enabled
            if( test===true )
                testing = true;
            else
                testing = false;

                
            //
            // TODO Production environment
            // Remove next line
            //
            testing = true;
            //

            easypayCheckout.startCheckout(result, {"testing": testing, "language": checkoutLang, "onSuccess": checkoutEasypay, "onClose": checkoutClose, "onError": checkoutError});
        },
        error: function (jqXHR, exception) {
            var msg = '';
            if (jqXHR.status === 0) {
                msg = 'Not connect.\n Verify Network.';
            } else if (jqXHR.status === 400) {
                msg = 'Valor do ano é inválido!';
            } else if (jqXHR.status === 403) {
                msg = 'Não foi possível criar o diretório!';
            } else if (jqXHR.status == 404) {
                msg = 'Requested page not found. [404]';
            } else if (jqXHR.status === 409) {
                msg = 'O diretório já existe!';
            } else if (jqXHR.status == 500) {
                msg = 'Internal Server Error [500].';
            } else {
                msg = 'Uncaught Error.\n' + jqXHR.responseText;
            }
        }
    });     
}

function checkoutEasypay(checkoutInfo) {
console.log(checkoutInfo);
//easypayCheckout.unmount()
    var checkoutRequest = {};
    checkoutRequest.event     = eventid;
    checkoutRequest.packtoken    = packtoken;
    checkoutRequest.provider     = "easypay";
    checkoutRequest.checkoutinfo = checkoutInfo;
    if( test===true ) checkoutRequest.test = test;
    $.ajax({
        type: "POST",
        url: serverCheckout,
        dataType: 'json',
        data: JSON.stringify( checkoutRequest ),
        success: function(result){
//console.log(result);
        },
        error: function (jqXHR, exception) {
            var msg = '';
            if (jqXHR.status === 0) {
                msg = 'Not connect.\n Verify Network.';
            } else if (jqXHR.status === 400) {
                msg = 'Valor do ano é inválido!';
            } else if (jqXHR.status === 403) {
                msg = 'Não foi possível criar o diretório!';
            } else if (jqXHR.status == 404) {
                msg = 'Requested page not found. [404]';
            } else if (jqXHR.status === 409) {
                msg = 'O diretório já existe!';
            } else if (jqXHR.status == 500) {
                msg = 'Internal Server Error [500].';
            } else {
                msg = 'Uncaught Error.\n' + jqXHR.responseText;
            }
        }
    });     
}

function checkoutClose() {
    $('#formPack').removeClass("d-none");
    $('#formPackPayment').removeClass("d-none");
    $('#formEasypay').addClass("d-none");
    $('#easypay-checkout').html('');
    $('html, body').animate({scrollTop:0}, 'slow');
}

function checkoutError(error) {
    //easypayCheckout.unmount();
    switch (error.code) {
        case 'checkout-expired':
            // In this case a new Checkout session must be created
            /*
            const manifest = await yourFunctionToGetTheManifest();
            checkoutInstance = startCheckout(manifest, {onError: myErrorHandler});
            */
            break;
        case 'already-paid':
            document.write('Your order was already paid. Thank you.');
            break;
        case 'checkout-canceled':
            document.write('Your checkout was canceled.');
            break;
        default:
            document.write('Unable to process payment, please try again.');
    }
}


//
// Prepare pack
//

function preparePack() {
    // prepare pack
    inputfields = {};
    inputfields.event = eventid;
    inputfields.packtoken = packtoken;
    if( test===true ) inputfields.test = test;
    $.ajax({
        type: "POST",
        url: serverPackBooking,
        dataType: 'json',
        data: JSON.stringify( inputfields ),
        success: function(result){
            //packBookings = result.bookings;
            // add pack bookings to table
            packSumAmount = result.totalamount;
            packDiscountAmount = result.discountamount;
            packTotalAmount = result.totalamount - packDiscountAmount;
            packDepositAmount = result.depositamount - packDiscountAmount;
            // add pack bookings to table
            $('#tablePack tbody').html('');
            table_html = $('#tablePackPayment tbody tr').html();
/*
            table_payment_template = table_html.split("<td>");
            table_input = table_payment_template[3].split("value=");
            table_input_text = table_input[1].split('"');     // counter (1-3)
            table_input_text_value = table_input_text[1];
console.log(table_input_text_value);   // data-text
            table_data = table_payment_template[3].split("data-text=");
            table_data_text = table_data[1].split('"');     // counter (1-3)
            table_data_text_value = table_data_text[1];     // data-text property of label
console.log(table_data_text_value);   // data-text
            table_label = table_data[1].split(">");    // counter (1-3)
            table_label_text = table_label[1].split("</label");
            table_label_text_value = table_label_text[0];   // content of label
console.log(table_label_text_value);
*/
            $('#tablePackPayment tbody').html('');
            let count = 0;
            packPaidAmount = 0;
            $.each( result.events, function( eventname, event ) {
                $.each( event.bookings, function( key, val ) {
                    let pvalue;
                    if( result.payments[val.number]===undefined )
                        pvalue = 0;
                    else
                        pvalue = result.payments[val.number];
                    $('#tablePack tbody').append('<tr><td>' + val.number + '</td><td>' + val.name + '</td><td>' + parseFloat(val.price).toFixed(2) + '</td><td>' + parseFloat(val.deposit).toFixed(2) + '</td><td>' + parseFloat(pvalue).toFixed(2) + '</td></tr>');
                    var row_text = '<tr><td>' + val.number + '</td><td>' + val.name + '</td><td>' + parseFloat(val.price).toFixed(2) + '</td><td>' + parseFloat(val.deposit).toFixed(2) + '</td><td>' + parseFloat(pvalue).toFixed(2) + '</td><td>';
                    if( pvalue<val.price )
                        for( i=1 ; i<4 ; i++ ) {
                            table_payment_template = table_html.split("<td>");
                            table_input = table_payment_template[6].split("value="); // after 5th td
    //console.log(table_input);
                            table_input_text = table_input[i].split('"');     // counter (1-3)
    //console.log(table_input_text);
                            table_input_text_value = table_input_text[1];
    //console.log(table_input_text_value);   // data-text
                            if( table_input_text_value=="deposit" && pvalue>=val.deposit ) continue;
                            table_data = table_payment_template[6].split("data-text=");
                            table_data_text = table_data[i].split('"');     // counter (1-3)
                            table_data_text_value = table_data_text[1];     // data-text property of label
    //console.log(table_data_text_value);   // data-text
                            table_label = table_data[i].split(">");    // counter (1-3)
                            table_label_text = table_label[1].split("</label");
                            table_label_text_value = table_label_text[0];   // content of label
    //console.log(table_label_text_value);
                            row_text += '<div class="form-check"><input class="form-check-input" type="radio" name="t_payment_' + val.number + '" id="t_payment_' + val.number + '.' + table_input_text_value + '" value="' + table_input_text_value + '"><label class="form-check-label" for="t_payment_' + val.number + '.' + table_input_text_value + '" data-text="' + table_data_text_value + '">' + table_label_text_value + '</label></div>';
                        }
                    row_text += '</td></tr>';
                    //$('#tablePackPayment tbody').append('<tr><td>' + val.number + '</td><td>' + val.name + '</td><td><div class="form-check"><input class="form-check-input" type="radio" name="' + val.number + '_payment" id="' + val.number + '_payment.none" value="none"><label class="form-check-label" for="' + val.number + '_payment.none" data-text="Nenhum">Nenhum</label></div><div class="form-check"><input class="form-check-input" type="radio" name="' + val.number + '_payment" id="' + val.number + '_payment.deposit" value="deposit"><label class="form-check-label" for="' + val.number + '_payment.deposit" data-text="Depósito">Depósito</label></div><div class="form-check"><input class="form-check-input" type="radio" name="' + val.number + '_payment" id="' + val.number + '_payment.full" value="full" data-error="Quantia a pagar"><label class="form-check-label" for="' + val.number + '_payment.full" data-text="Completo">Completo</label></div></td></tr>');
                    $('#tablePackPayment tbody').append(row_text);
                    packPaidAmount += pvalue;
                    count++;
                });
            });
            if( packPaidAmount>=packTotalAmount ) {
                // disable payment button
                $('#formPackButtonPayment').addClass("d-none");
            }
            // calculate pack discounts
            // update amounts
            /*
            if( packTotalAmount==0 || packTotalAmount==packPaidAmount ) {
                $('#msgMinimum').addClass("d-none");
                $('#msgFull').addClass("d-none");
                $('#msgComplete').removeClass("d-none");
                $('#t_Payment').addClass("d-none");
            } else if ( packPaidAmount>=packDepositAmount ) {
                $('#msgMinimum').addClass("d-none");
                $('#msgFull').removeClass("d-none");
                $('#msgComplete').addClass("d-none");
                $('#t_Payment').removeClass("d-none");
            } else {
                $('#msgMinimum').removeClass("d-none");
                $('#msgFull').addClass("d-none");
                $('#msgComplete').addClass("d-none");
                $('#t_Payment').removeClass("d-none");
            }
            $('#packAmounts tr[name=packSumAmount] td').html(parseFloat(packSumAmount).toFixed(2));
            if( packDiscountAmount>0 ) {
                $('#packAmounts tr[name=packDiscountAmount] td').html(parseFloat(packDiscountAmount).toFixed(2));
                $('#packAmounts tr[name=packDiscountAmount]').removeClass("d-none");
            }
            $('#packAmounts tr[name=packTotalAmount] td').html(parseFloat(packTotalAmount).toFixed(2));
            if( packTotalAmount-packPaidAmount<=0 ) {
                $('#fullvalue').html(parseFloat(0).toFixed(2) + " €");
                $('[id="t_Payment.full"]').prop("disabled", true);
            } else {
                $('#fullvalue').html(parseFloat(packTotalAmount - packPaidAmount).toFixed(2) + " €");
                $('[id="t_Payment.full"]').prop("disabled", false);
            }
            $('#packAmounts tr[name=packDepositAmount] td').html(parseFloat(packDepositAmount).toFixed(2));
            if( packDepositAmount-packPaidAmount<=0 ) {
                $('#minimumvalue').html(parseFloat(0).toFixed(2) + " €");
                $('[id="t_Payment.minimum"]').prop("disabled", true);         
            } else {
                $('#minimumvalue').html(parseFloat(packDepositAmount - packPaidAmount).toFixed(2) + " €");
                $('[id="t_Payment.minimum"]').prop("disabled", false);         
            }
            if( packTotalAmount-packPaidAmount<=0 && packDepositAmount-packPaidAmount<=0 ) {
                $('#t_PaymentAmount').prop('min', parseFloat(0).toFixed(2));
                $('#t_PaymentAmount').prop('max', parseFloat(0).toFixed(2));
                $('[id="t_Payment.other"]').prop("disabled", true);
                $('#buttonPayment').addClass("d-none");
            } else {
                $('#t_PaymentAmount').prop('min', parseFloat(packDepositAmount - packPaidAmount).toFixed(2));
                $('#t_PaymentAmount').prop('max', parseFloat(packTotalAmount - packPaidAmount).toFixed(2));
                $('[id="t_Payment.other"]').prop("disabled", false);            
                $('#buttonPayment').removeClass("d-none");
            }
            //$('#t_PaymentAmount').prop('placeholder', "De " + parseFloat(packDepositAmount).toFixed(2) + " a " + parseFloat(packTotalAmount).toFixed(2));
                */
        },
        error: function (jqXHR, exception) {
            var msg = '';
            if (jqXHR.status === 0) {
                msg = 'Not connect.\n Verify Network.';
            } else if (jqXHR.status === 400) {
                msg = 'Valor do ano é inválido!';
            } else if (jqXHR.status === 403) {
                msg = 'Não foi possível criar o diretório!';
            } else if (jqXHR.status == 404) {
                msg = 'Requested page not found. [404]';
            } else if (jqXHR.status === 409) {
                msg = 'O diretório já existe!';
            } else if (jqXHR.status == 500) {
                msg = 'Internal Server Error [500].';
            } else {
                msg = 'Uncaught Error.\n' + jqXHR.responseText;
            }
        }
    });
}

//
// Main functions
//

function getResourceAvailability(actions=false) {
    const form = document.querySelector('form')
    inputFields = convertFormToJSON(form);
    // remove all fields that are not in the list
    for (const key in inputFields)
        if( config.inputsForAvailabilityCheck.includes(key)===false )
            delete inputFields[key];
    // add event ID to form data
    inputFields.event = eventid;
    if( searchParams.has("booking")===true ) {
        inputFields.booking = searchParams.get("booking");
    }
    if( test===true ) inputFields.test = test;
    $.ajax({
        type: "POST",
        url: serverResourceAvailability,
        dataType: 'json',
        data: JSON.stringify( inputFields ),
        success: function(result){
            availableFields = result.available;
            unavailableFields = new Array();
            // check if any time field is sold out
            $.each( availableFields, function (key, val) {
                let t_available = false;
                $.each( val, function (key2, val2) {
                    let s_available = false;
                    let s_capacity = 0;
                    $.each( val2, function (key3, val3) {
                        let r_available = true;
                        let r_capacity;
                        $.each( val3, function (key4, val4) {
                            if( r_capacity===undefined || r_capacity>val4 ) 
                                r_capacity = val4;
                            if( val4==0 ) {
                                r_available = false;
                                return false;
                            }
                        });
                        if( r_available===true )
                            s_available = true;
                            //return false;
                        if( r_capacity!==undefined )
                            s_capacity += r_capacity;
                    });
                    if( s_available===false ) {
                        unavailableFields.push(key2);
                        $( '[id="' + key2 + '"]' ).prop("checked", false);
                        $( '[id="' + key2 + '"]' ).prop("disabled", true);
                    } else {
                        t_available = true;
                        $( '[id="' + key2 + '"]' ).prop("disabled", false);
                        let field = key2.substring(0, key2.indexOf('.'));
                        let value = key2.substring(key2.indexOf('.')+1);
                        // check if low availability alert is set
                        if( config.lowavailabilitythreshold!=undefined && config.lowavailabilitythreshold[field]!=undefined) {
                            if( !Array.isArray(config.lowavailabilitythreshold[field]) && s_capacity<config.lowavailabilitythreshold[field] )
                                $( '[id="' + key2 + '.alert"]' ).removeClass("d-none");
                            else if( Array.isArray(config.lowavailabilitythreshold[field]) && s_capacity<config.lowavailabilitythreshold[field][value] )
                                $( '[id="' + key2 + '.alert"]' ).removeClass("d-none");
                        } else {
                            $( '[id="' + key2 + '.alert"]' ).addClass("d-none");
                        }
                    }
                });
                if( t_available===false ) {
                    unavailableFields.push(key);
                    $( '[id="' + key + '"]' ).prop("checked", false);
                    $( '[id="' + key + '"]' ).prop("disabled", true);
                }
            });
            if( actions!==false )
                // do actions
                doActions( actions );
        },
        error: function (jqXHR, exception) {
            var msg = '';
            if (jqXHR.status === 0) {
                msg = 'Not connect.\n Verify Network.';
            } else if (jqXHR.status === 400) {
                msg = 'Valor do ano é inválido!';
            } else if (jqXHR.status === 403) {
                msg = 'Não foi possível criar o diretório!';
            } else if (jqXHR.status == 404) {
                msg = 'Requested page not found. [404]';
            } else if (jqXHR.status === 409) {
                msg = 'O diretório já existe!';
            } else if (jqXHR.status == 500) {
                msg = 'Internal Server Error [500].';
            } else {
                msg = 'Uncaught Error.\n' + jqXHR.responseText;
            }
        }
    });     
}

function conditionNOT( constraint ) {
    var condition;
    if( constraint.NOT!==undefined ) {
        condition = conditionNOT( constraint.NOT );
    } else if( constraint.AND!==undefined ) {
        condition = conditionAND( constraint.AND );
    } else if( constraint.OR!==undefined ) {
        condition = conditionOR( constraint.OR );
    } else if( constraint.XOR!==undefined ) {
        condition = conditionXOR( constraint.XOR );
    } else {
        const keys = Object.keys(constraint);
        if( $( "input[name='" + keys[0] + "']:checked" ).val() != constraint[keys[0]] )
            condition = true;
        else
            condition = false;
    }
    return condition;
}
function conditionAND( constraint ) {
    var condition;
    for( let n = 0; n < constraint.length; n++ ) {
        if( constraint[n].NOT!==undefined ) {
            condition = conditionNOT( constraint[n].NOT );
        } else if( constraint[n].AND!==undefined ) {
            condition = conditionAND( constraint[n].AND );
        } else if( constraint[n].OR!==undefined ) {
            condition = conditionOR( constraint[n].OR );
        } else if( constraint[n].XOR!==undefined ) {
            condition = conditionXOR( constraint[n].XOR );
        } else {
            const keys = Object.keys(constraint[n]);
            if( $( "input[name='" + keys[0] + "']:checked" ).val() == constraint[n][keys[0]] )
                condition = true;
            else
                condition = false;
        }
        if( condition===false )
            break;
    }
    return condition;
}
function conditionOR( constraint ) {
    var condition;
    for( let n = 0; n < constraint.length; n++ ) {
        if( constraint[n].NOT!==undefined ) {
            condition = conditionNOT( constraint[n].NOT );
        } else if( constraint[n].AND!==undefined ) {
            condition = conditionAND( constraint[n].AND );
        } else if( constraint[n].OR!==undefined ) {
            condition = conditionOR( constraint[n].OR );
        } else if( constraint[n].XOR!==undefined ) {
            condition = conditionXOR( constraint[n].XOR );
        } else {
            const keys = Object.keys(constraint[n]);
            if( $( "input[name='" + keys[0] + "']:checked" ).val() == constraint[n][keys[0]] )
                condition = true;
            else
                condition = false;
        }
        if( condition===true )
            break;
    }
    return condition;
}
function conditionXOR( constraint ) {
    var condition, count=0;
    for( let n = 0; n < constraint.length; n++ ) {
        if( constraint[n].NOT!==undefined ) {
            condition = conditionNOT( constraint[n].NOT );
        } else if( constraint[n].AND!==undefined ) {
            condition = conditionAND( constraint[n].AND );
        } else if( constraint[n].OR!==undefined ) {
            condition = conditionOR( constraint[n].OR );
        } else if( constraint[n].XOR!==undefined ) {
            condition = conditionXOR( constraint[n].XOR );
        } else {
            const keys = Object.keys(constraint[n]);
            if( $( "input[name='" + keys[0] + "']:checked" ).val() == constraint[n][keys[0]] )
                condition = true;
            else
                condition = false;
        }
        if( condition===true )
            count++;
    }
    if( count==0 || count>1 )
        condition = false;
    else
        condition = true;
    return condition;
}

function evaluateConstraint( constraint ) {
    //
    // requires upgrade to recursive evaluation
    //
    var condition = true;
    if( constraint.IF!==undefined ) {
        // single field
        const keys = Object.keys(constraint.IF);
        if( $( "input[name='" + keys[0] + "']:checked" ).val() == constraint.IF[keys[0]] )
            condition = true;
        else
            condition = false;
        // if there are more fields they are ignored
    } else if( constraint.NOT!==undefined ) {
        // NOT field
        condition = conditionNOT( constraint.NOT );
    } else if( constraint.AND!==undefined ) {
        // AND fields
        condition = conditionAND( constraint.AND );
    } else if( constraint.OR!==undefined ) {
        // OR fields
        condition = conditionOR( constraint.OR );
    } else if( constraint.XOR!==undefined ) {
        // XOR fields
        condition = conditionXOR( constraint.XOR );
    }
    return condition;
}

function checkConditions( val ) {
    if( val.date!==undefined && val.date.begin!==undefined ) {
        var begin = new Date(val.date.begin);
        if( date < begin ) return false;
    }
    if( val.date!==undefined && val.date.end!==undefined ) {
        var end = new Date(val.date.end);
        if( date > end ) return false;
    }
    if( val.open==undefined || val.open===true )
        return evaluateConstraint( val );
    return false;
}
function setupForm( setup ) {
    // Evaluate date/fields array
    $.each( setup, function (key, val) {
        if( val.date!==undefined && val.date.begin!==undefined ) {
            var date = new Date();
            var begin = new Date(val.date.begin);
            if( date < begin ) return true;
        }
        if( val.date!==undefined && val.date.end!==undefined ) {
            var date = new Date();
            var end = new Date(val.date.end);
            if( date > end ) return true;
        }
        // check conditions
        var condition = evaluateConstraint( val );
        if( condition===true )
            if( val.checkAvailability!==undefined && val.checkAvailability===true ) {
                // check availability
                getResourceAvailability(val.actions);
            } else {
                // execute actions defined
                doActions(val.actions);
            }
    });
}
//
//  Event handlers
//
function inputClickHandler( event ) {
    var value;
    value = $( "input[name='" + $(this).attr("name") + "']:checked" ).val();
    // Check if there's a click block for this radio/checkbox
    if( event.data[value]!==undefined && event.data[value].click!==undefined)
       clickHandler($(this),event.data[value].click);
}
function buttonClickHandler( event ) {
    clickHandler($(this),event.data.click);
      /*
      // Working code
      $('.btnNext').click(function() {
        const nextTabLinkEl = $('.nav-tabs .active').closest('li').next('li').find('button')[0];
        const nextTab = new bootstrap.Tab(nextTabLinkEl);
        nextTab.show();
      });
      $('.btnPrevious').click(function() {
        const prevTabLinkEl = $('.nav-tabs .active').closest('li').prev('li').find('button')[0];
        const prevTab = new bootstrap.Tab(prevTabLinkEl);
        prevTab.show();
      });
      */
}
function clickHandler( element, click ) {
//console.log(element.attr("id"));
    // Evaluate date/fields array
    $.each( click, function (key, val) {
        if( val.date!==undefined && val.date.begin!==undefined ) {
            var date = new Date();
            var begin = new Date(val.date.begin);
            if( date < begin ) return true;
        }
        if( val.date!==undefined && val.date.end!==undefined ) {
            var date = new Date();
            var end = new Date(val.date.end);
            if( date > end ) return true;
        }
        // check conditions
        var condition = evaluateConstraint( val );
        if( condition===true )
            if( val.checkAvailability!==undefined && val.checkAvailability===true ) {
                // check availability
                getResourceAvailability(val.actions);
            } else {
                // execute actions defined
                doActions(val.actions);
            }
    });
}

function doActions(val) {
    // enable
    $.each( val.enable, function (key2, val2) {
        $.each( val2, function (key3, val3) {
            var id;
            if( val3===true ) id = key3;
            else id = key3 + "." + val3;
            if( unavailableFields!==undefined && unavailableFields.includes(id)===false )
                $( '[id="' + id + '"]' ).prop("disabled", false);
        });
    });
    // check
    $.each( val.check, function (key2, val2) {
        $.each( val2, function (key3, val3) {
            var id;
            if( val3===true ) id = key3;
            else id = key3 + "." + val3;
            if( unavailableFields!==undefined && unavailableFields.includes(id)===false )
                $( '[id="' + id + '"]' ).prop("checked", true);
        });
    });
    // uncheck
    $.each( val.uncheck, function (key2, val2) {
        $.each( val2, function (key3, val3) {
            var id;
            if( val3===true ) id = key3;
            else id = key3 + "." + val3;
            $( '[id="' + id + '"]' ).prop("checked", false);
        });
    });
    // clear
    $.each( val.clear, function (key2, val2) {
        $.each( val2, function (key3, val3) {
            var id;
            if( val3===true ) id = key3;
            else id = key3 + "." + val3;
            $( '[id="' + id + '"]' ).val("");
        });
    });
    // disable
    $.each( val.disable, function (key2, val2) {
        $.each( val2, function (key3, val3) {
            var id;
            if( val3===true ) id = key3;
            else id = key3 + "." + val3;
            $( '[id="' + id + '"]' ).prop("disabled", true);
        });
    });                
    // expand
    $.each( val.expand, function (key2, val2) {
        $.each( val2, function (key3, val3) {
            var id;
            if( val3===true ) id = key3;
            else id = key3 + "." + val3;
            $( '[id="' + id + '"]' ).removeClass("collapse");
            //$( '[id="' + id + '"]' ).collapse("show");
        });
    });
    /*
    // collapse
    $.each( val.collapse, function (key2, val2) {
        $.each( val2, function (key3, val3) {
            var id;
            if( val3===true ) id = key3;
            else id = key3 + "." + val3;
            $( '[id="' + id + '"]' ).addClass("collapse");
            //$( '[id="' + id + '"]' ).collapse("hide");
        });
    });
    */
    // show
    $.each( val.show, function (key2, val2) {
        $.each( val2, function (key3, val3) {
            var id;
            if( val3===true ) id = key3;
            else id = key3 + "." + val3;
            $( '[id="' + id + '"]' ).removeClass("d-none");
        });
    });
    // hide
    $.each( val.hide, function (key2, val2) {
        $.each( val2, function (key3, val3) {
            var id;
            if( val3===true ) id = key3;
            else id = key3 + "." + val3;
            $( '[id="' + id + '"]' ).addClass("d-none");
        });
    });
}
//
//  Calculator functions
//
function calculateAmounts() {
    var discountAmount = 0;
    depositAmount = 0;
    totalAmount = 0;
    // process each block of the calculator
    $.each( info.calculator, function( key, val ) {
        price = 0;
        amounts[key] = 0;
        $.each( val, calculateBlock );
        if( prices.length > 0 ) {
            // add all elements of prices array using a reduce
            const reducer = (accumulator, curr) => accumulator + curr;
            amounts[key] = prices.reduce(reducer);
            prices = [];
        }
        if( discounts.length > 0 ) {
            // add all elements of prices array using a reduce
            const reducer = (accumulator, curr) => accumulator + curr;
            discountAmount += discounts.reduce(reducer);
            discounts = [];
        }
        if( deposits.length > 0 ) {
            // add all elements of prices array using a reduce
            const reducer = (accumulator, curr) => accumulator + curr;
            depositAmount += deposits.reduce(reducer);
            deposits = [];
        }
    });

    // prepare amounts to display
    partialAmount = 0;
    for( const key in amounts ) {
        const value = amounts[key];
        partialAmount += value;
        if( value>0 ) {
            $('#tAmounts tr[name=' + key + 'Amount] td').html(parseFloat(value).toFixed(2));
            $('#tAmounts tr[name=' + key + 'Amount]').removeClass("d-none");
        } else
            $('#tAmounts tr[name=' + key + 'Amount]').addClass("d-none");
    }
    totalAmount = partialAmount - discountAmount;
    
    if( discountAmount>0 ) {
        $('#tAmounts tr[name=partialAmount] td').html(parseFloat(partialAmount).toFixed(2));
        $('#tAmounts tr[name=discountAmount] td').html(parseFloat(discountAmount).toFixed(2));
        $('#tAmounts tr[name=partialAmount]').removeClass("d-none");
        $('#tAmounts tr[name=discountAmount]').removeClass("d-none");
    } else {
        $('#tAmounts tr[name=partialAmount]').addClass("d-none");
        $('#tAmounts tr[name=discountAmount]').addClass("d-none");
    }
    $('#tAmounts tr[name=totalAmount] td').html(parseFloat(totalAmount).toFixed(2));
    $('span[name=totalAmount]').html(parseFloat(totalAmount).toFixed(2));
    $('#tAmounts tr[name=depositAmount] td').html(parseFloat(depositAmount).toFixed(2));
    $("#packTotalAmount").text(packTotalAmount);
    $("#packDepositAmount").text(packDepositAmount);
    // update min and max of other amount field
    $('#t_PaymentAmount').prop('min', parseFloat(depositAmount).toFixed(2));
    $('#t_PaymentAmount').prop('max', parseFloat(totalAmount).toFixed(2));
    $('#t_Payment.full.value').html(parseFloat(packTotalAmount).toFixed(2));
    $('#t_Payment.minimum.value').html(parseFloat(packDepositAmount).toFixed(2));
    //$('#t_PaymentAmount').prop('placeholder', "Entre " + parseFloat(depositAmount).toFixed(2) + " e " + parseFloat(totalAmount).toFixed(2));
}

function calculateBlock(key, val) {
    $.each( val, function (key2, val2) {
        // initialize discount
        discount=0;
        var id = key + "." + key2;
        if( $( '[id="' + id + '"]' ).prop("checked") ) {
            if( val2.price!==undefined ) {
                // there's a price block so iterate each element of price array to get the best amount
                smallestAmount= Number.MAX_SAFE_INTEGER;
                biggestAmount = 0;
                $.each( val2.price, getBlockAmount );
                if( smallestAmount < Number.MAX_SAFE_INTEGER ) {
                    price = smallestAmount
                    prices.push( price );
                }
            }
            if( val2.discount!==undefined && price>0 ) {
                // there's a discount block so iterate each element of discount array to get the best amount
                smallestAmount= Number.MAX_SAFE_INTEGER;
                biggestAmount = 0;
                $.each( val2.discount, getBlockAmount );
                if( biggestAmount > 0 ) {
                    discount = biggestAmount;
                    discounts.push( discount );
                }
            }
            if( val2.deposit!==undefined && price>0 ) {
                // there's a deposits block so iterate each element of deposits array to get the best amount
                smallestAmount= Number.MAX_SAFE_INTEGER;
                biggestAmount = 0;
                $.each( val2.deposit, getBlockAmount );
                if( biggestAmount > 0 ) {
                    deposit = biggestAmount;
                    deposits.push( biggestAmount );
                }
            }
        }
    });
}

function getBlockAmount(key, val) {
    // Evaluate date/fields array
    if( val.date!==undefined && val.date.begin!==undefined ) {
        var date = new Date();
        var begin = new Date(val.date.begin);
        if( date < begin ) return;
    }
    if( val.date!==undefined && val.date.end!==undefined ) {
        var date = new Date();
        var end = new Date(val.date.end);
        if( date > end ) return;
    }
    if( val.open!==undefined && val.open===false ) {
        return;
    }
    // check conditions
    var condition = evaluateConstraint( val );
    if( condition===true) {
        // get amount from current block if it's lower than the best amount from the previous blocks
        if( val.amount!==undefined && smallestAmount>val.amount)
            smallestAmount = val.amount;
        else if( val.percentage!==undefined && smallestAmount>(val.percentage * (price-discount) / 100) )
            smallestAmount = val.percentage * (price-discount) / 100;
        // get amount from current block if it's lower than the best amount from the previous blocks
        if( val.amount!==undefined && biggestAmount<val.amount)
            biggestAmount = val.amount;
        else if( val.percentage!==undefined && biggestAmount<(val.percentage * (price-discount) / 100) )
            biggestAmount = val.percentage * (price-discount) / 100;
    }
}

//
// Helper functions
//

function convertFormToJSON(form) {
    return $(form)
        .serializeArray()
        .reduce(function (json, { name, value }) {
            json[name] = value;
            return json;
        }, {});
}  

function getFileName() {
    let url = new URL(window.location.href);
    let path = url.pathname;
    let fileName = path.substring(path.lastIndexOf('/') + 1);
    return fileName;
}

function resetFormWithoutValidation(form) {
    // Remove 'was-validated' class to prevent showing validation messages
    form.classList.remove('was-validated');
    // Reset the form
    form.reset();
    // Clear validation state manually
    var inputs = form.querySelectorAll('input, select, textarea');
    inputs.forEach(function (input) {
        input.setCustomValidity('');
        input.classList.remove('is-invalid');  // Remove any custom invalid class if used
        input.classList.remove('is-valid');    // Remove any custom valid class if used
    });
    // setup form
    if( config.setup!==undefined )
        setupForm( config.setup );
}
