

function hrefonclickButtonGO(pagename, pagedatastring = '') {
    if (!pagename) { return false; }
    return `href="javascript:void(0);" onclick="ButtonGo('${pagename}',${pagedatastring});return false;"`;
}

function generateHTMLfromarray(prepend, append, array, func) {
    if (!func || !array) { return false; }
    let htmlres = prepend;
    array.forEach((value) => {
        if (value.length > 0) {
            htmlres += func(...value);
        }
    });
    htmlres += append;
    return htmlres;
}

function imgiconuserdefault(imgsrc, imgwidth = '', imgheight = '', id = '', onclick = '') {
    if (!imgsrc) { return false; }
    if (!imgwidth) { imgwidth = 30; }
    if (!imgheight) { imgheight = 30; }
    if (id) { id = 'id="' + id + '"'; } else { id = '' }
    return `<img src="${imgsrc}" style="width: ${imgwidth}; height: ${imgheight};" ${id} onclick="${onclick}" class="icon-user"/>`;
}

function UICardStatsDetails(Title = '', number = 0, Unit = '', leftORright = 'left', numberid = '') {
    if (!leftORright) { leftORright = 'left'; }
    return `<div class="col br-right">
    <div class="inner-${leftORright}">
        <p>${Title}</p>
        <h3 id="${numberid}">${number}</h3>
        <span>${Unit}</span>
    </div>
    </div>`;
}

/**
 * Generates an HTML string for displaying stats details.
 * 
 * @param {array} statsarray - A 2D array containing stats data, where each inner array has the format [title, number, unit, leftorright,numberid]
 * @returns {string} HTML string representing the stats details
 */
function UIStatsDetailsArray(statsarray) {

    return generateHTMLfromarray('<div class="row">', '</div>', statsarray, UICardStatsDetails);

}
/**
 * Generates an HTML string for displaying stats details.
 * 
 * @param {array} statsarray - A 2D array containing stats data, where each inner array has the format [title, number, unit, leftorright,numberid]
 * @returns {string} HTML string representing the stats details including the balance wrapper
 */
function UIBalance_WrapperfromArray(statsarray) {
    if (!statsarray) { return false; }
    let htmlres = `<div id="balance_wrapper">
                    <div class="balance">`;
    htmlres += UIStatsDetailsArray(statsarray);
    htmlres += '</div></div>'
    return htmlres;
}

function UIBalance_Wrapper_WalletFooter_Item(maintitle = '', onclickstring = '', imgsrc = '', href = '', subtitleline1 = '', subtitleline2 = '', subtitleline3 = '', subtitleline4 = '', imgwidth = '', imgheight = '') {

    if (!href) { href = "javascript:void(0);"; }
    if (!imgwidth) { imgwidth = "30"; }
    if (!imgheight) { imgheight = "30"; }
    return `<li class="wallet-card-item">
                        <a class="fw_6 text-center" id="btn-popup-down" href="${href}" 
                        onclick="${onclickstring}">
                            <ul>
                                <li class="path1">${subtitleline1}</li>
                                <li class="path2">${subtitleline2}</li>
                                <li class="path3">${subtitleline3}</li>
                                <li class="path4">${subtitleline4}</li>
                            </ul>
                            ${imgiconuserdefault(imgsrc, imgwidth, imgheight)}
                            ${maintitle}
                        </a>
                    </li>`;
}

function UIBalance_Wrapper_WalletFooter_Item_ButtonGO(maintitle, pagename, pagestring = '', iconclass = '', subtitleline1 = '', subtitleline2 = '', subtitleline3 = '', subtitleline4 = '') {
    if (!pagename) { return false; }
    const onclickstring = `ButtonGo('${pagename}','${pagestring}');return false;`;
    //const iconclass =`icon far fa-hdd`;
    const htmlres = UIBalance_Wrapper_WalletFooter_Item(maintitle, onclickstring, iconclass, false, subtitleline1, subtitleline2, subtitleline3, subtitleline4);

    return htmlres;
}

/**
 * Generates an HTML string for a balance wrapper item button array.
 * 
 * @param {array} balancewrapper_item_array - A 2D array containing balance wrapper item data, where each inner array has the format [maintitle, pagename, pagestring, imagesrc, subtitleline1, subtitleline2, subtitleline3, subtitleline4,imgwidth,imgheight]
 * @returns {string} HTML string representing the balance wrapper item button array
 */
function UIBalance_Wrapper_WalletFooter_ARRAY(balancewrapper_item_array) {
    return generateHTMLfromarray(`<div class="wallet-footer">
        <ul class="d-flex justify-content-between align-items-center">`, '</ul></div>', balancewrapper_item_array, UIBalance_Wrapper_WalletFooter_Item_ButtonGO);
}
/**
 * Generates an HTML string for a balance wrapper item button array.
 * 
 * @param {array} statsarray - A 2D array containing stats data, where each inner array has the format [title, number, unit, leftorright]
 * @param {array} balancewrapper_item_array - A 2D array containing balance wrapper item data, where each inner array has the format [maintitle, pagename, pagestring, iconclass, subtitleline1, subtitleline2, subtitleline3, subtitleline4]
 * @param {string} style - a string containing custom style for the balance box
 * @returns {string} HTML string for the whole balance box
 */
function UIcreateBalanceBoxfromArray(statsarray, balancewrapper_item_array, style = 'border: solid 3px #000d88;') {

    let htmlres = `<div class="tf-container">
<div class="tf-balance-box" style="${style}">`;
    htmlres += UIBalance_WrapperfromArray(statsarray);
    htmlres += UIBalance_Wrapper_WalletFooter_ARRAY(balancewrapper_item_array);
    return htmlres;
}

function UIServices_Button(imgiconsrc, title = '', onclick = '', href = '', bgcolor8 = false) {
    if (!bgcolor8) { bgcolor8 = '' } else { bgcolor8 = 'bg_color_8'; }
    return `<li><a href="${href}" onclick="${onclick}"><div class="icon-box ${bgcolor8}" ><img src="${imgiconsrc}"/></div>${title}</a></li>`;
}
function UIServices_Button_GOTOPAGE(imgiconsrc, title, pagename, pagedatastring = '') {
    return UIServices_Button(imgiconsrc, title, `ButtonGo('${pagename}','${pagedatastring}');return false;`, '');
}

function UIServices_FullDIV_GOTOPAGE_Array(title, viewallhref = '', viewallonclick = '', viewalltext = '', services_button_array) {
    return generateHTMLfromarray(`<div class="mt-5">
            <div class="tf-container">
                <div class="tf-title d-flex justify-content-between">
                    <h3 class="fw_6">${title}</h3>
                    <a href="${viewallhref}" onclick="${viewallonclick}" class="primary_color fw_6">${viewalltext}</a>
                </div>
                <ul class="box-service mt-3">`, '</ul></div></div>', services_button_array, UIServices_Button_GOTOPAGE);
}



