/*!
 * Thorium JSON API functions for framework7 projects
 * Version 4.0 january 2024
 * framework7 v8.x (https://framework7.io) MIT Licensed
 * Thorium builder © Copyright 2018-2024 Nymphide Lab, All Rights Reserved.
*/

var jsonApiPlugin = {
    name: "Thorium Builder JSON API Plugin",
    bundleid: "com.thoriumbuilder.jsonapi",
    version: "4.0",
    currentRepeaterId: null,
    currentDisplayerId: null,
    dataset : null,
    currentKey: null,
    currentData: null,
    parseDataRecursive: function (prop, data, item) {
        thoriumapi.logEvent(0, "[com.thoriumbuilder.jsonapi] Parsing Data ");
        for (var prop in data) {
            if (typeof data[prop] == "object" && data[prop] !== null) {
                if (Array.isArray(data[prop])) {
                    var p = prop.replaceAll(" ", "_");
                    item[p] = data[prop];
                } else {
                    jsonApiPlugin.parseDataRecursive(prop, data[prop], item);
                }
            } else {
                var p = prop.replaceAll(" ", "_");
                item[p] = data[prop];
            }
        }
        return item;
    },
    initDisplayerMap: function (field, lat, lng) {
        if ((!lat) || (!lng)) {
            field.style.display = 'none';
            return;
        }
        var engine = field.getAttribute("data-engine") || null;
        if ((!engine) && (typeof openStreetMapPlugin !== 'undefined')) {
            engine = "osm";
        } else if ((!engine) && (typeof googleMapPlugin !== 'undefined')) {
            engine = "googlemap";
        }
        thoriumapi.logEvent(0, "[com.thoriumbuilder.dbexpress.maps] Loading Displayer Map with Engine [" + engine + "]");
        if ((engine == 'osm') && (typeof openStreetMapPlugin !== 'undefined')) {
            var map = openStreetMapPlugin.initMap(field.id);
            if (map) {
                var item = {};
                item.latitude = lat;
                item.longitude = lng;
                item.name = lat + ";" + lng;
                openStreetMapPlugin.addMarkerAt(map, lat, lng, item);
                map.panTo(new L.LatLng(lat, lng));
            }
        } else if ((engine == 'googlemap') && (typeof googleMapPlugin !== 'undefined')) {
            googleMapPlugin.initializeMap(field.id);
            var LatLng = new google.maps.LatLng(parseFloat(lat), parseFloat(lng));
            googleMapPlugin.addMarker(field.map, LatLng, lat + ";" + lng);
            field.map.setCenter(LatLng);
        }
    },
    setGeoPointMapContent: function(map,data) {
        var latFld = map.getAttribute("data-latitude") || null;
        var lngFld = map.getAttribute("data-longitude") || null;
        var geopointFld = map.getAttribute("data-geopoint") || null;                  
        if ((!latFld) || (!lngFld)) {
            if ( (geopointFld) && (geopointFld.length>0) ) {
                var c=data[geopointFld];
                if ((c) && (c.length>0)) {
                    const ar = c.replaceAll("{","").replaceAll("}","").split(",");
                    if (ar.length==2) {
                        jsonApiPlugin.initDisplayerMap(map, ar[0],  ar[1]);
                    } else {
                        map.style.display = 'none';
                    }
                } else {
                    map.style.display = 'none';
                }
            } else {
                map.style.display = 'none';
            }                       
        } else {
            var latValue = data[latFld];
            var lngValue = data[lngFld];
            if ((latValue) && (lngValue)) {
                jsonApiPlugin.initDisplayerMap(map, latValue, lngValue);
            } else {
                map.style.display="none";
            }
        }
    },
    setDisplayerDataContent: function (form, data) {
        if (!data) {
            thoriumapi.logEvent(1, "[com.thoriumbuilder.jsonapi] unable to set Displayer contents, undefined data");
            return;
        }
        thoriumapi.logEvent(0, "[com.thoriumbuilder.jsonapi] Set Content for Displayer with ID [" + form.id + "]");
        $("#" + form.id + " [data-json-value]").each(function (jsonfield) {
            var tag = jsonfield.tagName.toLowerCase();
            var c = jsonfield.className.toLowerCase();
            var fld = jsonfield.getAttribute("data-json-value");
            var dataValue = "";
            dataValue = data[fld];
            thoriumapi.logEvent(0, "[com.thoriumbuilder.jsonapi] Set Content for field [" + fld + "]");
            if ((["embed-responsive-item"].indexOf(c) > -1) && (tag != "audio") && (tag != "video")) {
                var root = jsonfield.getAttribute("data-httproot") || '';
                if (dataValue) {
                    jsonfield.style.backgroundImage = "url('" + root + dataValue + "')";
                } else {
                    jsonfield.closest('.embed-responsive').style.display = 'none';
                }
            } else if ((["source"].indexOf(tag) > -1) || (tag == "audio") || (tag == "video")) {
                var root = jsonfield.getAttribute("data-httproot") || '';
                if (dataValue) {
                    jsonfield.setAttribute("src", root + dataValue);
                }
                else {
                    jsonfield.style.display = 'none';
                }
            } else if (tag == "img") {
                if (dataValue) {
                    var root = jsonfield.getAttribute("data-httproot") || '';
                    jsonfield.setAttribute("src", root + dataValue);
                } else {
                    jsonfield.setAttribute("src", "img/defaultimg.png");
                }
            } else {
                if (dataValue) {
                    var lh = jsonfield.innerHTML;
                    if ((lh) && (fld)) { jsonfield.innerHTML = lh.replaceAll("{" + fld + "}", dataValue); }
                    if (tag == "a") {
                        lh = jsonfield.getAttribute("href");
                        if (lh) {
                            lh = lh.replaceAll("{" + fld + "}", dataValue);
                            jsonfield.setAttribute("href", lh);
                        }
                    }
                } else {
                    jsonfield.style.display = 'none';
                }
            }
        });
        //Map Geopoint View
        var m=form.querySelector(".jsonapi-geopoint-map");
        if (m) {
            jsonApiPlugin.setGeoPointMapContent(m,data);
        }

        form.setAttribute("data-loaded", true);
        $("#" + form.id).show();
        app.emit('jsonDisplayerInitialized', form, data);

        app.emit('displayerDataLoaded[#'+form.id+']',form,data);

        app.preloader.hide();
    },

    getRepeaterTemplate: function (r) {
        thoriumapi.logEvent(0, "[com.thoriumbuilder.jsonapi] Get Template for Repeater with ID [" + r.id + "]");
        var oh = r.outerHTML;
        r.style.display = null;
        $("#" + r.id + " .json-field p, .json-field .text-link").each(function (item) {
            var fld = item.getAttribute('data-json-value') || '';
            var tag = item.tagName.toLowerCase();
            var lh = item.innerHTML;
            if ((lh) && (fld)) { item.innerHTML = lh.replaceAll("{" + fld + "}", "{{" + fld + "}}"); }
            if (tag == "a") {
                lh = item.getAttribute("href");
                if ((lh) && (fld)) {
                    lh = lh.replaceAll("{" + fld + "}", "{{" + fld + "}}");
                    item.setAttribute("href", lh);
                }
            }
        });
        $("#" + r.id + " .json-field img,video,source").each(function (item) {
            var fld = item.getAttribute('data-json-value') || '';
            var root = item.getAttribute('data-httproot') || '';
            item.setAttribute('src', root + "{{" + fld + "}}");
        });
        $("#" + r.id + " .json-field .embed-responsive-item").each(function (item) {
            var fld = item.getAttribute('data-json-value') || '';
            var root = item.getAttribute('data-httproot') || ''
            item.setAttribute('style', "background-image:url('" + root + "{{" + fld + "}}') , url('img/defaultimg.png')");
        });
        r.removeAttribute("id");
        r.removeAttribute("data-template-height");
        r.classList.remove("templaterow");
        var t = r.outerHTML;
        r.outerHTML = oh;
        return t;
    },

    getCollectionRow: function (root, data, template) {
        thoriumapi.logEvent(0, "[com.thoriumbuilder.jsonapi] Get Collection Rows");
        for (var prop in data) {
            if (typeof data[prop] == "object" && data[prop] !== null) {
                if (!(Array.isArray(data[prop]))) {
                    var p;
                    if (root.length > 0) { p = root + "." + prop; } else { p = prop; }
                    template = jsonApiPlugin.getCollectionRow(p, data[prop], template);
                }
            } else {
                var p;
                if (root.length > 0) { p = root + "." + prop; } else { p = prop; }
                if (p) {
                    p = p.replaceAll(" ", "_");
                    var v = data[prop];
                    if ((!v) && (v != 0)) { v = ''; }
                    template = template.replaceAll("{{" + p + "}}", v);
                    template = template.replaceAll("{" + p + "}", v);
                }
            }
        }
        return template;
    },

    flattenObj: function(ob){
        var toReturn = {};
        for (var i in ob) {
            if (!ob.hasOwnProperty(i)) continue;
            const elt= ob[i];
            if ((typeof elt) == 'object') {
                toReturn[i]=elt;
                var flatObject = jsonApiPlugin.flattenObj(elt);
                for (var x in flatObject) {
                    if (!flatObject.hasOwnProperty(x)) continue;
                    toReturn[i + '.' + x] = flatObject[x];
                }
            } else {
                toReturn[i] = elt;
            }
        }
        return toReturn;
    },


    setRepeaterDataContent: function (field, items) {
        var displayMode = field.getAttribute("data-displaymode") || 0;
        var templateRef = document.getElementById('template-' + field.id);
        var t;
        if (!(templateRef)) {
            t = $('#' + field.id).data("template");
            if ((!t) || (t.length == 0)) {
                thoriumapi.logEvent(1, "[com.thoriumbuilder.jsonapi] No Template found for object with ID [" + field.id + "]");
                $("#" + field.id).hide();
                return;
            }
        }
        /*- get template html --*/
        if ((!t) || (t.length == 0)) {
            if (displayMode != 1) {
                t = jsonApiPlugin.getRepeaterTemplate(templateRef);
            } else {
                t = templateRef.outerHTML;
            }
            $('#' + field.id).data("template", t);
        }
        if (displayMode != "1") { /*Virtual List*/
            var flatresult=[];
            for (const [item, value] of Object.entries(items)) {
                var flatItems =jsonApiPlugin.flattenObj(value);
                flatresult.push(flatItems);
            }
            thoriumCorePlugin.virtuallist.renderVirtualListFromData(field, flatresult, t);
        }
        else { /*Collection*/
            if (items.length > 0) {
                thoriumapi.logEvent(0, "[com.thoriumbuilder.jsonapi] Render Collection for Repeater with ID [" + field.id + "]");
                $("#" + field.id).data('items', items);
                var dataroot = field.parentNode.getAttribute("data-img-root") || '';
                var i = 0;
                //Flatten items
                var itemhtml;
                for (var item in items) { //Loop Results
                    itemhtml = jsonApiPlugin.getCollectionRow('', items[item], t);
                    itemhtml = itemhtml.replace("url({data-img-root})", "url(./img/defaultimg.png)");
                    itemhtml = itemhtml.replaceAll("templaterow", "");
                    itemhtml = itemhtml.replaceAll('template-' + field.id, 'template-' + field.id + "-" + i);
                    itemhtml = itemhtml.replaceAll("{data-img-root}", dataroot);
                    itemhtml = itemhtml.replaceAll("'" + dataroot + "'", "./img/defaultimg.png");
                    field.innerHTML = field.innerHTML + itemhtml;
                    i = i + 1;
                }
                field.setAttribute("data-loaded", true);
                field.setAttribute("data-count", items.length);
                //check if has search bar
                var sb=document.querySelector(".searchbar[data-search-container='#"+field.id+"']");
                if (sb) {
                    var sbi=app.searchbar.get(sb);
                    if (sbi) {
                        app.searchbar.destroy(sb);
                    }
                    sbi=app.searchbar.create({
                        el: sb,
                        customSearch: true,
                        removeDiacritics: true,
                        on: {
                          search: function (e) {
                            var x = field.querySelectorAll(".collection-item ");
                            for (var i = 0; i < x.length; i++) {
                                var elt = x[i];
                                if (elt.innerText.toLowerCase().includes(e.query.toLowerCase()) ) {
                                    elt.classList.remove("hidden");
                                } else {
                                    elt.classList.add("hidden");
                                }
                            }
                          }
                        }
                    })
                }
            }
        }
        var parentRepeater=field.closest(".json-virtual-list") || null;
        app.emit('jsonRepeaterInitialized', parentRepeater, items);
        
        app.emit('repeaterDataLoaded[#'+parentRepeater.id+']',parentRepeater,items);
        
    },

    getChildrenProperty: function (object, n) {
        var r;
        for (var property in object) {
            if (property == n) {
                r = object[property];
                break;
            }
            else if (object.hasOwnProperty(property) && (!(r))) {
                if (typeof object[property] == "object" && object[property] !== null) {
                    r = jsonApiPlugin.getChildrenProperty(object[property], n);
                }
            }
            if (r) { break; }
        }
        if (r != null) { return r; }
    },
    getRepeaterData: function (field, source, root, nocache) {
        nocache = nocache || false;
        var url = "";
        var items = [];
        url = source;
        var vl = $("#" + field.id);
        if (!(vl)) { return; }
        var ref = app.virtualList.get(vl);
        if (ref) {
            app.virtualList.destroy(ref);
        }
        thoriumapi.logEvent(0, "[com.thoriumbuilder.jsonapi] Get data for Repeater with ID [" + field.id + "] from url [" + url + "]");
        var ctnr = vl.closest('.page-content');
        if (ctnr) {
            app.preloader.hide();
            if (kShowPreloader==true) {app.preloader.showIn(ctnr);}
            setTimeout(function () { if (ctnr) { app.preloader.hideIn(ctnr); } }, 4000);
        };
        jsonApiPlugin.currentRepeaterId = null;
        if (field) {
            var rpt = field.closest(".json-virtual-list");
            if (rpt) { jsonApiPlugin.currentRepeaterId = rpt.id }
        }
        var options = {};
        var headers = {};
        var hasheader = false;
        //API Options Stored Data
        var api_method=field.getAttribute("data-api-method")||'get';
        var api_referrer=field.getAttribute("data-api_referrer")||'';
        var api_referrerpolicy=field.getAttribute("data-api-referrerpolicy")||'';
        var api_mode=field.getAttribute("data-api-mode")||'';
        var api_cache=field.getAttribute("data-api-cache")||'';
        var api_credentials=field.getAttribute("data-api-credentials")||'';
        var api_redirect=field.getAttribute("data-api-redirect")||'';
        //API Headers Stored Data
        var api_contenttype=field.getAttribute("data-api-contenttype")||'application/json';
        var api_accept=field.getAttribute("data-api-accept")||'application/json';
        var api_authorization=field.getAttribute("data-api-authorization")||'';
        var api_header_key=field.getAttribute("data-api-header_key")||'';
        var api_header_value=field.getAttribute("data-api-header_value")||'';

        options["method"] = api_method;
        if (api_referrer.length > 0) { options["referrer"] = api_referrer;}
        if (api_referrerpolicy.length > 0) { headers["referrerpolicy"] = api_referrerpolicy; }
        if (api_mode.length > 0) { options["mode"] = api_mode; }
        if (api_cache.length > 0) { options["cache"] = api_cache; }
        if (api_credentials.length > 0) { options["credentials"] = api_credentials; }
        if (api_redirect.length > 0) { headers["redirect"] = api_redirect;}
        /* header */
        headers["Content-Type"] = api_contenttype;
        headers["Accept"] = api_accept;
        if (api_authorization.length > 0) { 
            headers["Authorization"] = thoriumapi.replaceDynamicVariables(api_authorization);
        }
        options["headers"] = headers;

        
        // var token="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0eXBlIjoidXNlckF1dGgiLCJ1c2VySWQiOiI2NWU4ODMyN2ZkNDJiZjAwMWM2ZWM5NWQiLCJleHAiOjE3MDk5MjAyNzksImlhdCI6MTcwOTkxNjY3OX0.tfmkDdjjdiRt1o9pXzTQJjpwb_Wm5i33PaHwXKaK58c";
        // headers["Accept"] = 'application/json';
		// headers["Content-type"] = "application/json";
        // headers["Authorization"] = `JWT ${token}`;
        // hasheader = true;

        // if (hasheader == true) {
        //     options["headers"] = headers;
        // }

        /* -- new callback before call --*/
        var fn = window["callback_repeater_before_load"];
        var fnparams = [options];
        if (typeof fn === "function") {
            options = fn.apply(this, fnparams);
        }

        var dummyParam=field.getAttribute("data-dummy-param")||null;
        if ( (dummyParam) && (dummyParam == "true")) {
            var rnd = Math.floor(Date.now() / 1000);
            if (url.indexOf("?") == -1) {
                url = url + "?rnd=" + rnd;
            } else {
                url = url + "&rnd=" + rnd;
            }
        }
        //Dynamic variables
        url=thoriumapi.replaceDynamicVariables(url);
       
        fetch(url, options)
        .then(function (response) {
            for (var pair of response.headers.entries()) {
                console.log("[com.thoriumbuilder.core] fetch api returned headers " + pair[0]+ ': '+ pair[1]);
                thoriumapi.logEvent(0, "[com.thoriumbuilder.core] fetch api returned headers " + pair[0]+ ': '+ pair[1]);
            }
            response.text()
                .then(txt => {
                    thoriumapi.logEvent(0, "[com.thoriumbuilder.jsonapi] Got Response from url [" + url + "]");
                    if (txt.length == 0) {
                        thoriumapi.logEvent(1, "[com.thoriumbuilder.jsonapi] Empty Result. Maybe a CORS issue. Status [" + response.status + "] :" + response.statusText);
                        field.classList.remove('loadingdata');
                        if (ctnr) { app.preloader.hideIn(ctnr) };
                        return;
                    }
                    var data;
                    try {
                        data = JSON.parse(txt);
                    } catch (err) {
                        thoriumapi.logEvent(2, "[com.thoriumbuilder.jsonapi] Error "+err.code+" "+ err.message+". Returned Result: "+txt );
                        app.emit('jsonDataloadError', $(this), err);
                        if (ctnr) { app.preloader.hideIn(ctnr) };
                        app.dialog.alert(err.message + " " + txt);
                        return;
                    }
                    /* -- new callback after data loaded call V4 --*/
                    var fname=field.getAttribute("data-function")||null;
                    if (fname) {
                        var fn = window[fname];
                        var fnparams = [data];
                        if (typeof fn === "function") {
                            data = fn.apply(this, fnparams);
                        }
                    }
                    if (!data) {
                        if (ctnr) { app.preloader.hideIn(ctnr) };
                        app.preloader.hide();
                        thoriumapi.logEvent(1, "[com.thoriumbuilder.jsonapi] Empty Dataset: "+txt ); 
                        return;
                    }
                    var i = 0;
                    var item = {};
                    var myItems;
                    if ((typeof data == "object") && (root)) {
                        myItems = jsonApiPlugin.getChildrenProperty(data, root);
                    } else {
                       if (data) {
                        if (!(root)) { myItems = data; } else { myItems = data[root]; }
                       }
                    }
                    if (myItems) {
                        for (var prop in myItems) {
                            item = myItems[prop];
                            item["dataindex"] = i;
                            i = i + 1;
                            items.push(item);
                        }
                    } else {
                        if (Object.keys(data).length>0) {
                         thoriumapi.logEvent(2, "[com.thoriumbuilder.jsonapi] "+root+"is an invalid Root name"); 
                          app.dialog.alert(root+" is an invalid Root name (returned result: "+txt+")") ;
                        } else {
                          thoriumapi.logEvent(1, "[com.thoriumbuilder.jsonapi] Invalid Result: "+txt ); 
                        }                       
                    }
                    jsonApiPlugin.setRepeaterDataContent(field, items);
                    app.emit('jsonDataloadSuccess', $(this), field, items);
                    if (ctnr) { app.preloader.hideIn(ctnr) };
                    app.preloader.hide();
                })
                .catch(function (err) {
                    app.preloader.hide();
                    thoriumapi.logEvent(2, "[com.thoriumbuilder.jsonapi] " + err.message);
                    field.classList.remove('loadingdata');
                    $("#" + field.id).hide();
                    app.dialog.alert(err.message);
                });
        }).catch(function (err) {
            app.preloader.hide();
            thoriumapi.logEvent(2, "[com.thoriumbuilder.jsonapi] " + err.message);
            if (ctnr) { app.preloader.hideIn(ctnr) };
            $("#" + field.id).hide();
            app.emit('jsonDataloadError', $(this), err);
            if (app.online == false) {
                thoriumapi.showNotification("Internet connection lost");
            } else {
                app.dialog.alert(err.message);
            }
        });
    },
    reloadRepeater : function(id) { //New V4
        var r=document.getElementById(id);
        if (id) {
            var virtualList = r.querySelector(".json-virtual-list-content");
            if (virtualList) {
                var source = virtualList.getAttribute('data-source') || null;
                if (source == "js/json/") { source = null; }
                if ((jsonApiPlugin.currentKey) && (source)) { source = source.replaceAll("{key}", jsonApiPlugin.currentKey); }
                var root =virtualList.getAttribute('data-root-field') || null;
                if (source) {
                    jsonApiPlugin.getRepeaterData(virtualList, source, root, true);
                }
            }
        }
    },
    initAllRepeaters: function (key, nocache) { //OK JS
        nocache = nocache || false;
        thoriumapi.logEvent(0, "[com.thoriumbuilder.jsonapi] Checking Repeaters State");
        var x = document.querySelectorAll(".json-virtual-list-content");
        for (var i = 0; i < x.length; i++) {
            var virtualList = x[i];
            if (virtualList.getAttribute("data-loaded") != "true") {
                var source = virtualList.getAttribute('data-source') || null;
                if (source == "js/json/") { source = null; }
                if ((key) && (source)) { source = source.replaceAll("{key}", key); }
                var root =virtualList.getAttribute('data-root-field') || null;
                if (source) {
                    jsonApiPlugin.getRepeaterData(virtualList, source, root, nocache);
                    const element = document.querySelector("#view-main"); 
                    if (element) {element.style.display=true;}
                }
            }
        }
        if ((!x) || (x.length==0)) {
            app.preloader.hide();
        }
    },

    handleFetchError: function(errcode,errmessage,url,sender)  {
        thoriumapi.logEvent(2, "[com.thoriumbuilder.jsonapi] url [" + url + "] returned [" + errmessage + "] ");
        app.emit('jsonDataloadError', sender, errmessage);
        if (app.online == false) {
            thoriumapi.showNotification("Internet connection lost");
        }
        app.dialog.alert(errmessage);
    },
    
    getDisplayerData: function (extapi, key, form) {
        form.style.opacity=0;
        var url = extapi.replaceAll("{key}", key);
        thoriumapi.logEvent(0, "[com.thoriumbuilder.jsonapi] Get Displayer Data from url [" + url + "]");
        var options = {};
        var headers = {};
        var hasheader = false;
        options["method"] = "GET";
        if (kMode.length > 0) { options["mode"] = kMode; }
        if (kCache.length > 0) { options["cache"] = kCache; }
        if (kCredentials.length > 0) { options["credentials"] = kCredentials; }
        if (kContenttype.length > 0) { headers["Content-Type"] = kContenttype; hasheader = true; }
        if (kRedirect.length > 0) { headers["redirect"] = kRedirect; hasheader = true; }
        if (kReferrerpolicy.length > 0) { headers["referrerpolicy"] = kReferrerpolicy; hasheader = true; }
        if (kAuthorization.length > 0) { headers["Authorization"] = kAuthorization; hasheader = true; }
        if (hasheader == true) {
            options["headers"] = headers;
        }
        jsonApiPlugin.currentDisplayerId = null;
        if (form) {
            jsonApiPlugin.currentDisplayerId = form.id;
        }
        /* -- new callback before call --*/
        var fn = window["callback_displayer_before_load"];
        var fnparams = [options];
        if (typeof fn === "function") {
            options = fn.apply(this, fnparams);
        }

        //Dynamic variables
        url=thoriumapi.replaceDynamicVariables(url);

        fetch(url, options)
            .then(
                function (response) {
                    if (response.status !== 200) {
                        jsonApiPlugin.handleFetchError(response.status,"Invalid Server Response",url,form);
                        return;
                    }
                    else {
                        response.text()
                            .then(txt => {
                                var data;
                                try {
                                    data = JSON.parse(txt);
                                } catch (err) {
                                    jsonApiPlugin.handleFetchError(err.errcode,err.message,url,form);
                                    return;
                                }
                                var item = {};
                                for (var prop in data) {
                                    if (typeof data[prop] == "object" && data[prop] !== null) {
                                        item = jsonApiPlugin.parseDataRecursive(prop, data[prop], item);
                                    } else {
                                        var p = prop.replaceAll(" ", "_");
                                        item[p] = data[prop];
                                    }
                                }
                                thoriumapi.logEvent(0, "[com.thoriumbuilder.jsonapi] Data loaded from url [" + url + "]");
                                app.emit('jsonDataloadSuccess', $(this), form, item);
                                jsonApiPlugin.setDisplayerDataContent(form, item);
                                $('#' + form.id).data('item', item);
                                form.style.opacity=0;
                                $('#' + form.id).show();
                                form.style.opacity=1;
                            })
                            .catch(function (err) {
                                jsonApiPlugin.handleFetchError(err.errcode,err.message,url,form);
                            });
                    }
                }).catch(function (err) {
                    jsonApiPlugin.handleFetchError(err.errcode,err.message,url,form);
                });
    },
    repeaterDblLineClick: function (e, t) {
        var rowindex = t.attr('data-index') || null;
        var datakey = t.attr('data-key') || null;
        if (rowindex) {
            thoriumapi.logEvent(0, "[com.thoriumbuilder.jsonapi] Detect Double Click/Touch on line [" + rowindex + "]");
            var o = t.parents(".json-virtual-list-content");
            if (o) {
                var vl = app.virtualList.get("#" + o[0].id);
                var target = o.attr('data-detail') || null;
                var itemSel = vl.items[rowindex];
                if (target) {
                    e.preventDefault();
                    if (itemSel) {
                        var view = app.view;
                        if ((view) && (view.length > 0)) {
                            try {
                                var url='/' + target + '/?rowindex=' + rowindex + "&key=" + datakey + '&data=' + encodeURIComponent(JSON.stringify(itemSel)); 
                                if (url.length<=2083) {
                                    jsonApiPlugin.dataset=null;
                                    view[0].router.navigate(url);
                                } else {
                                    jsonApiPlugin.dataset=JSON.stringify(itemSel);
                                    view[0].router.navigate('/' + target + '/?rowindex=' + rowindex + "&key=" + datakey); //url without data
                                }
                            }
                            catch(err) {
                                app.dialog.alert(err.message);
                            }
                           
                        }
                    }
                }
                var parentRepeater=t.closest(".json-virtual-list") || null;
                app.emit('jsonRepeaterLineDblClick',parentRepeater, rowindex,datakey,itemSel,target);   
            }
        }
    },

    repeaterLineClick: function (e, t) {
        var rowindex = t.attr('data-index') || null;
        var datakey = t.attr('data-key') || null;
        if (rowindex) {
            thoriumapi.logEvent(0, "[com.thoriumbuilder.jsonapi] Detect Click/Touch on line [" + rowindex + "]");
            var o = t.parents(".json-virtual-list-content");
            if (o) {
                var vl = app.virtualList.get("#" + o[0].id);
                var target = o.attr('data-detail') || null;
                var itemSel = vl.items[rowindex];
                if (target) {
                    e.preventDefault();
                    if (itemSel) {
                        var view = app.view;
                        if ((view) && (view.length > 0)) {
                            try {
                                var url='/' + target + '/?rowindex=' + rowindex + "&key=" + datakey + '&data=' + encodeURIComponent(JSON.stringify(itemSel)); 
                                if (url.length<=2083) {
                                    jsonApiPlugin.dataset=null;
                                    view[0].router.navigate(url);
                                } else {
                                    jsonApiPlugin.dataset=JSON.stringify(itemSel);
                                    view[0].router.navigate('/' + target + '/?rowindex=' + rowindex + "&key=" + datakey); //url without data
                                }
                            }
                            catch(err) {
                                app.dialog.alert(err.message);
                            }
                           
                        }
                    }
                }
                var parentRepeaterVL=t.closest(".json-virtual-list") || null;
                app.emit('jsonRepeaterLineClick',parentRepeaterVL, rowindex,datakey,itemSel,target);   
                var parentRepeater=o[0].closest(".json-repeater") || null;
                if (parentRepeater) {
                    app.emit('lineChange[#'+parentRepeater.id+']',e, parentRepeater,rowindex,itemSel);
                }
            }
        }
    },

    collectionrepeaterLineClick: function (e, t) {
        var rowindex = t.attr('data-index') || null;
        var datakey = t.attr('data-key') || null;
        if (rowindex) {
            thoriumapi.logEvent(0, "[com.thoriumbuilder.jsonapi] Detect Click/Touch on line [" + rowindex + "]");
            var o = t.parents(".json-virtual-list-content");
            if (o) {
                var items = o.data('items');
                var target = o.attr('data-detail') || null;
                var itemSel = items[rowindex];
                var view = app.view;
                if ((view) && (view.length > 0)) {
                    var parentRepeater=t.closest(".json-virtual-list") || null;
                    app.emit('jsonRepeaterLineClick', parentRepeater, rowindex,datakey,itemSel,target);  
                    view[0].router.navigate('/' + target + '/?rowindex=' + rowindex + '&data=' + encodeURIComponent(JSON.stringify(itemSel)) + "&key=" + datakey);
                }
            }
        }
    },

    initAllDisplayers: function (key, data) {
        thoriumapi.logEvent(0, "[com.thoriumbuilder.jsonapi] Checking JSON Displayer State");
        var x = document.querySelectorAll(".json-form");
        for (var i = 0; i < x.length; i++) {
            var form = x[i];
            if (form.getAttribute("data-loaded") != "true") {
                var extapi = form.getAttribute('data-custom-api') || null;
                if (extapi) {
                    jsonApiPlugin.getDisplayerData(extapi, key, form);
                } else {
                    jsonApiPlugin.setDisplayerDataContent(form, data);
                }
            }
        }
        if ((!x) || (x.length==0)) {
            app.preloader.hide();
        }
    },

    /*-- Virtual list Filter Button Click--*/
    setRepeaterFilter: function (e, t) {
        var vlid = t.attr('data-filter-virtuallist') || null;
        var vl = app.virtualList.get("#" + vlid);
        if (vl) {
            thoriumapi.logEvent(0, "[com.thoriumbuilder.jsonapi] Set New Filter for Repeater with ID [" + vlid + "]");
            document.getElementById(vlid).setAttribute("data-loaded", false);
            document.getElementById(vlid).setAttribute("data-count", 0);
            var dl = t.attr("data-source");
            if (dl) {
                document.getElementById(vlid).setAttribute("data-source", dl);
                jsonApiPlugin.initAllRepeaters(null);
            }
        } else {
            var m = "An error occured, the Json Repeater is not initialized";
            thoriumapi.logEvent(2, "[com.thoriumbuilder.jsonapi] " + m);
            app.dialog.alert(m);
        }
    },

    repeaterLineButtonClick: function (e, t) {
        var rowindex = t.attr('data-index') || null;
        var datakey = t.attr('data-key') || null;
        var datatarget = t.attr('data-target') || null;
        var transition = t.attr('data-transition') || null;
        if (rowindex) {
            thoriumapi.logEvent(0, "[com.thoriumbuilder.jsonapi] Detect Click/Touch on Line [" + rowindex + "]");
            var o = t.parents(".json-virtual-list-content");
            if ((o) && (o.length > 0)) {
                var vl = app.virtualList.get("#" + o[0].id);
                if (vl) {
                    var itemSel = vl.items[rowindex];
                    var view = app.view;
                    var parentVl = t.closest(".virtual-list") || null;
                    var parentID = null;
                    if (parentVl) { parentID = parentVl[0].id; }
                    if ((view) && (view.length > 0)) {
                        app.emit('VirtualListLineClick', t, rowindex, itemSel, datatarget);
                        view[0].router.navigate('/' + datatarget + '/?rowindex=' + rowindex + '&data=' + encodeURIComponent(JSON.stringify(itemSel)) + "&key=" + datakey + "&parentvlid=" + parentID, { animate: true, transition: transition, reloadAll: false });
                    }
                    var parentRepeater=t.parents(".json-virtual-list") || null;
                    if ((parentRepeater) && (parentRepeater.length>0)) {parentRepeater=parentRepeater[0];}
                    app.emit('jsonRepeaterLineClick', parentRepeater, rowindex,datakey,itemSel,datatarget); 
                }
            }
        }
    },

    //Flatten Form Data to item eg field1.name
    getFlatFormData: function (elt, data, item) {
        for (var prop in data) {
            if (typeof data[prop] == "object" && data[prop] !== null) {
                if (Array.isArray(data[prop])) {
                    var p = prop.replaceAll(" ", "_");
                    item[p] = data[prop];
                } else {
                    jsonApiPlugin.getFlatFormData(elt + "." + prop, data[prop], item);
                }
            } else {
                var p = prop.replaceAll(" ", "_");
                item[elt + "." + p] = data[prop];
            }
        }
        return item;
    },

    setJsonFormData: function (form, data, parentkey) {
        if (!(data)) { return; }
        if (form.getAttribute("data-loaded") === true) { return; };
        var formData = {};
        var item = {};
        for (var prop in data) {
            if (typeof data[prop] == "object" && data[prop] !== null) {
                item = jsonApiPlugin.getFlatFormData(prop, data[prop], item);
            } else {
                var p = prop.replaceAll(" ", "_");
                item[p] = data[prop];
            }
        }
        thoriumapi.logEvent(0, "[com.thoriumbuilder.jsonapi] Set JSON Form Data for form with ID [" + form.id + "]");
        for (let [key, value] of Object.entries(item)) {
            var reservedWords = ["name", "id", "description", "this", "title", "submit"]; //to be completed
            var alias = key; //.toLowerCase();
            if (reservedWords.includes(alias) === true) { alias = alias + "_alias"; } //alias for reserved words

            var fld = document.getElementsByName(alias)[0]; // document.getElementById(key);
            if (fld) {
                var isShadow = fld.classList.contains("shadow-text");
                if (fld.type == 'checkbox') {
                    if ((value === 'true') || (value === true) || (value === '1') || (value === 'on')) {
                        formData[alias] = 'on';
                        fld.setAttribute("checked", "checked");
                    } else {
                        formData[alias] = 'off';
                        fld.removeAttribute("checked");
                    }
                } else if ((fld.type == 'select-one') || (fld.tagName.toLowerCase == 'select')) {
                    $('#' + fld.id).attr('data-value', value);
                    var fp = $('#' + fld.id).closest('.smart-select');
                    if ((fp) && (fp.length > 0)) {
                        var sm = app.smartSelect.get(fp);
                        if (sm) { sm.setValue(value); }
                    } else {
                        $('#' + fld.id).val(value);
                        var n = $('#' + fld.id).html().trim();
                        if (n.length == 0) {
                            $('#' + fld.id).html('<option value="' + value + '">' + value + '</option>');
                        }
                    }
                    formData[key] = value;

                } else if (fld.type == 'image') {
                    $('#' + fld.id + '-fileinput-filename').css('visibility', 'hidden');
                    if ((value) && (value.length > 0)) {
                        $('#' + fld.id).css('background-image', 'url(' + value + ')');
                        $('#' + fld.id + '-fileinput-filename span').text(value);
                        $('#' + fld.id + '-remove').show();
                    }
                } else if (fld.type == 'range') {
                    formData[key] = value;
                    var range = app.range.get(fld.parentElement);
                    if (range) {
                        range.setValue(value);
                    } else {
                        range = app.range.create(fld.parentElement);
                        range.setValue(value);
                    }
                } else if (isShadow == true) {
                    formData[key] = value;
                    var sid = fld.id.replaceAll("-shadow", '');
                    var te = app.textEditor.get('#' + sid);
                    if (te) {
                        te.setValue(value);
                    }
                } else if (fld.type == 'text') {
                    fld.value = value;
                } else if (fld.type == 'textarea') {
                    fld.value = value;

                } else if (fld.type == 'radio') {
                    //Loop on all Radio Items
                    var radioParent = fld.closest("ul");
                    var radioName = fld.getAttribute("name");
                    var radioButtons = radioParent.querySelectorAll("input[name='" + radioName + "']");
                    for (var i = 0; i < radioButtons.length; i++) {
                        var radioItem = radioButtons[i];
                        var radioValue = radioItem.value;
                        if (radioValue == value) {
                            radioItem.setAttribute("checked", "checked");
                        } else {
                            radioItem.removeAttribute("checked");
                        }
                    }
                } else if (fld.type == 'file') {
                    var lineIdent = fld.getAttribute("data-fileinput-ref");
                    var ot = $('#' + lineIdent);
                    if ((ot) && (ot.length > 0)) {
                        var toto = $('#' + lineIdent + '-fileinput-filename span');
                        $('#' + lineIdent + '-fileinput-filename').show();
                        $('#' + lineIdent + '-fileinput-filename').css('visibility', 'visible');
                        $('#' + lineIdent + '-fileinput-filename span').text(value);
                        $('#' + lineIdent + '-fileinput-filename i').show();
                        $('#' + lineIdent + '-fileinput-link').show();
                        $('#' + lineIdent + '-fileinput-link span').html('<a class="external" target="_blank" rel="noopener" data-rel="external" target="_blank" href="' + value + '">See attached file</a>');
                        if (value.length > 0) {
                            $('#' + lineIdent + '-remove').show();
                        } else {
                            $('#' + lineIdent + '-fileinput-filename').css('visibility', 'hidden');
                        }

                    }
                    formData[key] = value;

                } else {
                    formData[key] = value;
                    fld.value = value;
                }
            }
        }

        app.form.fillFromData("#" + form.id, formData);
        form.setAttribute("data-loaded", true);
        form.setAttribute("data-parent-key", parentkey);
    },

    initAllJsonWidgets: function (e) {
        var p = e.detail;
        var appRoute;
        var jsonData;
        var rowindex;
        var key;
        var elt;
        if (p === page) { elt = app.root; } else { elt = p.$el; appRoute = p.route; }
        if (elt) {
            if (appRoute) {
                jsonData = appRoute.query.data || null;
                if ((!jsonData) && (jsonApiPlugin.dataset)) {
                    jsonData =jsonApiPlugin.dataset;
                    appRoute.query.data=jsonData;
                }

                rowindex = appRoute.query.rowindex || null;
                key = appRoute.query.key || null;
                var data;
                thoriumapi.logEvent(0, "[com.thoriumbuilder.jsonapi] Get Page Parameters");
                if (jsonData=="undefined") {jsonData=null;}
                if (jsonData) {
                    try {
                        data = JSON.parse(jsonData);
                    }
                    catch (e) {
                        var err = "[com.thoriumbuilder.jsonapi] Get Page Parameters, Unable to Parse data parameter Json:" + e.message
                        thoriumapi.logEvent(2, err);
                        app.dialog.alert(err);
                        return;
                    }
                }
                jsonApiPlugin.currentKey=key;
                jsonApiPlugin.currentData=data;

                if (kShowPreloader==true) {app.preloader.show();}
                jsonApiPlugin.initAllDisplayers(key, data);
                jsonApiPlugin.initAllRepeaters(key);
                $(".form[data-from-repeater='true']").each(function (form) {
                    if (form.classList.contains("firebase-data-form") == false) {
                        app.emit('jsonFormInitialized', form, data, key);
                        jsonApiPlugin.setJsonFormData(form, data, key);
                        app.emit('formDataLoaded[#'+form.id+']',form, data, key);
                    }
                });
            }
        }
    },

    initialize: function () {
        thoriumapi.logEvent(0, "[com.thoriumbuilder.jsonapi] Initializing JSON API");
        jsonApiPlugin.initAllRepeaters(null);
        jsonApiPlugin.initAllDisplayers();
        thoriumCorePlugin.app.showAppLoader(false);
    }
};

