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

var thoriumapi = {
    name: "Thorium Public API",
    bundleid: "com.thoriumbuilder.api",
    version: "4.0.0",
    setDarkMode: function (isdark) {
        if ((isdark == "true") || ((isdark == true))) {
            document.documentElement.classList.add("dark");
        } else {
            document.documentElement.classList.remove("dark");
        }
        return thoriumapi.isDarkMode();
    },
    isDarkMode: function () {
        if (document.documentElement.classList.contains("dark")) {
            return "1";
        } else {
            return "0";
        }
    },
    changeTheme: function(t) {
        app.theme=t;
        document.documentElement.classList.remove('ios');
        document.documentElement.classList.remove('md');
        document.documentElement.classList.add(t);
    },
    isLocal: function () {
        if (window.location.protocol == "file:") {
            return true;
        } else {
            return false;
        }
    },
    getURL: function () {
        return window.location;
    },
    getProtocol: function () {
        return window.location.protocol;
    },
    getpageparam: function (e) {
        if ((e) && (e.detail) && (e.detail.route)) {
            var a = e.detail.route;
            if (a) {
                return a.query.data || null;
            }
        }
    },
    replaceDynamicVariables: function (source) {  //Dynamic variables
        var str = source,
            rg = /[^{\}]+(?=})/g,
            match;
        while (match = rg.exec(str)) { // Iterate matches 
            var dynamicVar = match[0];
            if ((dynamicVar) && (dynamicVar.length > 0)) {
                var varValue = "";
                try {
                    varValue = window[dynamicVar];
                } catch (err) {
                    app.preloader.hide();
                    var m = "[com.thoriumbuilder.jsonapi] Unable to find variable " + dynamicVar + "] " + err;
                    app.dialog.alert(m);
                    return;
                }
                if (varValue) {
                    source = source.replace("{" + dynamicVar + "}", encodeURIComponent(varValue));
                } else {
                    app.preloader.hide();
                    var m = "[com.thoriumbuilder.jsonapi] variable [" + dynamicVar + "] is undefined";
                    app.dialog.alert(m);
                    return;
                }
            }
        }
        return source;
    },
    handleError: function (errorMsg, url, lineNumber, ColumnNumber) {
        var loc = window.location.pathname;
        var dir = loc.substring(0, loc.lastIndexOf('/'));
        var origin = window.location.origin;
        url = url.replace("file://", "").replace(dir, "").replace("/js/", "").replace(origin, "");
        var msg = "<span class=\"text-color-red\">[javascript error]</span><br><span class=\"text-color-blue\">" + errorMsg + '</span><br>source: <span class=\"text-color-blue\">' + url + "</span><br>[line: " + lineNumber + " - col: " + ColumnNumber + "]";
        if (kDebugMessagesLevel > 0) {
            console.log("[com.thoriumbuilder.api] " + msg);
        }
        app.preloader.hide;
        if (kDebugMessagesLevel == 2) {
            app.dialog.alert(msg, "Debugger");
        }
        if (kDebugMessagesLevel > 0) {
            thoriumapi.logEvent(2, "[com.thoriumbuilder.api] " + errorMsg);
        }
    },
    forceReload: function (showPreloader) {
        thoriumCorePlugin.app.forceReload(showPreloader);
    },
    logSimulator: function(level,message) {
        if (app.device.capacitor == false) {
            if ((app.device.capacitor == false) && (thoriumapi.isSafari() == true)) {
                if ((window) && (window.webkit)) {
                    var webKitRef = window.webkit;
                    if ((webKitRef) && (app.device.cordova == false) && (app.device.capacitor == false) && (window.webkit.messageHandlers)) {
                        try {
                            window.webkit.messageHandlers.thoriumHandler.postMessage("{" + level + "} " + message);
                        }
                        catch (err) {
                            //
                        }
                    }
                }
            }
        }
    },
    logEvent: function (level, message) {
        level = level || 0;
        message = message || '';
        var now = new Date();
        var time = now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds() + ":" + now.getMilliseconds() + " ms";
        if (kDebugMessagesLevel > 0) {
            console.log(time + " " + message);
            window.status = "{" + level + "} " + message;
        }
        thoriumapi.logSimulator(level,message);
    },
    loadpage: function (url, props, transition) {
        thoriumapi.logEvent(0, "[com.thoriumbuilder.api] Loading url " + page);
       // transition=transition||"f7-cover";
        if (!props) {props={}}
        for (const [key, value] of Object.entries( app.routes)) {
            if (value.name==page) {
                value.props=props;
                break;
            }
        }
        var options={};
        options.reloadCurrent=false;
        options.reloadPrevious=false;
        options.reloadAll=false;
        options.clearPreviousHistory=false;
        options.animate=true;
        options.history=true;
        options.browserHistory=false;
        options.ignoreCache=false;
        options.props=props;
        if (transition) {options.transition=transition;}
        if (url.indexOf("/")==-1) {
            url="/"+url+"/";
        }
        app.views.main.router.navigate(url,options);
    },
    alert: function (message) {
        if (typeof app !== 'undefined') {
            thoriumCorePlugin.app.showAppLoader(false);
            app.preloader.hide();
            app.dialog.alert(message, "");
        } else {
            alert(message);
        }
    },
    logError: function (displayMessage, messageText) {
        thoriumCorePlugin.app.showAppLoader(false);
        if (auth) {
            thoriumapi.logEvent(2, "[" + auth.bundleid + "] " + messageText);
        }
        if (displayMessage == true) {
            app.preloader.hide();
            app.dialog.alert(messageText, "Alert");
        }
    },
    callFunctionByName(fn,fnparams) {
        var r;
        if (typeof fn === "function") {
            try {
                if (fnparams) {
                    r = fn.apply(this, fnparams);
                } else {
                    r = fn.apply(this);
                }

            } catch(e) {
                thoriumapi.logEvent(2, "[com.thoriumbuilder.api] Function [" + fn.name + "] Call Failed");
                app.dialog.alert(e);
            }
           
            thoriumapi.logEvent(0, "[com.thoriumbuilder.api] Calling Function [" + fn.name + "]");
            return fnparams;
        } else {
            var err = '[com.thoriumbuilder.api] An error occured "' + fn.name + '" is not an existing function';
            thoriumapi.logEvent(2, err);
            app.dialog.alert(err);
            return false;
        }

    },
    setDynamicVariableContent(v) {
        if ((v) && (v.length > 0)) {
            var str = v,
                rg = /[^{\}]+(?=})/g,
                match;
            while (match = rg.exec(str)) { // Iterate matches
                var varValue = "";
                var varname = match[0];
                try {
                    varValue = window[varname];
                    if (varValue) { 
                        v=v.replaceAll("{"+varname+"}",varValue);
                    }
                } catch (err) {
                    thoriumapi.logEvent(1, "[com.thoriumbuilder.api] Unable to find variable " + varname + "]");
                }
            }
        }
        return v;
    },

    /* -- F E T C H  A P I -- */
    status: function (response) {
        for (var pair of response.headers.entries()) {
            console.log("[com.thoriumbuilder.api] fetch api returned headers " + pair[0] + ': ' + pair[1]);
            thoriumapi.logEvent(0, "[com.thoriumbuilder.api] fetch api returned headers " + pair[0] + ': ' + pair[1]);
        }
        if (response.status >= 200 && response.status < 300) {
            return Promise.resolve(response)
        } else {
            var error=new Error(response.status+": "+ response.statusText);
            error.code=response.status;
            return Promise.reject(error);
        }
    },

    json: function (response) {
        try {
            return response.json();
        } catch {
            return {};
        }
        
    },
    blob: function (response) {
        try {
            return response.blob();
        } catch {
            return {};
        }
        
    },

    checkResult: function (data) {
        if ((data) && (data.code < 0)) {
            app.preloader.hide();
            app.dialog.alert(data.message);
            return false;
        } else if (!data) {
            app.preloader.hide();
            app.dialog.alert("Invalid Result");
            return false;
        } else {
            return true;
        }
    },
    /* -- F E T C H  A P I -- */

    reloadHomePage: function () {
        thoriumapi.logEvent(0, "[com.thoriumbuilder.api] Reloading Home Page ");
        if (app.view[0].router.url != "/") {
            app.preloader.show();
            setTimeout(
                function () {
                    location.reload();
                }, 1000
            );
        }
    },

    backToPreviousPage: function () {
        thoriumapi.logEvent(0, "[com.thoriumbuilder.api] Back to previous page");
        app.view[0].router.back();
    },

    txtToUrl: function (t) {
        if (t == null) {
            return '';
        }
        var expression = /[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/gi;
        var regex = new RegExp(expression);
        try {
            var result = t.match(regex);
        } catch (error) {
            return t;
        }
        if (result) {
            result.forEach(function (entry) {
                t = t.replace(entry, '<a class="link external" data-rel="external" target="_blank" rel="noopener" href="' + entry + '">' + result + '</a>');
            });
            return t;
        } else {
            return t;
        }
    },

    isSafari: function () {
        var ua = navigator.userAgent.toLowerCase();
        if (ua.indexOf('safari') != -1) {
            if (ua.indexOf('chrome') > -1) {
                return false;
            } else {
                return true;
            }
        }
    },

    showAlert: function (message) {
        app.dialog.alert(thoriumCorePlugin.txtToUrl(message));
    },
    showNotification: function (message, timeout, icon, cssClass, subtitle, title) {
        title = title || 'NOTIFICATION';
        thoriumapi.logEvent(0, "[com.thoriumbuilder.api] Show Notification");
        timeout = timeout || 3000;
        icon = icon || "bell_fill";
        subtitle = subtitle || '';
        var notificationFull = app.notification.create({
            icon: '<i class="f7-icons text-muted">' + icon + '</i>',
            title: title,
            closeButton: false,
            titleRightText: '',
            subtitle: subtitle,
            text: message,
            closeTimeout: timeout,
            swipeToClose: true,
            cssClass: cssClass
        });
        notificationFull.open();
    },

    showToast: function (text, closeButton, position, closeTimeout, icon) {
        thoriumapi.logEvent(0, "[com.thoriumbuilder.api] Showing Toast Message");
        var toast;
        if (typeof closeButton != "boolean") {
            closeButton = false
        };
        position = position || 'bottom';
        closeTimeout = closeTimeout || 3000;
        icon = icon || null;
        if (icon) {
            toast = app.toast.create({
                icon: (icon) ? '<i class="f7-icons">' + icon + '</i>' : null,
                text: text,
                position: position,
                destroyOnClose: true,
                closeTimeout: closeTimeout,
            });
        } else {
            toast = app.toast.create({
                text: text,
                closeButton: closeButton,
                closeButtonText: "OK",
                closeButtonColor: "text-color-white",
                position: position,
                destroyOnClose: true,
                closeTimeout: closeTimeout,
            });
        }
        toast.open();
    },

    openPopup: function (p) {
        thoriumapi.logEvent(0, "[com.thoriumbuilder.api] Open Popup");
        var myPopup = app.popup.create({
            content: p,
        });
        myPopup.open();
    },

    getObjectViewPortPercent: function (el, viewportTop) {
        var elt = $('#' + el.id);
        var elementTop = elt.offset().top;
        var elementBottom = elementTop + elt.outerHeight();
        var viewportBottom = viewportTop + $(window).height();
        var scrollPercent = 100 - (Math.round(100 * (elementBottom - $(window).scrollTop()) / ($(window).height() + elt.height())));
        return parseInt(Math.round(((viewportBottom - elementTop) / elt.outerHeight()) * 100));
    },

    findGetParameter: function (p) {
        thoriumapi.logEvent(0, "[com.thoriumbuilder.api] Get URL Parameters");
        var result = null,
            tmp = [];
        location.search
            .substr(1)
            .split("&")
            .forEach(function (item) {
                tmp = item.split("=");
                if (tmp[0] === p) result = decodeURIComponent(tmp[1]);
            });
        return result;
    },

    cookies: {
        id: "app.condominium.cookies",
        setCookie: function (cName, cValue) {
            let date = new Date();
            const expDays = 30;
            date.setTime(date.getTime() + (expDays * 24 * 60 * 60 * 1000));
            const expires = "expires=" + 30; //date.toUTCString();
            document.cookie = cName + "=" + cValue + "; " + expires + "; path=/"; //;HttpOnly:true;Secure: true
        },
        updateCookie: function (cName, cValue) {
            setCookie(cName, cValue, 30);
        },
        deleteCookie: function (cName) {
            document.cookie = cName + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/";
        },
        getCookie: function (cName) {
            const name = cName + "=";
            const cDecoded = decodeURIComponent(document.cookie);
            if (cDecoded)  {
                const cArr = cDecoded.split('; ');
                let res;
                cArr.forEach(val => {
                    if (val.indexOf(name) === 0) res = val.substring(name.length);
                })
                if (res) { return res;} else {return null;}
            } else {
                return null;
            }
        },
        getCookies: function () {
            return document.cookie;
        },
    },

    localstorage: {
        name: "Thorium localstorage Public API",
        isAvailable: function () {
            try {
                return 'localStorage' in window && window['localStorage'] !== null;
            } catch (e) {
                thoriumapi.logEvent(2, "[com.thoriumbuilder.thoriumapi] Local Storage not available #" + e.code + " " + e.message);
                app.dialog.alert("Local Storage error #" + e.code + " " + e.message);
                return false;
            }
        },
        setItem: function (key, value) {
            if (thoriumapi.localstorage.isAvailable() == true) {
                try {
                    window.localStorage.setItem(key, value);
                } catch (e) {
                    if (e.code == 22) {
                        // Storage full, maybe notify user or do some clean-up
                        thoriumapi.logEvent(2, "[com.thoriumbuilder.thoriumapi] Local Storage is Full");
                    } else if ((e.code == 1014) && (e.name === 'NS_ERROR_DOM_QUOTA_REACHED')) { // Firefox
                        thoriumapi.logEvent(2, "[com.thoriumbuilder.thoriumapi] Local Storage is Full");
                    } else {
                        thoriumapi.logEvent(2, "[com.thoriumbuilder.thoriumapi] Local Storage error #" + e.code + " " + e.message);
                    }
                    app.dialog.alert("Local Storage error #" + e.code + " " + e.message);
                    return false;
                }
                return true;
            }
        },
        getItem: function (key) {
            if (thoriumapi.localstorage.isAvailable() == true) {
                try {
                    var result = window.localStorage.getItem(key);
                } catch (e) {
                    thoriumapi.logEvent(2, "[com.thoriumbuilder.thoriumapi] Local Storage error #" + e.code + " " + e.message);
                    app.dialog.alert("Local Storage error #" + e.code + " " + e.message);
                    return;
                }
                return result;
            }
        },
        removeItem: function (key) {
            if (thoriumapi.localstorage.isAvailable() == true) {
                try {
                    window.localStorage.removeItem(key);
                } catch (e) {
                    thoriumapi.logEvent(2, "[com.thoriumbuilder.thoriumapi] Local Storage error #" + e.code + " " + e.message);
                    app.dialog.alert("Local Storage error #" + e.code + " " + e.message);
                    return false;
                }
                return true;
            }
        },
        clear: function () {
            if (thoriumapi.localstorage.isAvailable() == true) {
                try {
                    window.localStorage.clear();
                } catch (e) {
                    thoriumapi.logEvent(2, "[com.thoriumbuilder.thoriumapi] Local Storage error #" + e.code + " " + e.message);
                    app.dialog.alert("Local Storage error #" + e.code + " " + e.message);
                    return false;
                }
                return true;
            }
        },
    },
    sessionstorage: {
        name: "Thorium sessionstorage Public API",
        isAvailable: function () {
            try {
                return 'sessionStorage' in window && window['sessionStorage'] !== null;
            } catch (e) {
                thoriumapi.logEvent(2, "[com.thoriumbuilder.thoriumapi] Session Storage not available #" + e.code + " " + e.message);
                app.dialog.alert("Session Storage error #" + e.code + " " + e.message);
                return false;
            }
        },
        setItem: function (key, value) {
            if (thoriumapi.sessionstorage.isAvailable() == true) {
                try {
                    window.sessionStorage.setItem(key, value);
                } catch (e) {
                    if (e.code == 22) {
                        // Storage full, maybe notify user or do some clean-up
                        thoriumapi.logEvent(2, "[com.thoriumbuilder.thoriumapi] Session Storage is Full");
                    } else if ((e.code == 1014) && (e.name === 'NS_ERROR_DOM_QUOTA_REACHED')) { // Firefox
                        thoriumapi.logEvent(2, "[com.thoriumbuilder.thoriumapi] Session Storage is Full");
                    } else {
                        thoriumapi.logEvent(2, "[com.thoriumbuilder.thoriumapi] Session Storage error #" + e.code + " " + e.message);
                    }
                    app.dialog.alert("Session Storage error #" + e.code + " " + e.message);
                    return false;
                }
                return true;
            }
        },
        getItem: function (key) {
            if (thoriumapi.sessionstorage.isAvailable() == true) {
                try {
                    var result = window.sessionStorage.getItem(key);
                } catch (e) {
                    thoriumapi.logEvent(2, "[com.thoriumbuilder.thoriumapi] Session Storage error #" + e.code + " " + e.message);
                    app.dialog.alert("Session Storage error #" + e.code + " " + e.message);
                    return;
                }
                return result;
            }
        },
        removeItem: function (key) {
            if (thoriumapi.sessionstorage.isAvailable() == true) {
                try {
                    window.sessionStorage.removeItem(key);
                } catch (e) {
                    thoriumapi.logEvent(2, "[com.thoriumbuilder.thoriumapi] Session Storage error #" + e.code + " " + e.message);
                    app.dialog.alert("Session Storage error #" + e.code + " " + e.message);
                    return false;
                }
                return true;
            }
        },
        clear: function () {
            if (thoriumapi.sessionstorage.isAvailable() == true) {
                try {
                    window.sessionStorage.clear();
                } catch (e) {
                    thoriumapi.logEvent(2, "[com.thoriumbuilder.thoriumapi] Session Storage error #" + e.code + " " + e.message);
                    app.dialog.alert("Session Storage error #" + e.code + " " + e.message);
                    return false;
                }
                return true;
            }
        },
    },

    spatial : {
        name: "Thorium Spatial Public API",
        getDistance: function(lat1, lon1, lat2, lon2) {
            var R = 6371; // Radius of the earth in km
            var dLat = thoriumapi.spatial.deg2rad(lat2 - lat1);  // deg2rad below
            var dLon = thoriumapi.spatial.deg2rad(lon2 - lon1);
            var a =
                Math.sin(dLat / 2) * Math.sin(dLat / 2) +
                Math.cos(thoriumapi.spatial.deg2rad(lat1)) * Math.cos(thoriumapi.spatial.deg2rad(lat2)) *
                Math.sin(dLon / 2) * Math.sin(dLon / 2)
                ;
            var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
            var d = R * c; // Distance in km
            return d;
        },
        deg2rad: function(deg) {
            return deg * (Math.PI / 180)
        },
    },
    geolocation: {
        name: "Thorium geolocation Public API",
        watch: null,
        latitude: null, //The latitude as a decimal number (always returned)
        longitude: null, //The longitude as a decimal number (always returned)
        accuracy: null, //The longitude as a decimal number (always returned)
        altitude: null, //The altitude in meters above the mean sea level (returned if available)
        altitudeAccuracy: null, //The altitude accuracy of position (returned if available)
        heading: null, //The heading as degrees clockwise from North (returned if available)
        speed: null, //The speed in meters per second (returned if available)
        timestamp: null, //The date/time of the response (returned if available)
        isAvailable: function () {
            if (navigator.geolocation) {
                return true;
            } else {
                app.emit('geolocationError', error);
                thoriumapi.logEvent(2, "[com.thoriumbuilder.thoriumapi] Geolocation is not supported");
                app.dialog.alert("Geolocation is not supported");
                return false;
            }
        },
        setPosition: function (pos) {
            if ((pos) && (pos.coords)) {
                var coord = pos.coords;
                thoriumapi.geolocation.latitude = coord.latitude;
                thoriumapi.geolocation.longitude = coord.longitude;
                thoriumapi.geolocation.accuracy = coord.accuracy;
                thoriumapi.geolocation.altitude = coord.altitude;
                thoriumapi.geolocation.altitudeAccuracy = coord.altitudeAccuracy;
                thoriumapi.geolocation.heading = coord.heading;
                thoriumapi.geolocation.speed = coord.speed;
                thoriumapi.geolocation.timestamp = pos.timestamp;
                thoriumapi.logEvent(0, "[com.thoriumbuilder.thoriumapi] geoLocation returned, [" + coord.longitude + " | " + coord.latitude + "]");
                app.emit('geolocationSuccess', coord);
            }
        },
        getCurrentPosition: function () {
            if (thoriumapi.geolocation.isAvailable() == true) {
                thoriumapi.logEvent(0, "[com.thoriumbuilder.thoriumapi] Getting geoLocation...");
                try {
                    navigator.geolocation.getCurrentPosition(thoriumapi.geolocation.setPosition, thoriumapi.geolocation.geoLocationError);
                    return true;
                } catch (error) {
                    app.emit('geolocationError', error);
                    thoriumapi.logEvent(2, "[com.thoriumbuilder.thoriumapi] " + error.message);
                    app.dialog.alert(error.message);
                    return false;
                }
            } else {
                return false;
            }
        },
        geoLocationError: function (error) {
            app.emit('geolocationError', error);
            thoriumapi.logEvent(2, "[com.thoriumbuilder.thoriumapi] " + error.message);
        },
        watchPosition: function () {
            watch = navigator.geolocation.watchPosition(thoriumapi.geolocation.setPosition, thoriumapi.geolocation.geoLocationError);
        },
        clearWatch: function () {
            if (thoriumapi.geolocation.watch) {
                navigator.geolocation.clearWatch(thoriumapi.geolocation.watch);
                thoriumapi.geolocation.watch = null;
            }
        },

    },
    mediaDevices: {
        name: "Thorium mediaDevices Public API",
        devices: [],
        enumerateDevices: function () {
            if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) {
                thoriumapi.logEvent(2, "[com.thoriumbuilder.thoriumapi] enumerateDevices() not supported.");
                thoriumapi.mediaDevices.devices = [];
                app.emit('mediaDevicesError', "enumerateDevices() not supported.");
                return;
            }
            // List cameras and microphones.
            navigator.mediaDevices.enumerateDevices()
                .then(function (devices) {
                    thoriumapi.mediaDevices.devices = [];
                    devices.forEach(function (device) {
                        thoriumapi.mediaDevices.devices.push(device);
                        thoriumapi.logEvent(2, "[com.thoriumbuilder.thoriumapi] Device Added to list [" + thoriumapi.mediaDevices.devices.kind + " " + thoriumapi.mediaDevices.devices.label + "]");
                    });
                    app.emit('mediaDevicesSuccess');
                })
                .catch(function (err) {
                    app.emit('mediaDevicesError', err.message);
                    console.log(err.name + ": " + err.message);
                });
        }
    },

    osm: {
        name: "Thorium Open Street Map - leaflet.js Public API",
        getMapInstance: function (id) {
            if (typeof openStreetMapPlugin != "undefined") {
                var mo = document.getElementById(id);
                if (mo) {
                    if (mo.data) {
                        return mo.data;
                    } else {
                        return null;
                    }
                } else {
                    return null;
                }
            } else {
                thoriumapi.logEvent(2, "[com.thoriumbuilder.thoriumapi] Open Street Map & Leaflet Plugin not installed");
            }
        },
    },

    repeaters: {
        name: "Thorium Repeaters Public API",
        getVirtualList: function (elt) {
            var r = document.getElementById(elt);
            if (r) {
                var vlc = r.querySelector(".virtual-list");
                if (vlc) {
                    var vl = app.virtualList.get(vlc);
                    if (!vl) {
                        vl = app.virtualList.create(vlc);
                    }
                    return vl;
                }
            }
        },
        getAllItems: function (elt) {
            var vl = thoriumapi.repeaters.getVirtualList(elt);
            if (vl) {
                if (!vl.items) { vl.items = []; }
                return vl.items;
            } else {
                return null;
            }
        },
        getItemAt: function (elt, index) {
            var vl = thoriumapi.repeaters.getVirtualList(elt);
            if (vl) {
                if (!vl.items) { return; }
                return vl.items[index];
            }
        },
        getFilteredItems: function (elt) {
            var vl = thoriumapi.repeaters.getVirtualList(elt);
            if (vl) {
                if (!vl.items) { return; }
                return vl.filteredItems;
            } else {
                return null;
            }
        },
        clear: function (elt) {
            var vl = thoriumapi.repeaters.getVirtualList(elt);
            if (vl) {
                if (!vl.items) { return; }
                vl.items = [];
                vl.deleteAllItems();
                vl.update();
            }
        },
        appendItem: function (elt, item) {
            var vl = thoriumapi.repeaters.getVirtualList(elt);
            if (vl) {
                if (!vl.items) {
                    vl.items=[];
                 }
                if (vl.items) {
                    item.dataindex = vl.items.length;
                    vl.appendItem(item);
                    vl.update();
                } else {
                    item.dataindex = 0;
                    thoriumapi.logEvent(1, "[com.thoriumbuilder.api] Repeater not initialized");
                }

            }
        },
        replaceItemAt: function (elt, index, item) {
            var vl = thoriumapi.repeaters.getVirtualList(elt);
            if (vl) {
                if (!vl.items) { return; }
                vl.replaceItem(index, item);
                vl.update();
            }
        },
        removeItemAt: function (elt, index) {
            var vl = thoriumapi.repeaters.getVirtualList(elt);
            if (vl) {
                if (!vl.items) { return; }
                vl.deleteItem(index);
                for (var i = 0; i < vl.items.length; i++) {
                    vl.items[i].dataindex = i;
                }
                vl.update();
                var x = vl.el.querySelectorAll("ul .item-dbexpress");
                for (var i = 0; i < x.length; i++) {
                    var elt = x[i];
                    elt.setAttribute("data-index", i);
                }
            }
        },
        scrollToItem: function (elt, index) {
            var vl = thoriumapi.repeaters.getVirtualList(elt);
            if (vl) {
                if (!vl.items) { return; }
                vl.scrollToItem(index);
                vl.update();
            }
        },
        moveItem: function (elt, pos, newpos) {
            var vl = thoriumapi.repeaters.getVirtualList(elt);
            if (vl) {
                if (!vl.items) { return; }
                vl.moveItem(pos, newpos);
                for (var i = 0; i < vl.items.length; i++) {
                    vl.items[i].dataindex = i;
                }
                vl.update();
                var x = vl.el.querySelectorAll("ul .item-dbexpress");
                for (var i = 0; i < x.length; i++) {
                    var elt = x[i];
                    elt.setAttribute("data-index", i);
                }
            }
        },
        itemsCount: function (elt) {
            var vl = thoriumapi.repeaters.getVirtualList(elt);
            if (vl) {
                if (vl.items) { return vl.items.length; }
                else { return 0; }
            } else {
                return 0;
            }
        },
        reload: function (eltId) {
            var vlElt = document.querySelector("#" + eltId + " .virtual-list");
            if (vlElt) {
                if (typeof dbExpressData == "object") {
                    var service = vlElt.getAttribute("data-service") || null;
                    dbExpressData.getRepeaterData(vlElt, service, null);
                }
            }
        },
    },

    chartjs: {
        name: "Thorium Chart.JS Public API",
        initialize: function () {
            if (typeof chartJS !== 'undefined') {
                chartJS.initialize();
            }
        },
        addDataSet: function (id, dataString, colorString, dataLabel) {
            if (typeof chartJS !== 'undefined') {
                chartJS.addDataSet(id, dataString, colorString, dataLabel);
            }
        },
        getChartInstanceFromId: function (id) {
            if (typeof chartJS !== 'undefined') {
                return chartJS.getChartInstanceFromId(id);
            }
        },
        addDataPoint: function (id, dataSet, label, value, color) {
            if (typeof chartJS !== 'undefined') {
                chartJS.addDataPoint(id, dataSet, label, value, color);
            }
        },
        replaceDataPoint: function (id, dataSet, index, label, value, color) {
            if (typeof chartJS !== 'undefined') {
                chartJS.replaceDataPoint(id, dataSet, index, label, value, color);
            }
        },
        clearChart: function (id) {
            if (typeof chartJS !== 'undefined') {
                chartJS.clearChart(id);
            }
        },
        changeChartType(id, newType) {
            if (typeof chartJS !== 'undefined') {
                chartJS.changeChartType(id, newType);
            }
        },
    },

    date: {
        name: "Thorium Date-Time  Public API",
        getTimeStamp: function () {
            var d = new Date();
            return d.getTime() / 1000;
        },
        getTimeStampFromDate: function (date) {
            var d = new Date(date);
            return d.getTime() / 1000;
        },
        timeDiff: function (curr, prev) {
            var ms_Min = 60 * 1000; // milliseconds in Minute
            var ms_Hour = ms_Min * 60; // milliseconds in Hour
            var ms_Day = ms_Hour * 24; // milliseconds in day
            var ms_Mon = ms_Day * 30; // milliseconds in Month
            var ms_Yr = ms_Day * 365; // milliseconds in Year
            var diff = curr - prev; //difference between dates.
            // If the diff is less then milliseconds in a minute
            if (diff < ms_Min) {
                var t = Math.round(diff / 1000);
                if (t == 0) {
                    return 'now';
                } else {
                    return Math.round(diff / 1000) + ' seconds ago';
                }
                // If the diff is less then milliseconds in a Hour
            } else if (diff < ms_Hour) {
                return Math.round(diff / ms_Min) + ' minutes ago';
                // If the diff is less then milliseconds in a day
            } else if (diff < ms_Day) {
                return Math.round(diff / ms_Hour) + ' hours ago';
                // If the diff is less then milliseconds in a Month
            } else if (diff < ms_Mon) {
                return Math.round(diff / ms_Day) + ' days ago';
                // If the diff is less then milliseconds in a year
            } else if (diff < ms_Yr) {
                return Math.round(diff / ms_Mon) + ' months ago';
            } else {
                return Math.round(diff / ms_Yr) + ' years ago';
            }
        },
        getDateDiff: function (curr, prev) {
            var r={};
            var ms_Min = 60 * 1000; // milliseconds in Minute
            var ms_Hour = ms_Min * 60; // milliseconds in Hour
            var ms_Day = ms_Hour * 24; // milliseconds in day
            var ms_Mon = ms_Day * 30; // milliseconds in Month
            var ms_Yr = ms_Day * 365; // milliseconds in Year
            var diff = curr - prev; //difference between dates.
            // If the diff is less then milliseconds in a minute
            if (diff < ms_Min) {
                var t = Math.round(diff / 1000);
                if (t == 0) {
                    r.diff=0;
                    r.unit= '';
                } else {
                    r.diff= Math.round(diff / 1000);
                    r.unit= 's';
                }
                // If the diff is less then milliseconds in a Hour
            } else if (diff < ms_Hour) {
                r.diff= Math.round(diff / ms_Min);
                r.unit="m";
                // If the diff is less then milliseconds in a day
            } else if (diff < ms_Day) {
                r.diff=  Math.round(diff / ms_Hour) ;
                r.unit="h";
                // If the diff is less then milliseconds in a Month
            } else if (diff < ms_Mon) {
                r.diff= Math.round(diff / ms_Day);
                r.unit="D";
                // If the diff is less then milliseconds in a year
            } else if (diff < ms_Yr) {
                r.diff= Math.round(diff / ms_Mon);
                r.unit="M";
            } else {
                r.diff=Math.round(diff / ms_Yr);
                r.unit="Y"
            }
            return r;
        },
        getDateTimeFromTimeStamp: function (timestamp, datetype, locale, showHours) {
            var today= new Date();
            var userTimezoneOffset =today.getTimezoneOffset() * 60000;
            var myDate = new Date((parseInt(timestamp) * 1000)+userTimezoneOffset);
            showHours = showHours || false;
            var dateTemplate = kDateFormat;
            if (!dateTemplate) {dateTemplate="YYYY-MM-DD"}
            var day = myDate.getDate() || 0;
            if (day < 10) { day = "0" + day; }
            var month = myDate.getMonth() + 1 || 0;
            if (month < 10) { month = "0" + month; }
            var fullyear = myDate.getFullYear();
            var year = myDate.getYear();
            dateTemplate = dateTemplate.replace("dd", day).replace("DD", day).replace("d", day).replace("D", day);
            dateTemplate = dateTemplate.replace("MM", month).replace("mm", month).replace("m", month).replace("M", month);
            dateTemplate = dateTemplate.replace("YYYY", fullyear).replace("yyyy", fullyear).replace("YY", year).replace("yy", year);
            if (showHours == true) {
                dateTemplate = dateTemplate + " " + thoriumapi.date.getTime(myDate);
            }
            return dateTemplate;
        },

        ISO8601: function (date) {
            var d = date.getDate();
            if (d < 10) d = '0' + d;
            var m = date.getMonth() + 1;
            if (m < 10) m = '0' + m;
            return date.getFullYear() + '-' + m + '-' + d;
        },
        getDateFromISO : function(iso) {
            var d = new Date(iso);
            return d;
        }, 
        convertDateToLocalDateTime(d,lg,showtime) {
            var fd = d.toLocaleDateString(lg);
            if (showtime==true) {
                fd+=" " + d.toLocaleTimeString(lg);
            }
            return fd;
        },
        convertMinutestoHoursAndMinutes: function(M)  {
            const hours = (Math.floor(M / 60)).toString().padStart(2, '0');
            const minutes = (M % 60).toString().padStart(2, '0');
            return hours+":"+minutes;
        },
        getTime: function (date) {
            var p = '';
            var h = date.getHours();
            if (kHours12 == true) {
                if (h > 12) {
                    h = h - 12;
                    p = "pm";
                } else {
                    p = "am";
                }
            }
            if (h < 10) {
                h = "0" + h
            }
            var m = date.getMinutes();
            if (m < 10) {
                m = "0" + m
            }
            var r = h + ":" + m + " " + p;
            return r.trim();
        },
        getCalendar: function (id) {
            var x = document.querySelector("#" + id + " .calendar-inline");
            if (x) {
                return app.calendar.get(x);
            }
        },
        addValuetoCalendar: function (id, date) {
            var x = document.querySelector("#" + id + " .calendar-inline");
            if (x) {
                var c = app.calendar.get(x);
                if (c) {
                    c.addValue(date);
                }
            }
        },
        disableDateFromCalendar: function (id, date) {
            var x = document.querySelector("#" + id + " .calendar-inline");
            if (x) {
                var c = app.calendar.get(x);
                if (c) {
                    var disabled = c.params.disabled;
                    if (!disabled) {
                        disabled = [];
                    }
                    var obj = {};
                    obj["date"] = date;
                    disabled.push(obj);
                    c.params.disabled = disabled;
                    c.update();
                }
            }
        },
        addEventToCalendar: function (id, date,custom) {
            var x = document.querySelector("#" + id + " .calendar-inline");
            if (x) {
                var c = app.calendar.get(x);
                if (c) {
                    var events = c.params.events;
                    if (!events) {
                        events = [];
                    }
                    var obj = {};
                    obj["date"] = date;
                    obj["color"] = '#FF3B30'; //iOS Red
                    if (custom) {
                        obj["custom"] = custom;
                    } else {
                        obj["custom"] = {};
                    }                   
                    events.push(obj);
                    c.params.events = events;
                    c.update();
                }
            }
        },

    },

    firebase: {
        name: "Thorium Firebase Public API",
        logout: function () {
            if (typeof firebasePlugin !== 'undefined') {
                firebasePlugin.logoutExt();
            }
        },
        showRegisterScreen: function () {
            if (typeof firebasePlugin !== 'undefined') {
                firebasePlugin.showRegisterScreen();
            }
        },
        showEditProfilePageExt: function () {
            if (typeof firebasePlugin !== 'undefined') {
                firebasePlugin.showEditProfilePageExt();
            }
        },
        facebookLogin: function () {
            if (typeof firebasePlugin !== 'undefined') {
                firebasePlugin.facebookLoginExt();
            }
        },
        googleLogin: function () {
            if (typeof firebasePlugin !== 'undefined') {
                firebasePlugin.googleLoginExt();
            }
        },
        twitterLogin: function () {
            if (typeof firebasePlugin !== 'undefined') {
                firebasePlugin.twitterLoginExt();
            }
        },
        getUser: function () {
            if (typeof firebasePlugin !== 'undefined') {
                var user = firebase.auth().currentUser;
                return user;
            }
        },

    },

    dbexpress: {
        name: "Thorium dbExpress Public API",
        executeCustomService: function (service, callback, field1, operator1, value1, field2, operator2, value2) {
            if (typeof dbExpressData == "object") {
                dbExpressData.executeCustomSelectService(service, callback, field1, operator1, value1, field2, operator2, value2);
            }
        },
        getToken: function () {
            if (typeof auth !== 'undefined') {
                return auth.getToken();
            }
        },
        showResetPasswordScreen: function () {
            if (typeof auth !== 'undefined') {
                auth.showResetPasswordScreen(null);
            }
        },
        showSigninPopup: function () {
            if (typeof auth !== 'undefined') {
                auth.showSigninPopup(null);
            }
        },
        showTermsPopup: function () {
            if (typeof auth !== 'undefined') {
                auth.showTermsPopup(null);
            }
        },
        showPrivacyPopup: function () {
            if (typeof auth !== 'undefined') {
                auth.showPrivacyPopup(null);
            }
        },
        showProfileScreen: function () {
            if (typeof auth !== 'undefined') {
                auth.loadProfileScreen();
            }
        },
        showRegisterPopup: function () {
            if (typeof auth !== 'undefined') {
                auth.showRegisterPopup(null);
            }
        },
        signIn: function (email, pw, token, pin) {
            if (typeof auth !== 'undefined') {
                auth.signIn(email, pw, token, pin);
            }
        },
        logout: function () {
            if (typeof auth !== 'undefined') {
                auth.logout();
            }
        },
        getCurrentUser: function () {
            if (typeof auth !== 'undefined') {
                return auth.currentUser;
            }
        },
        getWebServiceURL: function () {
            if (typeof auth !== 'undefined') {
                return thoriumCorePlugin.httpRoot;
            }
        },
        setWebServiceURL: function (url) {
            if (typeof auth !== 'undefined') {
                thoriumCorePlugin.httpRoot = url;
            }
        },
        postData: function (table, data, callback) {
            if (typeof dbExpressData == "object") {
                dbExpressData.sendData(table, data, callback);
            }
        }

    },

    googleMap: {
        name: "GoogleMap Public API",
        getGoogleMapObject: function (id) {
            var elt = document.getElementById(id);
            if (elt) {
                if (elt.map) { return elt.map; } else { return null; }
            } else { return null; }
        },
        reloadMapData: function (id) {
            googleMapPlugin.initializeMap(id);
        },
        centerMapAtPosition: function (id, lat, lng) {
            var map = thoriumapi.googleMap.getGoogleMapObject(id);
            if (map) {
                var pos = {
                    lat: lat,
                    lng: lng,
                };
                map.setCenter(pos);
            }
        },
        setZoom: function (id, level) {
            var map = thoriumapi.googleMap.getGoogleMapObject(id);
            if (map) {
                map.setZoom(level);
            }
        },
        getZoom: function (id) {
            var map = thoriumapi.googleMap.getGoogleMapObject(id);
            if (map) {
                return map.getZoom();
            }
        },
        getCenter: function (id) {
            var map = thoriumapi.googleMap.getGoogleMapObject(id);
            if (map) {
                var pos = map.getCenter();
                var result = {};
                result.lat = pos.lat();
                result.lng = pos.lng();
                return result;
            }
        },
        setCenter: function (id, lat, lng) {
            var map = thoriumapi.googleMap.getGoogleMapObject(id);
            if (map) {
                var pos = {
                    lat: lat,
                    lng: lng,
                };
                map.setCenter(pos);
            }
        },
        drawCircleAtPos: function (id, lat, lng, size) {
            var map = thoriumapi.googleMap.getGoogleMapObject(id);
            if (map) {
                var pos = {
                    lat: lat,
                    lng: lng,
                }
                googleMapPlugin.drawCircleAtPos(map, pos, size);
            }
        },
        panTo: function (id, lat, lng) {
            var map = thoriumapi.googleMap.getGoogleMapObject(id);
            if (map) {
                var pos = {
                    lat: lat,
                    lng: lng,
                }
                map.panTo(pos);
            }
        },
        setOptions: function (id, options) {
            var map = thoriumapi.googleMap.getGoogleMapObject(id);
            if (map) {
                map.setOptions(options);
            }
        },
        addMarker: function (id, lat, lng, data) {
            var map = thoriumapi.googleMap.getGoogleMapObject(id);
            if (map) {
                var pos = new google.maps.LatLng(parseFloat(lat), parseFloat(lng));
                var title = data.title || '';
                var uid = data.uid || '';
                var addr = data.addr || '';
                var img = data.img || '';
                var desc = data.desc || '';
                var subtitle = data.subtitle || '';
                var badge = data.badge || '';
                var rating = data.rating || 0;
                var target = data.target || '';
                googleMapPlugin.addMarker(map, pos, title, uid, addr, img, desc, subtitle, badge, rating, target);
            }
        }
    },

    forms: {
        name: "forms Public API",
        reloadFormSelect: function (id) {
            var x = document.querySelectorAll("#" + id + " select[data-api-mode]");
            for (var i = 0; i < x.length; i++) {
                var obj = x[i];
                if (obj) {
                    obj.setAttribute("data-loaded", false);
                    var api = obj.getAttribute("data-api") || null;
                    var fld = obj.getAttribute("data-api-field") || null;
                    var coll = obj.getAttribute("data-select-collection") || null;
                    var fldid = obj.getAttribute("data-api-fieldid") || null;
                    var func = obj.getAttribute("data-function") || null;
                    var mode = 0;
                    mode = obj.getAttribute("data-api-mode") || '0';
                    if ((api) && (mode == '0')) {
                        mode = 1;
                    } //Fallback version 1.x
                    if ((mode == '1') && (api) && (fld)) {
                        thoriumCorePlugin.forms.fillSelect(obj, api, fld, mode, fldid, func);
                        thoriumapi.logEvent(0, "[com.thoriumbuilder.api] Form Input [" + obj.name + "] of type Select initialized from api [" + api + "]");
                    } else if ((mode == '2') && (coll) && (fld)) {
                        setTimeout(function () {
                            thoriumCorePlugin.forms.fillSelect(obj, coll, fld, mode, fldid, func);
                        }, 100);
                        thoriumapi.logEvent(0, "[com.thoriumbuilder.api] Form Input [" + obj.name + "] of type Select initialized from api [" + api + "]");
                    }
                }
            }
        },
    },

    jsonapi: {
        name: "jsonapi Public API",
        reloadRepeater: function (id, url) {
            var virtualList = document.querySelector("#" + id + " .json-virtual-list-content");
            if (virtualList) {
                thoriumapi.logEvent(0, "[com.thoriumbuilder.api] Reloading Repeater [" + id + "] from api [" + url + "]");
                virtualList.setAttribute("data-loaded", false);
                virtualList.setAttribute("data-source", url);
                var root = virtualList.getAttribute('data-root-field') || null;
                if (url) {
                    jsonApiPlugin.getRepeaterData(virtualList, url, root, true);
                    var element = document.querySelector("#view-main");
                    if (element) { element.style.display = true; }
                }
            } else {
                thoriumapi.logEvent(1, "[com.thoriumbuilder.api] Reloading Repeater [" + id + "] not found");
            }
        },
    },
}