function UIServices_FullDIV_ONCLICK_Array(title, viewallhref = '', viewallonclick = '', viewalltext = '', services_button_array) {

    return generateHTMLfromarray(`<div class="mt-5">
            <div class="tf-container">
                <div class="tf-title d-flex justify-content-between">
                    <h3 class="fw_6">${title}</h3>
                    <a href="${viewallhref}" onclick="${viewallonclick}" class="primary_color fw_6">${viewalltext}</a>
                </div>
                <ul class="box-service mt-3">`, '</ul></div></div>', services_button_array, UIServices_Button);
}

function UISideText_DualColumnButton(text, pagename, pagedatastring = '', imgsrc = '', imgwidth = '', imgheight = '') {
    if (!pagename || !text) { return false; }
    if (!imgwidth) { imgwidth = 30; } if (!imgheight) { imgheight = 30; }
    return `<li onclick="ButtonGo('${pagename}','${pagedatastring}');return false;">
            <div class="">
              ${imgiconuserdefault(imgsrc, imgwidth, imgheight)}
            </div>${text}
        </li>`;
}

function UISideText_DualColumnButton_Array(sidetext_button_dualcolumn_array) {
    return generateHTMLfromarray('<ul class="mt-3 box-outstanding-service">', '</ul>', sidetext_button_dualcolumn_array, UISideText_DualColumnButton);
}
function UICardSimple(title, text = '', id = '') {
    return CreateCardSimple(title, text, id);
}

function UIRecentSearchBar(searchplaceholdertext, classtosearch, id, imgsrclefticon = '', imgsrcrighticon = '', imgwidth = '', imgheight = '') {
    if (!imgwidth) { imgwidth = 30; }
    if (!imgheight) { imgheight = 30; }
    if (!classtosearch) { classtosearch = ''; }
    if (!imgsrclefticon) { imgsrclefticon = '<span class="icon-search"></span>'; } else {
        imgsrclefticon = imgiconuserdefault(imgsrclefticon, imgwidth, imgheight);
    }
    if (!searchplaceholdertext) { searchplaceholdertext = 'Search'; }
    let righticonhtml = '';
    if (imgsrcrighticon) {
        righticonhtml = imgiconuserdefault(imgsrcrighticon, imgwidth, imgheight, id + '-leftsearchicon');
    } else {
        righticonhtml = '';
    }

    return `<div class="box-search mt-3" >
            <div class="input-field">
                ${imgsrclefticon}
                <input id=${id}  class="search-field value_input" placeholder="${searchplaceholdertext}" type="text">
                <span class="icon-clear" id="clear-${id}"></span>
            </div>
            ${righticonhtml}
        </div>
        <script>
$(document).ready(function() {
    $('#${id}').on('keyup', function() {
        let searchTerm_${id} = $(this).val().toLowerCase();
        $('.list-card-invoice.${classtosearch}').filter(function() {
            let contentText_${id} = $(this).find('.content-right h4 a').text().toLowerCase() + 
                              $(this).find('.content-right p').text().toLowerCase();
        });
    });

    $('#clear-${id}').on('click', function() {
    $('#${id}').val(''); 
    $('#${id}').trigger('keyup'); 
        });
});
        </script>
        `;
}




function UIRecentSearchable_Button_GO(title, subtitle, rightsidetext, classforsearch, pagename, pagedatastring = '', imgsrc, imgwidth = '', imgheight = '') {
    if (!pagename) { return false; }
    if (!imgwidth) { imgwidth = 30; }
    if (!imgheight) { imgheight = 30; }
    if (!classforsearch) { classforsearch = ''; }
    return `<li class="list-card-invoice ${classforsearch}">
                <div class="logo">
                  <img src="${imgsrc}" style="width: ${imgwidth}; height: ${imgheight};" class="icon-user">
                </div>
                <div class="content-right">
                    <h4><a href="" onclick="ButtonGo('${pagename}',${pagedatastring});return false;">${title} 
                    <span class="critical_color">${rightsidetext}</span></a></h4>
                    <p>
                        ${subtitle}
                    </p>
                </div>
            </li>`;
}

function UIRecentSearchable_Button_GO_ARRAY(title, recentssearchablebuttonarray, viewallpagetarget, viewallpagedata = '', viewalltext = '') {
    return generateHTMLfromarray(`<h3 class="fw_6 d-flex justify-content-between mt-3">${title}<a ${hrefonclickButtonGO(viewallpagetarget, viewallpagedata)}>${viewalltext}</a></h3>
                    <ul class="mt-3 mb-5">`, '</ul>', recentssearchablebuttonarray, UIRecentSearchable_Button_GO);
}




function UIListArrowButton_GO(title, subtitle, pagename, pagedatastring = '', imgsrc, imgwidth = '', imgheight = '') {
    if (!pagename) { return false; }
    if (!imgwidth) { imgwidth = 30; }
    if (!imgheight) { imgheight = 30; }
    return `<div class="list-bill-view mb-4">
            ${imgiconuserdefault(imgsrc, imgwidth, imgheight)}
            <div class="content">
                <h4><a ${hrefonclickButtonGO(PAGENAME, pagedatastring)} class="fw_6">${title}</a></h4>
                <p>${subtitle}</p>
            </div>
            <i class="icon-right"></i>
        </div>`;
}
function UIListArrowButton_GO_ARRAY(UIListArrowButtonGOARRAY) {
    return generateHTMLfromarray('', '', UIListArrowButtonGOARRAY, UIListArrowButton_GO);
}



function UISearchBox_with_BUTTONS_FULL(title, recentssearchablebuttonarray, UIListArrowButtonGOARRAY = '', viewallpagetarget, viewallpagedata = '', viewalltext = '', classtosearch = '', searchid = '', searchplaceholdertext = '', searchlefticon = '', searchrighticon = '', imgwidth = '', imgheight = '') {
    let htmlres = '';
    if (classtosearch && searchid) {
        htmlres += UIRecentSearchBar(searchplaceholdertext, classtosearch, searchid, searchlefticon, searchrighticon, imgwidth, imgheight);
    }
    htmlres += UIRecentSearchable_Button_GO_ARRAY(title, recentssearchablebuttonarray, viewallpagetarget, viewallpagedata, viewalltext);
    if (UIListArrowButtonGOARRAY) {
        htmlres += UIListArrowButton_GO_ARRAY(UIListArrowButtonGOARRAY);
    }
    return htmlres;
}

function UIinputgroupcore(innerhtml = '', label = '', inputgroupid = '') {
    let htmllabel;
    if (!label && !inputgroupid) { htmllabel = ''; }
    else { htmllabel = `<label for="${inputgroupid}">${label}</label>`; }
    return `${htmllabel}<div class="input-group mb-3" id="${inputgroupid}" style="">
              ${innerhtml}
            </div>`;
}