/* -- Events Handler --*/
$(document).on('click', '.item-json', function (e) {
    e.preventDefault();
    var sender=e.target;
    if (sender) {
        if (sender.classList.contains("btn-json-page") == false) { 
            jsonApiPlugin.repeaterLineClick(e, $(this));
        }
    }
});

/* --- DATALISTVIEW EVENTS --*/
$(document).on("click", ".json-field-link", function (e) {
    e.preventDefault();
    var textFld = this.querySelector(".json-field");
    if (textFld) {
        textFld.style.whiteSpace = "break-spaces";
        var t = textFld.innerText;
        var elt = document.querySelector(".text-viewer-popup .block-text");
        if (elt) { elt.innerText = t; }
        var textPopup = app.sheet.create({
            el: '.text-viewer-popup',
            swipeToClose: false,
            backdrop: true,
            closeByBackdropClick: true,
            closeByOutsideClick: true,
            closeOnEscape: true,
            animate: true,
        });
        textPopup.open(true);
        textFld.style.whiteSpace = "normal";
    }
});


$(document).on('dblclick', '.item-json', function (e) {
    e.preventDefault();
    var sender=e.target;
    if (sender) {
        if (sender.classList.contains("btn-json-page") == false) { 
            jsonApiPlugin.repeaterDblLineClick(e, $(this));
        }
    }
});

$(document).on('click', 'a.collection-item-json', function (e) {
    e.preventDefault();
    jsonApiPlugin.collectionrepeaterLineClick(e, $(this));
});

$(document).on('click', 'a.btn-json-page', function (e) {
    e.preventDefault();
    jsonApiPlugin.repeaterLineButtonClick(e, $(this));
});


$(document).on('click', 'a.btn-json-filter', function (e) {
    e.preventDefault();
    jsonApiPlugin.setRepeaterFilter(e, $(this));
});

$(document).on('page:mounted', function (e) {
    e.preventDefault;
    jsonApiPlugin.initAllJsonWidgets(e);
})