//Input group
function UIInputGroup(placeholder, type, id, label = '', classinput = '', spanclass = '', imginsteadofspan = '', required = false, textvalue = '', datalist = '', imgwidth = '', imgheight = '', disabled = false) {
    if (!required) { required = ''; } else { required = 'required'; }
    if (!type) { return false; }
    let span; let html; let inner; let labelid;
    if (!type) { type = 'text'; }
    if (!classinput) { classinput = 'form-control'; }
    if (datalist) { datalist = ' list="' + datalist + '" '; } else { datalist = ''; }
    span = `<span class="${spanclass}" id="${id}-span"></span>`;
    if (!imgwidth) { imgwidth = '40px'; } if (!imgheight) { imgheight = '40px'; }
    if (imginsteadofspan) { span = imgiconuserdefault(imginsteadofspan, imgwidth, imgheight, 'imgspan' + id); }
    if (!imginsteadofspan && !spanclass) { span = ''; } else {
        /*
        span =`<div class="input-group-append">
        <div class="input-group-text" id="${id}-input-group-text">
           ${span}
        </div>
    </div>`; 
        */
    }

    if (disabled) {
        disabled = ' disabled ';
    }

    if (label) { }
    inner = `<input type="${type}" id="${id}" class="${classinput}" ${disabled} ${datalist} placeholder="${placeholder}" value="${textvalue}" name="${id}" ${required}>${span}`;
    labelid = id + '-div-mb3';
    html = UIinputgroupcore(inner, label, labelid);
    return html;
}

function UIInputGroupFileUploadDropzone(id, label = '', url = '', inputgroupid = '', width = '100%', disabled = '') {
    if (!url) { url = '/File/Upload/Unknown'; }
    clearbuttonid = 'ClearUploadButton-' + id;
    if (width) {
        width = ' style="width: ' + width + ';" ';
    } else {
        width = '';
    }
    if (disabled) {
        disabled = 'style=" pointer-events: none;"';
    }
    const clearuploadsbutton = ' ' + imgiconuserdefault('https://cdn.jsdelivr.net/gh/telemagnadon/obj-vault-3a@v2026.05.14-vendor-2/a/b6dc254166b4.bin', '', '', clearbuttonid, `LoadDataPageFunc.ClearUpload['${id}']();`);
    return UIinputgroupcore('<form ' + disabled + ' action="' + url + '" ' + width + ' class="dropzone" id="' + id + '"></form>', label + clearuploadsbutton, inputgroupid);
}


function DropZoneLOADDATAPAGEFUNC(url, dropzoneid, acceptedfiles = '', maxsizeMB = 100) {
    if (!url) { url = '/File/Upload/Unknown'; }

    const clearbuttonid = 'ClearUploadButton-' + dropzoneid;
    $('#' + clearbuttonid).hide();

    window.Target_Uploaded_Files = [];

    if (!acceptedfiles) { acceptedfiles = DropZoneFunc.AcceptedFilesString.images; }
    if (typeof window.currentDropzone === 'undefined') { window.currentDropzone = {}; }

    // Initialize Dropzone
    const dzInstance = DropZoneFunc.InitializeDropZone(
        url,
        (response) => {
            if (response.success && response.hashkey) {
                if (!Target_Uploaded_Files.includes(response.hashkey)) {
                    Target_Uploaded_Files.push(response.hashkey);
                }
            } else {
                dzInstance.removeFile(dzInstance.files[dzInstance.files.length - 1]);
            }

            if (Target_Uploaded_Files.length > 0) {
                $('#' + clearbuttonid).show();
            } else {
                $('#' + clearbuttonid).hide();
            }
        },
        dropzoneid,
        acceptedfiles,
        'file',
        maxsizeMB,
        false,
        (errorresponse) => {
            // handle error if needed
        }
    );

    // Store globally
    window.currentDropzone[dropzoneid] = dzInstance;

    //dzInstance.dropzoneobject = dzInstance;
    dzInstance.functions = {};



    dzInstance.functions.AddPreviouslyUploadedFiles = function (filesarray) {
        return DropZoneFunc.AddPreviouslyUploadedFiles(dzInstance, filesarray);
    };

    dzInstance.functions.ReplaceDropzoneFiles = function (newFilesArray) {
        return DropZoneFunc.ReplaceDropzoneFiles(dropzoneid, newFilesArray);
    };
    dzInstance.functions.ResetDropzoneUpload = function (url, obj = null, reqtype = 'POST', successfunc = false) {
        return DropZoneFunc.ResetDropzoneUpload(url, obj, reqtype, successfunc);
    };

    dzInstance.functions.ClearDropzoneUpload = function () {
        return DropZoneFunc.ClearDropzoneUpload(dropzoneid, dzInstance);
    };

    dzInstance.functions.hasOngoingUploads = function () {
        return DropZoneFunc.hasOngoingUploads(dzInstance);
    };

    dzInstance.functions.RemoveLastUploadedDropzone = function () {
        return DropZoneFunc.RemoveLastUploadedDropzone(dzInstance);
    };

    dzInstance.functions.AddFiles = function (dropzonemodal = 'Dropzone-Modal', errorcallback) {
        return DropZoneFunc.AddFiles(url = '/File/Upload', errorcallback, filename = 'file', maxfilesize = 100, acceptedFiles, dropzoneid, dropzonemodal);
    };



    if (typeof LoadDataPageFunc.ClearUpload === 'undefined') {
        LoadDataPageFunc.ClearUpload = {};
    }

    LoadDataPageFunc.ClearUpload[dropzoneid] = function () {
        $('#' + clearbuttonid).hide();
        DropZoneFunc.ClearDropzoneUpload(dropzoneid, dzInstance);
    };
}

function InitializeLoadDataPageFuncDropZonePhotoUpload(url, dropzoneid, acceptedfiles = '', maxsizeMB = 100) {
    if (typeof LoadDataPageFunc === 'undefined') { return false; }
    // console.log('initializing photodropzone');
    LoadDataPageFunc.InitializePhotoDropZone = function () { return DropZoneLOADDATAPAGEFUNC(url, dropzoneid, acceptedfiles, maxsizeMB); };
}



function SendPostDataURLData(url, data, sucessfunc, errorfunc = false, fromvarcache = false) {
    if (!url || !data) { return false; }
    let SendPostDataReqq = new RequestData(false);
    SendPostDataReqq.url(url).type('POST').data(data)
        .fromVarCache(fromvarcache)
        .success((response) => {
            if (typeof sucessfunc === 'function') { sucessfunc(response); }
        }).error((response) => {
            if (typeof errorfunc === 'function') { errorfunc(response); }
        }).go();

}

function getInputAndTextareaValuesbyCSSClassName(className) {
    const elements = document.getElementsByClassName(className);
    const results = [];
    elements.forEach(element => {
        const id = element.id;
        const value = element.value;
        results.push({ id, value });
    });
    return results;
}

function getInputElementsValuesObjectbyCSSClassname(classname) {
    const elements = document.getElementsByClassName(classname);
    const results = {};

    elements.forEach(element => {
        const id = element.id;
        const value = element.value;
        results[id] = value;
    });
    return results;
}


// Helper function to extract hashkey from response (handles both string and JSON object responses)
function getHashkeyFromResponse(response) {
    if (!response) return null;
    
    // If response is already a string/hash key
    if (typeof response === 'string') {
        return response;
    }
    
    // If response is an object with hashkey property (JSON response from backend)
    if (response && typeof response.hashkey === 'string') {
        return response.hashkey;
    }
    
    return null;
}

// Helper function to extract hashkey and call callback with it
function getResponseHashkeyOrErrorMessage(response, successCallback, errorCallback) {
    const hashkey = getHashkeyFromResponse(response);
    if (hashkey) {
        successCallback(hashkey);
    } else {
        // Check if response is an error object
        if (response && typeof response === 'object' && !Array.isArray(response)) {
            const errorMessage = response.message || response.error || 'Unknown error';
            errorCallback(errorMessage);
        } else {
            errorCallback('Invalid response format');
        }
    }
}

function SendPostDataFormwithTARGETUPLOADEDFILES(url, forminputclass, successfunc, WithTarget_Uploaded_Files = true, errorfunc = false) {
    if (!url || !forminputclass || !successfunc) { return false; }
    let datatosend = getInputElementsValuesObjectbyCSSClassname(forminputclass);
    if (isObjectEmpty(datatosend)) { return false; }
    if (WithTarget_Uploaded_Files && typeof window.Target_Uploaded_Files !== 'undefined' && window.Target_Uploaded_Files.length > 0) {
        datatosend['files'] = Target_Uploaded_Files;
    }

    let target;
    let data = null;


    if (typeof currenttarget === 'object') {
        try {
            target = currenttarget['target'];
        } catch (error) {
            target = currenttarget;
        }

        try {
            data = currenttarget['data'];
        } catch (error) {
            data = null;
        }

    } else {
        target = currenttarget;
        data = null;
    }



    if (typeof datatosend.target === 'undefined') {
        datatosend['target'] = target;
        datatosend['data'] = data;
    }


    // Wrap successfunc to extract hashkey from JSON responses
    const wrappedSuccessFunc = function(response) {
        const hashkey = getHashkeyFromResponse(response);
        if (hashkey) {
            successfunc(hashkey);
        } else {
            // Pass original response for error handling
            successfunc(response);
        }
    };
    
    SendPostDataURLData(url, datatosend, wrappedSuccessFunc, errorfunc, fromvarcache = false);
}



function UIInputGroupTEXTAREA(label = '', textareaID = '', required = false, textareaCONTENT = '', textareaCLASS = '', inputgroupid = '', disabled = '') {
    if (required) { required = ' required '; } else { required = ''; }
    if (disabled) {
        disabled = 'disabled'
    }
    const innerhtml = `<textarea ${disabled} id="${textareaID}" name="${textareaID}" ${required} class="${textareaCLASS}">${textareaCONTENT}</textarea>`;
    return UIinputgroupcore(innerhtml, label, inputgroupid);
}


function UIInputGroupSelect(id = '', label = '', optionsarray = '', spanclass = '', imginsteadofspan = '', selectedvalue = '', imgwidth = '', imgheight = '', select_class = '', disabled = '') {
    //optionsarray =[['value1','text1'],['value2','text2',selectedtrue] ]
    let inner; let labelid; let htmlspan; let optionshtml = '';
    if (!spanclass && !imginsteadofspan) { htmlspan = ''; }
    if (!imgwidth) { imgwidth = '40px'; } if (!imgheight) { imgheight = '40px'; }
    optionshtml = UIArraytoOptionforSelect(optionsarray, selectedvalue);

    if (spanclass) {
        htmlspan = `<span class="spanclass"></span>`;
    }
    if (imginsteadofspan) {
        htmlspan = imgiconuserdefault(imginsteadofspan, '10px', '10px');
    }
    if (!spanclass && !imginsteadofspan) {
        htmlspan = '';
    } else {
        htmlspan = `<div class="input-group-append">
        <div class="input-group-text" id="${id}-input-group-text">
           ${htmlspan}
        </div>
    </div>`;
    }


    if (disabled) {
        disabled = 'disabled';
    } else {
        disabled = '';
    }

    inner = `<select ${disabled} class="form-control ${select_class}" id="${id}">
        ${optionshtml}
        </select>${htmlspan}`;

    labelid = id + '-select-div-mb3';
    html = UIinputgroupcore(inner, label, labelid);
    return html;
}

function UIInputGroupDatePicker() {

}


function UIArraytoOptionforSelect(array, selectedvalue = '') {
    if (!array) { return ''; } let optionshtml = '';
    let val; let selected;
    for (let i = 0; i < array.length; i++) {
        val = array[i];
        //   selected = (val[2] !== undefined) ? val[2] : '';
        selected = '';

        if (selectedvalue !== '' && selectedvalue == val[0]) { selected = 'selected'; }
        optionshtml += `<option value="${val[0]}" ${selected}>${val[1]}</option>`;
    }
    return optionshtml;
}

function UIReplaceCurrentOptionsSelect(selectid, optionsarray, selectedvalue = '') {
    if (!selectid || !optionsarray) { return false; }
    let optionshtml = UIArraytoOptionforSelect(optionsarray, selectedvalue);
    $('#' + selectid).html(optionshtml);
}

function UIInputGroupNumber(placeholder, id, label = '', classinput = '', min = '', max = '', spanclass = '', imginsteadofspan = '', required = false, val = 0, datalist = '', imgwidth = '', imgheight = '', disabled = false) {
    let UI = UIInputGroup(placeholder, 'number', id, label, classinput, spanclass, imginsteadofspan, required, val, datalist, imgwidth, imgheight, disabled);
    //    console.log('placeholder ',placeholder,' label ', label);
    UI = '<div>' + UI + '</div>';
    UI = $(UI);
    let input = UI.find('input');
    input.attr('min', min);
    input.attr('max', max);
    input.val(val);
    return UI.html();
}


function UIInputGroupButton(buttontext, buttonclass = '', buttonid = '', onclick = '', buttonstyle = '') {
    if (!buttontext) { return false; }
    if (!buttonclass) { buttonclass = 'btn-primary'; }

    return `<div class="input-group mb-3">
                <button class="form-control ${buttonclass}" id="${buttonid}" onclick="${onclick}" style="${buttonstyle}">${buttontext}</button>
            </div>`;
}

function UIInputGroupCheckBox(input_id, label, checked = false, additional_input_class = '', additional_label_class = '') {
    if (checked === true) { checked = 'checked'; } else {
        checked = '';
    }
    return `<div class="form-check">
        <input class="form-check-input ${additional_input_class}" type="checkbox" value="" ${checked} id="${input_id}">
            <label class="form-check-label ${additional_label_class}" for="${input_id}">
               ${label}
            </label>
    </div>`
}

function UISetDarkMode() {
    $('body').addClass('dark-mode'); $('.tf-balance-box').removeAttr('style');
    $('.card').addClass('dark-mode');
    $('.card-header').addClass('dark-mode');
    $('.card-body').addClass('dark-mode');
    $('.modal-content').addClass('dark-mode');
    $('.btn').addClass('dark-mode');
    $('input').addClass('dark-mode');
    $('textarea').addClass('dark-mode');
    $('select').addClass('dark-mode');
    $('form').addClass('dark-mode');

}

function UIUpdateBodyHTML(html = '') {
    $('#main-body').html(html);
}


function changeTopbarTitle(title) {
    $('#topbar-title').html(title);
}

function setDefaultBackOnclickifNoHistory(functtoCall) {

    if (!functtoCall) {
        defaultBackOnclick = null;
    }

    if (historylist.length < 2) {
        if (typeof functtoCall === 'function') {
            defaultBackOnclick = functtoCall;
        }
    }
}

function setDefaultbackGotoPageifNoHistory(pageName, targetdata) {
    const functiongoto = function () {
        gotoPage(pageName, targetdata);
    };
    setDefaultBackOnclickifNoHistory(functiongoto);
}

function getcurrenttargetHash() {
    const url = new URL(window.location.href);
    const parts = url.pathname.split('/').filter(Boolean);
    return parts.at(-1) || null;
}

function requestGetData(targetURL, functionsuccess, cachefirst = false) {
    request.url(targetURL)
        .success((response) => {
            if (typeof functionsuccess === 'function') {
                functionsuccess(response);
            }
        })
        .data()
        .fromVarCache(cachefirst)
        .type("GET")
        .go();
}


let ElementDOM = {};
function getUIElementsAndAttributes() {
    const uiElements = document.querySelectorAll('UI');
    const uiData = {};
    uiElements.forEach(uiElement => {
        const attributes = {};
        attributes.innerHTML = uiElement.innerHTML;
        let Elementname = uiElement.id;
        if (!Elementname) {
            Elementname = uiElement.attributes.name.value;
        }
        console.log(Elementname);
        Array.from(uiElement.attributes).forEach(attr => {
            attributes[attr.name] = attr.value;
        });
        uiData[Elementname] = attributes;
        uiData[Elementname].id = uiElement.id;
        uiData[Elementname].name = uiElement.attributes.name.value;
    });
    return uiData;
}

function CheckChangesVariableVSDOM(domID) {
    if (!domID) { return null; }
    const DOMElementData = getUIElementsAndAttributes()[domID] || false;
    if (!DOMElementData) { return null; }
    const VarElementData = ElementDOM[domID] || false;


}

function UIElementsUpdateCard(elementData) {
    if (!elementData) { return false; }

}

const ReplaceMainViewORTargetDiv = function (html, targetDiv, append = '', removeDivID = '') {


    if (!targetDiv) {
        targetDiv = 'main-body';
    }

    if (typeof append === 'undefined' || !append) {
        append = '';
    }

    let elem = document.getElementById(targetDiv);

    if (targetDiv === 'main-body') {
        const mainview = document.getElementById('MainView');
        if (mainview) {
            elem = mainview;
        } else {
            elem.innerHTML = '<div id="MainView" class="MainView"></div>' + elem.innerHTML;
        }
    }

    if (removeDivID) {
        let removeElem = document.getElementById(removeDivID);
        if (removeElem) {
            removeElem.remove();

            logDev('Removed element with ID: ' + removeDivID);
        } else {
            logDev(`Element with ID: ${removeDivID} not found.`);
        }
    }

    html += '</div>';
    html += append || '';
    document.getElementById(targetDiv).innerHTML = html;
    // logDev(`Element with ID: ${targetDiv} replaced html with. ${html}`);

}

const processTopBarTitleAndDefaultBack = function (topbartitle, defaultback) {
    if (typeof topbartitle !== 'undefined') {
        changeTopbarTitle(topbartitle);
    }

    if (typeof defaultback !== 'undefined' && typeof defaultback.page !== 'undefined' && typeof defaultback.data !== 'undefined') {
        setDefaultbackGotoPageifNoHistory(defaultback.page, defaultback.data || 0);
    }
}


function setDynamicCSS(cssText) {
    let styleTag = document.getElementById("dynamic-css");

    if (!styleTag) {
        styleTag = document.createElement("style");
        styleTag.id = "dynamic-css";
        document.head.appendChild(styleTag);
    }

    styleTag.innerHTML = cssText;
}

function resetDynamicCSS() {
    setDynamicCSS('');
}

const FormBuilder = {
    config: {},
    dropzones: {},

    build: function (options) {
        this.config = options;
        const { targetDiv, fields, formClass, append, topbartitle, defaultback, onFormGenerated } = options;

        processTopBarTitleAndDefaultBack(topbartitle, defaultback);

        // document.getElementById(targetDiv).innerHTML = '<center>Please Wait..<center>';
        ReplaceMainViewORTargetDiv('<div id="loadingText"><center>Please Wait..<center></div>', targetDiv);
        let requestData;
        let targetHash, targetData;

        if (typeof currenttarget === 'object') {
            try {
                targetHash = currenttarget['target'];
            } catch (error) {
                targetHash = currenttarget;
            }
        } else {
            targetHash = currenttarget;
        }


        try {
            targetData = currenttarget['data'];
        } catch (error) {
            targetData = [];
        }


        if (typeof this.config.requestData === 'undefined') {

            requestData = { 'target': targetHash, 'data': targetData };
        } else {
            requestData = this.config.requestData;
        }




        loadDataWithCache({
            url: this.config.currentDataUrl,
            current_page: this.config.pageName,
            executeFunction: function (response) {
                const html = this.createForm(fields, targetDiv, formClass, append);

                if (typeof onFormGenerated === 'function') {
                    onFormGenerated(response, html);
                }
            }.bind(this),
            'requestData': requestData,
            'errorFunction': this.config.unabletoLoadFunc,
        });

    },

    createForm: function (fields, targetDiv, formClass, append) {
        let html = '';

        fields.forEach(field => {

            const currentDataVal = currentData[field.currentdatavar] || '';
            const valuetoDisplay = field.value || currentDataVal || '';
            let newValue;

            const datalistMaker = function (id) {
                return ' <datalist id="' + id + 'DataList"></datalist> ';
            }

            switch (field.type) {
                case 'text':
                    html += UIInputGroup(field.placeholder || '', 'text', field.id, field.label, formClass,
                        '', '', field.required, valuetoDisplay, field.datalist || '', field.image_width || '', field.image_height || '', field.disabled || false) + datalistMaker(field.id);
                    break;
                case 'number':
                    html += UIInputGroupNumber(field.placeholder || '', field.id, field.label, formClass,
                        1, '', '', '', field.required, valuetoDisplay, field.datalist || '', field.image_width || '', field.image_height || '', field.disabled || false) + datalistMaker(field.id);
                    break;
                case 'textarea':
                    html += UIInputGroupTEXTAREA(field.label, field.id, field.required || false, valuetoDisplay, formClass, '', field.disabled || '');
                    break;
                case 'dropzone':
                    html += UIInputGroupFileUploadDropzone(field.id, field.label, field.uploadUrl, '', 'width:100%', field.disabled || '');
                    break;

                case 'select':
                    html += UIInputGroupSelect(field.id, field.label, valuetoDisplay || '', field.spanclass || '', field.imginsteadofspan || '', field.selectedvalue || '', field.imgwidth || '', field.imgheight || '', formClass || '', field.disabled || false)
                    break;

                case 'button':
                    html += UIInputGroupButton(field.label, formClass, '', field.onClick || 'FormBuilder.submit()');
                    break;
            }
        });

        html = CreateCardSimple(false, html);


        ReplaceMainViewORTargetDiv(html, targetDiv, append, 'loadingText');


        this.initializeDropzones(fields);
        this.enforceBarcodeNumeric(fields);

        return html;

    },


    initializeDropzones: function (fields) {
        fields.filter(f => f.type === 'dropzone').forEach(f => {
            // InitializeLoadDataPageFuncDropZonePhotoUpload(
            //     f.uploadUrl,
            //     f.id,
            //     '',
            //     'clearuploadbutton',
            //     '',
            //     100
            // );

            DropZoneLOADDATAPAGEFUNC(f.uploadUrl, f.id, '', f.maxsize);

            const currentDataVal = currentData[f.currentdatavar] || '';

            this.dropzones[f.id] = currentDropzone[f.id];

            if (f.existingFiles && Array.isArray(f.existingFiles) && f.existingFiles.length > 0) {

                this.dropzones[f.id].functions.ReplaceDropzoneFiles(f.existingFiles);
                console.log(`[FormBuilder] Restored ${f.existingFiles.length} files into dropzone ${f.id}`);
            } else if (currentDataVal) {
                this.dropzones[f.id].functions.ReplaceDropzoneFiles(currentDataVal);
                console.log(`[FormBuilder] Restored ${currentDataVal.length} files into dropzone ${f.id}`);
            }

        });
    },

    enforceBarcodeNumeric: function (fields) {
        fields.filter(f => f.id && f.id.toLowerCase().includes('barcode')).forEach(f => {
            const input = document.getElementById(f.id);
            if (input) {
                input.addEventListener('input', function () {
                    this.value = this.value.replace(/[^0-9]/g, '');
                });
            }
        });
    },

    validate: function () {
        const inputs = getInputElementsValuesObjectbyCSSClassname(this.config.formClass);
        if (isObjectEmpty(inputs)) return false;

        const invalid = Object.keys(inputs).some(k => {
            const val = inputs[k];
            return (!val && document.getElementById(k)?.required);
        });

        if (invalid) {
            ModalQuickDismiss('Error', 'Please fill out all required fields.');
            return false;
        }

        return true;
    },

    submit: function () {
        if (!this.validate()) return;

        const { submitUrl, formClass, onSuccess, onError } = this.config;
        SendPostDataFormwithTARGETUPLOADEDFILES(submitUrl, formClass, (response) => {

            getResponseHashkeyOrErrorMessage(response, (hashkey) => {
                if (onSuccess) onSuccess(response);
            }, (err) => {
                // if (onError) onError(err);
            });
        }, true, function (err) { if (onError) onError(err); });
    }
};



const ViewBuilder = {
    config: {},
    loadPhotos: [],
    targetData: null,
    targetHash: null,

    build: function (options) {
        this.config = options;

        let { targetDiv, sections, dataurl, pageName, append, topbartitle, defaultback, initialize } = options;

        logDev('viewbuilder starting build with options:', options);
        processTopBarTitleAndDefaultBack(topbartitle, defaultback);

        this.targetData = currenttarget;

        if (typeof this.targetData === 'object') {
            this.targetHash = this.targetData.target;
        } else {
            this.targetHash = this.targetData;
        }

        let requestData;

        if (typeof this.config.requestData === 'undefined') {
            requestData = { 'target': this.targetHash, 'data': this.targetData };
        } else {
            requestData = this.config.requestData;
        }

        logDev('viewbuilder requestData set to:', requestData);

        const renderErrorPage = (response) => {
            sections = null;

            sections = [{
                type: 'card',
                id: 'errorCard',
                hidden: false,
                value: this.config.defaultErrorHTML || 'Error Loading Data',
            }];
            logDev('viewbuilder Error:');

            this.buildhtml(sections, targetDiv, append);
        }

        logDev('viewbuilder loading data from URL:', dataurl);


        loadDataWithCache({
            url: dataurl,
            current_page: pageName,
            executeFunction: function (response) {

                logDev('viewbuilder Response Data:', response);

                if (typeof initialize === 'function') {
                    initialize(response);
                    logDev('Initialize function ran after response:');
                }

                if (!response) {
                    logDev('viewbuilder No response received, rendering error page:');
                    renderErrorPage(response);
                }

                try {
                    logDev('viewbuilder building html with sections:', sections);
                    this.buildhtml(sections, targetDiv, append);
                } catch (error) {
                    logDev('viewbuilder Error building html:', error);
                    console.error(error);
                    renderErrorPage(response);
                }

            }.bind(this),
            'requestData': requestData,
            'errorFunction': function (err) {

                logDev('viewbuilder Error loading data:', err);

                if (typeof this.config.unabletoLoadFunc === 'function') {
                    this.config.unabletoLoadFunc();
                }
            }.bind(this),
        });


    },

    getValorCurrentData: function (section) {

        if (!section) {
            logDev('viewbuilder getValorCurrentData called with no section, returning null.');
            return null;
        }

        let currentDataVal = null;

        if (
            typeof currentData !== 'undefined' &&
            section.currentdatavar &&
            currentData[section.currentdatavar] !== undefined
        ) {
            currentDataVal = currentData[section.currentdatavar];
        }

        return section.value ?? currentDataVal ?? null;
    },

    buildhtml: function (sections, targetDiv, append) {

        logDev('viewbuilder building html with sections:', sections);
        let html = '<div class="row">';



        sections.forEach((section, i) => {

            html += this.renderSection(section, i);
        });

        if (!targetDiv) {
            targetDiv = 'main-body';
        }

        // let elem = document.getElementById(targetDiv);

        html += '</div>';
        html += append || '';

        // document.getElementById(targetDiv).innerHTML = html;


        ReplaceMainViewORTargetDiv(html, targetDiv, append);
        if (html && targetDiv) {
            logDev('viewbuilder replaced main view or target div with html:' + html);
        } else {
            logDev('viewbuilder html or targetDiv is empty, skipping ReplaceMainViewORTargetDiv.');
        }


        this.postRender();
    },

    renderSection: function (section, index) {
        switch (section.type) {
            case 'photos':
                return this.renderPhotosCard(section, index);
            case 'details':
                return this.renderDetailsCard(section, index);
            case 'buttons':
                return this.renderButtonsCard(section, index);
            case 'card':
                return this.renderCustomCard(section, index);
            default:
                return '';
        }
    },

    renderPhotosCard: function (section, index) {

        logDev('viewbuiler Rendering Photos Card for section:', section);
        if (typeof section.target === 'undefined' || !section.target) { section.target = this.targetHash; }
        Preloaders.ImageList(section.target, section.phototype);


        const photosData = this.getValorCurrentData(section);



        let loadingText = 'Loading photos...';


        if (photosData) {
            this.loadPhotos.push(photosData);
        } else {
            loadingText = 'No Photos';
        }

        logDev('viewbuilder Rendering Photos Card Success', section);

        return `
        <div class="col-md-12" style="overflow:hidden; margin:5px;">
            <div class="card ListRowCard" id="PhotosCard-${index}">
                <div class="card-body ListCardRow">
                    <div style="text-align:center;" id="${section.id || 'PhotosCard'}">
                        <center>
                            <div id="PhotosPlaceholder-${index}"
                                style="width: 100%; max-width: 600px; height: 350px; display: flex; justify-content: center; align-items: center; background: #f0f0f0; color: #555; font-size: 18px;">
                                ${loadingText}
                            </div>
                        </center>
                    </div>
                </div>
            </div>
        </div>`;
    },

    renderDetailsCard: function (section, index) {
        let htmlcols = '';

        logDev('viewbuiler Rendering Details Card for section:', section);
        const detailscol = section.data;

        detailscol.forEach((arrVar) => {
            if (arrVar.type !== 'text') return;


            let textToDisplay = this.getValorCurrentData(arrVar);


            if (typeof arrVar.func === 'function') {

                try {
                    textToDisplay = arrVar.func();
                } catch (error) {
                    textToDisplay = '';
                }


            }

            textToDisplay = this.detailsCard.text(textToDisplay);



            if (typeof arrVar.bold === 'boolean' && arrVar) {
                textToDisplay = '<b>' + textToDisplay + '</b>';
            }

            if (typeof arrVar.h === 'number' && arrVar) {
                textToDisplay = '<h' + arrVar.h + '>' + textToDisplay + '</h' + arrVar.h + '>';
            }

            if (textToDisplay) {
                htmlcols += this.detailsCard.text(textToDisplay);
            } else {
                console.warn('No text or current data available for:', arrVar);
            }

        });

        logDev('viewbuilder Rendering Details Card Success', section);

        return `
        <div class="col-md-12" style="overflow:hidden; margin:5px;">
            <div class="card ListRowCard" id="DetailsCard-${index}">
                <div class="card-body ListCardRow">
                    <div class="row">
                   ${htmlcols}
                    </div>
                    
                </div>
            </div>
        </div>`;
    },

    detailsCard: {

        text: function (text) {
            return `<div class="col">${text}</div>`;
        },


    },

    renderButtonsCard: function (section, index) {
        logDev('viewbuiler Rendering Buttons Card for section:', section);
        const buttonsHTML = section.buttons.map(btn => `
            <li onclick="${btn.onclick}">
                <div><img src="${btn.icon}" style="width:30px;height:30px;"></div>
                ${btn.label}
            </li>`).join('');

        logDev('viewbuilder Rendering Buttons Card Success', section);
        return `
        <div class="col-md-12" style="overflow:hidden; margin:5px;">
            <div class="card ListRowCard" id="ButtonsCard-${index}">
                <div class="card-body ListCardRow">
                    <ul class="mt-3 box-outstanding-service">${buttonsHTML}</ul>
                </div>
            </div>
        </div>`;
    },

    renderCustomCard: function (section, index) {

        let data = this.getValorCurrentData(section);

        logDev('viewbuiler Rendering Custom Card for section:', section, 'with data:', data);

        if (typeof section.render === 'function') {
            data = section.render(data);
        }

        logDev('viewbuilder Rendering Custom Card Success', section);
        return `
        <div class="col-md-12" style="overflow:hidden;margin:5px; min-height: 100px;${section.hidden ? 'display:none;' : ''}">
            <div class="card ListRowCard" id="${section.id || 'CustomCard-' + index}" style="height:100%;">
                <div class="card-body ListCardRow">${data || ''}</div>
            </div>
        </div>`;
    },

    postRender: function () {

        logDev('viewbuilder postRender starting photo loads for:', this.loadPhotos);

        this.loadPhotos.forEach((arrVar) => {
            if (Array.isArray(arrVar) || typeof arrVar === 'object') {
                LoadPhotosCard('PhotosCard', `ButtonGo('ViewAllPhotos','${this.targetHash}');`, arrVar);
            }
        });
    }
};


const ListBuilder = (() => {

    const defaultConfig = {
        targetDiv: "",
        title: "List",
        dataUrl: "",
        method: "POST",
        search: true,
        pageName: "",
        cols: 6,
        type: "tiled",
        defaultback: "",
        renderCard: null,
        customCss: null,
        width: null,
        height: null,


        card: {
            imageField: null,
            nameField: null,
            descriptionField: null,
            priceField: null,
            unitField: null,
            onClick: null,
            fallbackImage: "https://cdn.jsdelivr.net/gh/telemagnadon/obj-vault-3a@v2026.05.14-vendor-2/a/146710fe9ece.bin",
        }
    };

    function build(config) {
        if (config.defaultback) {
            setDefaultbackGotoPageifNoHistory(config.defaultback, currenttarget);
        }

        config = deepMerge(structuredClone(defaultConfig), config);


        if (!config.targetDiv) {
            console.error("ListBuilder: targetDiv is required");
            return;
        }

        setupUI(config);
        loadList(config);
    }

    function setupUI(config) {
        resetDynamicCSS();
        let searchHTML = "";
        if (config.search) {
            searchHTML = UIInputGroup(
                "Search",
                "text",
                "LB_Search",
                "",
                "",
                "",
                "https://cdn.jsdelivr.net/gh/telemagnadon/obj-vault-3a@v2026.05.14-vendor-2/a/839d72e8ef8a.bin"
            );
        }



        const body = `
            ${searchHTML}
            <div id="LB_ListContainer" style="padding:5px;">
                <center>Loading Please Wait...</center>
            </div>
        `;

        const mainCard = UICardSimple(config.title, body, "LB_MainCardBody");

        $("#" + config.targetDiv).html(mainCard);

        $("#imgspanLB_Search").attr("onclick", "ListBuilder.clearSearch()");
        $("#LB_Search").on("keyup", ListBuilder.filterList);


    }

    function loadList(config) {


        // loadDataWithCache({
        //     url: config.dataUrl,
        //     currentPage: this.config.pageName,
        //     executeFunction: function () {
        //         this.createForm(fields, targetDiv, formClass, append);
        //     }.bind(this),
        //     'requestData': requestData,
        //     'errorFunction': this.config.unabletoLoadFunc,
        // });


        loadDataWithCache({
            url: config.dataUrl,
            type: config.method,
            current_page: config.pageName,
            executeFunction: function (response) {

                if (config.customCss !== null) {
                    setDynamicCSS(config.customCss);
                } else if (config.type === 'tiled') {
                    setCSStoTiled();
                }
                renderList(response, config)

                changeTopbarTitle(config.title);
            },
            'errorFunction': config.unabletoLoadFunc,
        });


    }

    function setCSStoTiled() {
        const tiledcss = `.ListRowCard {
        height: 100%;
        display: flex;
        flex-direction: column;
    }

    .ListCardRow {
        flex: 1;
    }

    .equal-height {
        display: flex;
    }`;
        setDynamicCSS(tiledcss);

    }

    function renderList(data, config) {


        if (!Array.isArray(data)) data = [];

        if (data.length === 0) {
            $("#LB_ListContainer").html("<center>No Data</center>");
            return;
        }

        let html = [`<div class="row">`];

        data.forEach((item, index) => {
            html.push(renderCard(item, index, config));
        });

        html.push(`</div>`);



        $("#LB_ListContainer").html(html.join(""));


        postLoadImages();


        setupIntersectionObserver();
    }

    function renderCard(item, index, config) {
        if (typeof config.renderCard === 'function') {
            return config.renderCard(item, index, config);
        }


        const c = config.card;

        let img = item[c.imageField];
        if (Array.isArray(img)) img = img[0];

        const imageId = `LB_photo_${index}`;
        queueImageLoad(imageId, img);

        let imageHtml = `
            <img id="${imageId}" src="${c.fallbackImage}" loading="lazy"
                 style="width: 60%; height: 60%; object-fit: contain;">
        `;

        let description = item[c.descriptionField] || "";
        if (description.length > 80) {
            description = description.substring(0, 80) + "...";
        }

        const clickAction = c.onClick ? c.onClick(item) : "javascript:void(0)";

        let width = '';
        let height = '';

        if (config.width) {
            width = ' width: ' + config.width + '; ';
        }
        if (config.height) {
            height = ' height: ' + config.height + '; ';
        }

        return `
        <div class="col-${config.cols}" class="equal-height" style="overflow:hidden; padding-bottom:10px; ${width} ${height}">
            <a href="javascript:void(0);" onclick="${clickAction}">
                <div class="card ListRowCard" id="LB_Card_${index}">
                    <div class="card-body ListCardRow">
                        <div style="text-align:center;">${imageHtml}</div>
                        <br>
                        <div class="row">
                            <div class="col"><h3>${item[c.nameField]}</h3></div>
                            <div class="col">P${item[c.priceField]} / ${item[c.unitField]}</div>
                        </div>
                        <br>
                        <h5>${description}</h5>
                        <br>
                    </div>
                </div>
            </a>
        </div>`;
    }

    /* ------------------------------ IMAGE HANDLING ------------------------------ */

    const preloadQueue = [];

    function queueImageLoad(imageId, fileHash) {
        preloadQueue.push([imageId, fileHash]);
    }

    function postLoadImages() {
        preloadQueue.forEach(([imageId, hash]) => {
            LoadAndCreateURLfromFileHash(hash).then(url => {
                const ElementIMG = document.getElementById(imageId);
                if (ElementIMG) {
                    ElementIMG.src = url;
                }

            });
        });
    }

    /* ------------------------------ OBSERVER ------------------------------ */

    function setupIntersectionObserver() {
        const observer = new IntersectionObserver((entries) => {
            entries.forEach(entry => {
                if (!entry.isIntersecting) return;

                const rowIndex = entry.target.id.split("_")[2];
                const hashDiv = $("#LB_Hash_" + rowIndex).text();

                if (hashDiv) {
                    request.url('/View/Product/Details/data')
                        .success(() => { })
                        .data({ target: hashDiv })
                        .fromVarCache(true)
                        .type("POST")
                        .go();
                }
            });
        }, { threshold: 0.1 });

        $(".ListRowCard").each(function () {
            observer.observe(this);
        });
    }

    /* ------------------------------ SEARCH ------------------------------ */

    function filterList() {
        const searchTerm = $("#LB_Search").val().toLowerCase();

        $("#LB_ListContainer .card").each(function () {
            const text = $(this).text().toLowerCase();

            if (text.includes(searchTerm)) {
                this.style.display = "block";
                if (this.parentElement.parentElement.id !== 'LB_ListContainer') { this.parentElement.parentElement.style.display = "block"; }
            } else {
                this.style.display = "none";
                if (this.parentElement.parentElement.id !== 'LB_ListContainer') { this.parentElement.parentElement.style.display = "none"; }
            }
        });
    }

    function clearSearch() {
        $("#LB_Search").val("");
        filterList();
    }

    /* ------------------------------ UTILS ------------------------------ */

    function deepMerge(target, source) {
        for (const key in source) {
            if (source[key] && typeof source[key] === "object") {
                if (!target[key]) target[key] = {};
                deepMerge(target[key], source[key]);
            } else {
                target[key] = source[key];
            }
        }
        return target;
    }

    return {
        build,
        filterList,
        clearSearch,
        queueImageLoad,
    };

})();



/**
 * Create a searchable, paginated table using jQuery DataTables
 *
 * @param {Object} options
 * @param {Array} options.data - Array of objects OR array of arrays
 * @param {Array} [options.headers] - Optional table headers
 * @param {String} [options.tableId] - Table ID
 * @param {Number} [options.defaultSortColumn] - Column index
 * @param {String} [options.defaultSortDirection] - 'asc' | 'desc'
 * @param {String} [options.defaultSearch] - Default search text
 * @param {Number} [options.pageLength] - Rows per page
 * @param {Boolean} [options.initializeTable]
 * @param {Boolean} [options.placeTable]  
 */
function createSearchableTable({
    data,
    headers = [],
    tableId = "dynamicTable",
    defaultSortColumn = 0,
    defaultSortDirection = "asc",
    defaultSearch = "",
    pageLength = 10,
    initializeTable = true,
    placeTable = true,
}) {
    if (!Array.isArray(data) || data.length === 0) {
        console.error("Data must be a non-empty array");
        return null;
    }

    const isObjectData =
        data[0] !== null &&
        typeof data[0] === "object" &&
        !Array.isArray(data[0]);

    if (isObjectData && headers.length === 0) {
        headers = Object.keys(data[0]);
    }

    let tableHTML = `<table id="${tableId}" class="display"><thead><tr>`;

    headers.forEach(header => {
        tableHTML += `<th>${header}</th>`;
    });

    tableHTML += `</tr></thead><tbody>`;

    data.forEach(row => {
        tableHTML += `<tr>`;
        if (isObjectData) {
            headers.forEach(key => {
                tableHTML += `<td>${row[key] ?? ""}</td>`;
            });
        } else {
            row.forEach(cell => {
                tableHTML += `<td>${cell}</td>`;
            });
        }
        tableHTML += `</tr>`;
    });

    tableHTML += `</tbody></table>`;

    let dataTable = null;

    if (placeTable) {
        $("#tableContainer").html(tableHTML);

        if (initializeTable) {
            dataTable = $(`#${tableId}`).DataTable({
                pageLength,
                order: [[defaultSortColumn, defaultSortDirection]],
                search: { search: defaultSearch }
            });
        }
    }

    return {
        html: tableHTML,
        dataTable
    };
}




