
// VOIP Awesome Click-and-Dial Extension for Google Chrome
// Chats Script
//
//  Copyright:  VOIP Awesome Inc, 2022
//  Author:     Jambu Atchison
//              jambu@voipawesome.com
//
//  @ Support:  cs@voipawesome.com
//



// Variables
if (typeof CND == 'undefined') { var CND = {}; }
if (typeof CND.chats == 'undefined') { CND.chats = {}; }
CND.online = window.navigator.onLine;
CND.chats.bgChatsLists = {};
CND.chats.bgLastActive = 0;
CND.chats.chatGroupIds = [];
CND.chats.chatsListLocal = [];
CND.chats.chatsListView = [];
CND.chats.chatsLists = {};
CND.chats.chatsLists.ChatsLastLoaded = 0;
CND.chats.chatsLists.ChatsListLoaded = {};
CND.chats.chatsLists.ChatsLoaded = {};
CND.chats.chatsLists.MessagesChatGroupId = 0;
CND.chats.chatsLists.MessagesLastLoaded = 0;
CND.chats.chatsLists.MessagesListLoaded = [];
CND.chats.chatsLists.MessagesLoaded = [];
CND.chats.chatsLists.LastRead = {};
CND.chats.chatsLists.LastScroll = {};
CND.chats.chatsLists.UnreadChats = {};
CND.chats.chatsLists.NotifiedChats = {};
CND.chats.chatsLists.Notifications = {};
CND.chats.debug = false;
CND.chats.EmojiRanges = '(\p{Emoji_Presentation}|\p{Extended_Pictographic})';
CND.chats.HasFocus = false;
CND.chats.IntervalErrorRefresh = 10000;
CND.chats.IntervalRefresh = 1000;
CND.chats.LastActive = 0;
CND.chats.LastBody = '';
CND.chats.LastSearch = null;
CND.chats.MessagesChatGroupId = 0;
CND.chats.TotalUnreadMsgs = 0;
CND.chats.UnixLast = 0;



// Functions
if (typeof CND.handleIsLoaded == 'undefined') {
    CND.handleIsLoadedWait = 1;
    CND.handleIsLoadedTimeout = null;
    CND.handleIsLoaded = function(fn='', successCallback=null, failureCallback=null, maxWait=10000, type='function') {
        if (!((typeof fn == 'string') && (fn !== ''))) { return; }
        clearTimeout(CND.handleIsLoadedTimeout);
        CND.handleIsLoadedTimeout = setTimeout(function() {
            if (typeof fn == type) {
                if (typeof successCallback == 'function') { setTimeout(function() { successCallback(); }, 1); }
            } else if ((typeof fn == 'string') && (typeof CND != 'undefined') && (typeof CND[fn] == type)) {
                if (typeof successCallback == 'function') { setTimeout(function() { successCallback(); }, 1); }
            } else if (CND.popup.handleIsLoadedWait < maxWait) {
                CND.handleIsLoadedWait = CND.handleIsLoadedWait + CND.handleIsLoadedWait * 3;
                CND.handleIsLoaded(fn, successCallback, failureCallback, maxWait);
            } else {
                if (typeof failureCallback == 'function') { setTimeout(function() { failureCallback(); }, 1); }
            } // end if fn
        }, CND.handleIsLoadedWait);
    }; // end function CND.handleIsLoaded
} // end if handleIsLoaded


CND.chats.handleOnWindowTimeout = null;
CND.chats.handleOnReady = function() {
    //CND.saveCurrentWindowPositionTimeout = setInterval(function() { CND.saveCurrentWindowPosition(); }, 1000);
    CND.jQueryLoader(function() {
        if (CND.chats.debug) { console.log('CND ready'); }
        CND.checkBodyIsCND(function() {
            if (CND.chats.debug) { console.log('Body is VAI CND Enabled'); }
            CND.getAccountInfo(function() {
                CND.chats.handleInit();
            });
        });
        CND.chats.saveChatsHasFocus();
    });
    window.addEventListener("blur", function() { CND.chats.handleWindowBlur(); });
    window.addEventListener("focus", function() { CND.chats.handleWindowFocus(); });
    window.addEventListener("beforeunload", function() { CND.saveCurrentWindowPosition(); });
    //window.addEventListener("mouseover", function() { CND.saveCurrentWindowPosition(); console.log('mouseover'); }); // These fire too often and are CPU intense
    //window.addEventListener("mouseout", function() { CND.saveCurrentWindowPosition(); console.log('mouseout'); }); // These fire too often and are CPU intense
    window.addEventListener("unload", function() { CND.saveCurrentWindowPosition(); });
    window.addEventListener("resize", function() { CND.chats.handleWindowResize(); });
}; // end function CND.chats.handleOnReady


CND.chats.handleWindowBlur = function() {
    if (CND.chats.debug) { console.log(CND.date.now(), 'window blur'); }
    CND.saveCurrentWindowPosition();
    CND.chats.saveChatsHasFocus();
    try {
        CND.dom('.chat-selected-active').addClass('chat-selected-inactive').removeClass('chat-selected-active');
    } catch (e) { console.log(e); }
}; // end function CND.chats.handleWindowBlur


CND.chats.handleWindowFocus = function() {
    if (CND.chats.debug) { console.log(CND.date.now(), 'window focus'); }
    CND.saveCurrentWindowPosition();
    CND.chats.saveChatsHasFocus();
    try {
        CND.dom('.chat-selected-inactive').addClass('chat-selected-active').removeClass('chat-selected-inactive');
        let active_badge = CND.dom('.chat-selected-active').find('.chat-list-item-badge');
        if (typeof active_badge != 'undefined') {
            active_badge.html('');
            CND.ui.hide(active_badge);
        }
    } catch (e) { console.log(CND.date.now(), e); }
}; // end function CND.chats.handleWindowFocus


CND.chats.handleWindowResize = function() {
    if (CND.chats.debug) { console.log(CND.date.now(), 'resize'); }
    clearTimeout(CND.chats.handleOnWindowTimeout);
    CND.chats.handleOnWindowTimeout = setTimeout(function() {
        if (CND.chats.debug) { console.log(CND.date.now(), 'resize timeout'); }
        CND.chats.saveChatsHasFocus();
        CND.saveCurrentWindowPosition();
        CND.chats.handleOnResizeTextarea("messages-send-msg-text");
    }, 100);
}; // end function CND.chats.handleWindowResize


CND.chats.handleInit = function() {
    CND.date.myLocalTZ.name();
    CND.chats.saveChatsHasFocus();

    if (CND.chats.debug) { console.log(CND.date.now(), 'in chats.handleInit'); }
    CND.chats.getChatsLocal(null, null, function() {
        try {
            CND.dom('#chats-list-search-input').val(CND.chats.LastSearch);
        } catch (e) { console.log(CND.date.now(), e); }
        CND.chats.showLoadChatsList();
    });
    try {
        CND.dom('#go_to_website').prop('href', CND.wwwUrl);
        CND.dom('#messages-send-msg-text').off('input').on('input', function(evt) {
            CND.chats.handleMessageInput(this, evt);
        });
        CND.dom('#chats-list-search-btn').off('click').on('click', function() {
            CND.chats.showLoadChatsList();
        });
        CND.dom('#chats-list-search-input').on('input', function() {
            CND.chats.handleSearchMsgsAuto();
        });
    } catch (e) { console.log(CND.date.now(), e); }
    CND.ui.handleFormEnter('#messages-send-msg-form', function(evt) {
        CND.chats.handleSendMsg();
    });
    CND.ui.handleFormEnter('#chats-list-search-form', function(evt) {
        if (CND.chats.debug) { console.log(CND.date.now(), 'enter event', evt); }
        CND.chats.showLoadChatsList();
    });
}; // end function CND.chats.handleInit


CND.chats.handleShowError = function(error_msg='', callbackFunction) {
    if (error_msg != '') { CND.ui.showError(error_msg); } else { CND.ui.hideError(); }
    CND.ui.hide('#chats-main-section');
    CND.ui.hide('#chats-loading-section');
    CND.ui.hide('#chats-offline-section');
    CND.ui.hide('#chats-menu-section');
    CND.ui.hide('#chats-menu-list');
    CND.ui.hide('#chats-menu-page-info');
    CND.ui.show('#chats-error-section');
    if (typeof callbackFunction == 'function') { setTimeout(function() { callbackFunction(); }, 1); }
}; // end function CND.chats.handleShowError


CND.chats.handleShowOffline = function(callbackFunction=null) {
    CND.ui.hideError();
    CND.ui.hide('#chats-main-section');
    CND.ui.hide('#chats-error-section');
    CND.ui.hide('#chats-loading-section');
    CND.ui.hide('#chats-menu-section');
    CND.ui.hide('#chats-menu-list');
    CND.ui.hide('#chats-menu-page-info');
    CND.ui.show('#chats-offline-section');
    if (typeof callbackFunction == 'function') { setTimeout(function() { callbackFunction(); }, 1); }
}; // end function CND.chats.handleShowOffline


CND.chats.handleShowMainLoading = function(callbackFunction=null) {
    CND.ui.hideError();
    CND.ui.hide('#chats-error-section');
    CND.ui.hide('#chats-offline-section');
    CND.ui.hide('#chats-main-section');
    CND.ui.hide('#chats-menu-section');
    CND.ui.hide('#chats-menu-list');
    CND.ui.hide('#chats-menu-page-info');
    CND.ui.show('#chats-loading-section');
    if (typeof callbackFunction == 'function') { setTimeout(function() { callbackFunction(); }, 1); }
}; // end function CND.chats.handleShowMainLoading


CND.chats.handleShowMain = function(callbackFunction=null) {
    CND.ui.hideError();
    CND.ui.hide('#chats-error-section');
    CND.ui.hide('#chats-offline-section');
    CND.ui.hide('#chats-loading-section');
    CND.ui.hide('#chats-list-search-spin');
    CND.ui.show('#chats-menu-section');
    CND.ui.show('#chats-menu-list');
    CND.ui.show('#chats-menu-page-info');
    CND.ui.show('#chats-list-search-btn');
    CND.ui.show('#chats-main-section');
    if (typeof callbackFunction == 'function') { setTimeout(function() { callbackFunction(); }, 1); }
}; // end function CND.chats.handleShowMain


CND.chats.handleShowChatsLoading = function(reset=false) {
    CND.chats.handleShowMsgsLoading(reset);
    try {
        if (reset) {
            CND.dom('#chats-list-scroll-div').html('');
            CND.dom('#chats-menu-page-info').find('.menu-page-info-icon').html('');
            CND.dom('#chats-menu-page-info').find('.menu-page-info-text').text('');
        } // end if reset
        let chats_loading = CND.dom('chat_list_loading_tpl').html();
        CND.dom('#chats-list-scroll-div').html(chats_loading);
    } catch (e) { console.log(CND.date.now(), e); }
    CND.ui.hide('#chats-menu-page-info');
    CND.ui.show('#chats-list-scroll-div');
}; // end function CND.chats.handleShowChatsLoading


CND.chats.handleShowMsgsLoading = function(reset=false) {
    CND.chats.handleShowMain();
    try {
        if (reset) {
            CND.dom('#messages-list-scroll-div').html('');
        } // end if reset
        let msgs_loading = CND.dom('#message_list_loading_tpl').html();
        CND.dom('#messages-list-scroll-div').html(msgs_loading);
    } catch (e) { console.log(CND.date.now(), e); }
    CND.ui.show('#messages-list-scroll-div');
}; // end function CND.chats.handleShowMsgsLoading


CND.chats.handleRemoveChatsLoading = function() {
    CND.chats.handleShowMain();
    try {
        CND.dom('#chats-list-scroll-div').find('.message-list-loading').remove();
    } catch (e) { console.log(CND.date.now(), e); }
    CND.ui.show('#chats-list-scroll-div');
}; // end function CND.chats.handleRemoveChatsLoading


CND.chats.handleRemoveMsgsLoading = function() {
    CND.chats.handleShowMain();
    try {
        CND.dom('#messages-list-scroll-div').find('.message-list-loading').remove();
    } catch (e) { console.log(CND.date.now(), e); }
    CND.ui.show('#messages-list-scroll-div');
}; // end function CND.chats.handleRemoveMsgsLoading


CND.chats.allowClickChatsList = true;
CND.chats.handleClickChatsList = function(e=null) {
  if (CND.chats.allowClickChatsList) {
    CND.chats.allowClickChatsList = false;
    var chat_group_id = parseInt(CND.dom(e).attr('data-chat-group-id'));
    if (typeof CND.chats.LastActive == 'undefined') { CND.chats.saveChatsLocal(0, CND.chats.LastSearch, CND.chats.chatsLists); }
    if (CND.chats.LastActive !== chat_group_id) {
        clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
        clearTimeout(CND.chats.loadChatsListTimeout);
        //CND.chats.unhandleOnClickChatsList('#chats-list-scroll-div');
        if (CND.chats.debug) { console.log(CND.date.now(), 'Clicked on chat group', chat_group_id); }
        CND.chats.saveChatsLocal(chat_group_id, CND.chats.LastSearch, CND.chats.chatsLists);
        CND.dom('#chats-list-scroll-div').find('.chat-list-item:not([data-chat-group-id="' + chat_group_id + '"])').removeClass('chat-selected').removeClass('chat-selected-active');
        CND.dom('#chats-list-scroll-div').find('.chat-list-item[data-chat-group-id="' + chat_group_id + '"]').addClass('chat-selected').addClass('chat-selected-active');
        if (CND.chats.debug) { console.log(CND.date.now(), 'selected', chat_group_id); }
        CND.chats.handleShowMsgsLoading();
        clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
        clearTimeout(CND.chats.loadChatsListTimeout);
        CND.chats.LastActive = parseInt(chat_group_id);
        CND.chats.loadChatsListTimeout = setTimeout(function() { CND.chats.loadChatsList(); }, 1);
    } // end if chat_group_id
  } // end if CND.chats.allowClickChatsList
}; // end function CND.chats.handleClickChatsList


CND.chats.unhandleOnClickChatsList = function(element=null) {
    try {
        CND.dom(element).find('.chat-list-item').off('click');
    } catch (e) { console.log(CND.date.now(), e); }
}; // end function CND.chats.unhandleOnClickChatsList


CND.chats.handleOnClickChatsList = function(element=null) {
    try {
        CND.dom(element).find('.chat-list-item').off('click').on('click', function() {
            let e = this;
            //if (!CND.dom(e).hasClass('chat-selected')) {
                CND.chats.handleClickChatsList(e);
            //} // end if chat-selected
        }); // end click chat-list-item
        CND.dom(element).find('.chat-list-item-delete-btn').off('click').on('click', function() {
            let e = this;
            CND.chats.handleClickDeleteChat(e);
        }); // end click chat-list-item
    } catch (e) { console.log(CND.date.now(), e); }
}; // end function CND.chats.handleOnClickChatsList


CND.chats.handleClickDeleteChat = function(element=null) {
    let parent = CND.dom(element).closest('.chat-list-item');
    var chat_group_id = CND.dom(parent).attr('data-chat-group-id');
    if (chat_group_id && (chat_group_id !== null)) {
        let chat_contacts = CND.dom(parent).find('.chat-list-item-contacts').text();
        if (confirm('Delete Messages for ' + chat_contacts + '?')) {
            CND.chats.handleDeleteChat(chat_group_id);
        } // end if confirm
    } // end if chat_group_id
}; // end function CND.chats.handleClickDeleteChat


CND.chats.handleDeleteChat = function(chat_group_id=0) {
    clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
    clearTimeout(CND.chats.loadChatsListTimeout);
    let domain = CND.accountSettings.domain ?? CND.defaultSettings.domain ?? '';
    let extension = CND.accountSettings.extension ?? CND.defaultSettings.extension ?? '';
    let apikey = CND.accountSettings.apikey ?? '';
    var search = document.getElementById('chats-list-search-input').value;
    if (typeof CND.chats.LastActive == 'undefined') { CND.chats.saveChatsLocal(0, search, CND.chats.chatsLists); }
    if (apikey != '') {
        let requestApiUrl = CND.getApiUrl(domain, true);
        let dataInputs = {
            'action': 'delete_chat',
            'domain': domain,
            'key': apikey,
            'group': chat_group_id
        };
        CND.ajax({
            type: 'POST',
            dataType: 'json',
            url: requestApiUrl,
            data: dataInputs,
            error: function(xhr, error, message) {
                clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
                clearTimeout(CND.chats.loadChatsListTimeout);

                if (CND.chats.debug) { console.log(CND.date.now(), 'error', requestApiUrl, xhr, error, message); }
                try {
                    if (typeof xhr.status != 'undefined') {
                        if (xhr.status == 403) { CND.loadExtensionPage('settings.html'); }
                    }
                } catch (e) { console.log(CND.date.now(), e); }
            }, // end ajax error
            offline: function() {
                clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
                clearTimeout(CND.chats.loadChatsListTimeout);

                CND.chats.handleShowOffline();
            }, // end ajax offline
            success: function(data) {
                clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
                clearTimeout(CND.chats.loadChatsListTimeout);

                if (CND.chats.debug) { console.log(CND.date.now(), 'success', requestApiUrl, dataInputs, data); }
                if ((data.status == true) || (data.status == 1)) {
                    CND.dom('#chats-list-scroll-div').find('.chat-list-item[data-chat-group-id="' + chat_group_id + '"]').remove();
                    if (chat_group_id == CND.chats.LastActive) {
                        CND.dom('#chats-menu-page-info').find('.menu-page-info-icon').html('');
                        CND.dom('#chats-menu-page-info').find('.menu-page-info-text').text('');
                        CND.chats.saveChatsLocal(0, search, CND.chats.chatsLists);
                        CND.chats.loadChatsListTimeout = setTimeout(function() { CND.chats.handleShowMainLoading(); CND.chats.loadChatsList(); }, 100);
                    } else {
                        CND.chats.loadChatsListTimeout = setTimeout(function() { CND.chats.loadChatsList(); }, 100);
                    } // end if CND.chats.LastActive
                } // end if data.status
            } // end ajax success
        }); // end ajax
    } else {
        CND.loadExtensionPage('settings.html');
        return false;
    } // end if apikey
    return true;
}; // end function CND.chats.handleDeleteChat


CND.chats.handleOnResizeTextarea = function(id='messages-send-msg-text') {
    let ml = document.getElementById(id);
    CND.chats.autoHeightMessageInput(ml, 42, 142, 8); // fix the messages-list
}; // end function CND.chats.handleOnResizeTextarea


CND.chats.isLoading = function(element) {
    il = false;
    try {
        let found = CND.dom(element).find('.loading-icon').length;
        if (found) { il = true; }
    } catch (e) { console.log(CND.date.now(), e); }
    return il;
}; // end function CND.chats.isLoading


CND.chats.autoHeightMessageInput = function(e=null, min=42, max=142, pad=8) {
    e.style.height = '1px';
    let h = e.scrollHeight;
    if (h < min) { h = min; }
    if (h > max) { h = max; }
    e.style.height = h + 'px';
    h = h + pad;
    let p = document.getElementById('messages-list-footer');
    p.style.height = h + 'px';
    let s = document.getElementById('messages-list-col');
    h = s.clientHeight - h;
    let u = document.getElementById('messages-list');
    u.style.height = h + 'px';
    let us = document.getElementById('messages-list-scroll-div');
    us.style.height = h + 'px';
    let ush = us.scrollHeight ?? 0;
    let ust = us.scrollTop || us.scrollY;
    if (ust < ush) {
        us.scrollTo(0, ush);
    }
}; // end function CND.chats.autoHeightMessageInput


CND.chats.getChatsLocalLite = function(callbackFunction=null) {
    // Get information from the Cookies. Nom Nom
    chrome.storage.local.get([ 'chats_has_focus', 'chats_active_id', 'chats_search' ], function(items) {
        //console.log(CND.date.now(), items);
        CND.chats.HasFocus = items.chats_has_focus ?? false;
        CND.chats.LastActive = items.chats_active_id ?? -1;
        CND.chats.LastSearch = items.chats_search ?? null;
        //console.log(CND.date.now(), items);
        if (typeof callbackFunction == 'function') {
            setTimeout(function() { callbackFunction(); }, 1);
        }
    }); // end chrome.storage.local.get
}; // end function CND.chats.getChatsLocalLite


CND.chats.getBackgroundChatsLocal = function(callbackFunction=null) {
    // Get information from the Cookies. Nom Nom
    chrome.storage.local.get([ 'chats_bg_active', 'chats_bg_lists' ], function(items) {
        //console.log(CND.date.now(), items);
        CND.chats.bgLastActive = items.chats_bg_active ?? CND.chats.LastActive ?? -1;
        CND.chats.bgChatsLists = items.chats_bg_lists ?? CND.chats.chatsLists ?? {};
        if (typeof CND.chats.bgChatsLists.ChatsLastLoaded == 'undefined') { CND.chats.bgChatsLists.ChatsLastLoaded = 0; }
        if (typeof CND.chats.bgChatsLists.ChatsListLoaded == 'undefined') { CND.chats.bgChatsLists.ChatsListLoaded = {}; }
        if (typeof CND.chats.bgChatsLists.ChatsLoaded == 'undefined') { CND.chats.bgChatsLists.ChatsLoaded = {}; }
        if (typeof CND.chats.bgChatsLists.MessagesChatGroupId == 'undefined') { CND.chats.bgChatsLists.MessagesChatGroupId = 0; }
        if (typeof CND.chats.bgChatsLists.MessagesLastLoaded == 'undefined') { CND.chats.bgChatsLists.MessagesLastLoaded = 0; }
        if (typeof CND.chats.bgChatsLists.MessagesListLoaded == 'undefined') { CND.chats.bgChatsLists.MessagesListLoaded = []; }
        if (typeof CND.chats.bgChatsLists.MessagesLoaded == 'undefined') { CND.chats.bgChatsLists.MessagesLoaded = []; }
        if (typeof CND.chats.bgChatsLists.LastRead == 'undefined') { CND.chats.bgChatsLists.LastRead = {}; }
        if (typeof CND.chats.bgChatsLists.LastScroll == 'undefined') { CND.chats.bgChatsLists.LastScroll = {}; }
        if (typeof CND.chats.bgChatsLists.UnreadChats == 'undefined') { CND.chats.bgChatsLists.UnreadChats = {}; }
        if (typeof CND.chats.bgChatsLists.NotifiedChats == 'undefined') { CND.chats.bgChatsLists.NotifiedChats = {}; }
        if (typeof CND.chats.bgChatsLists.Notifications == 'undefined') { CND.chats.bgChatsLists.Notifications = {}; }
        //console.log(CND.date.now(), items);
        if (typeof callbackFunction == 'function') {
            setTimeout(function() { callbackFunction(); }, 1);
        }
    }); // end chrome.storage.local.get
}; // end function CND.chats.getChatsLocal


CND.chats.getChatsLocal = function(successCallback=null, failureCallback=null, alwaysCallback=null) {
    // Get information from the Cookies. Nom Nom
    chrome.storage.local.get([ 'chats_active_id', 'chats_search', 'chats_lists', 'chat_group_ids' ], function(items) {
        //console.log(CND.date.now(), items);
        CND.chats.LastActive = items.chats_active_id ?? -1;
        CND.chats.LastSearch = items.chats_search ?? null;
        CND.chats.chatsLists = items.chats_lists ?? CND.chats.chatsLists ?? {};
        CND.chats.chatGroupIds = items.chat_group_ids ?? CND.chats.chatGroupIds ?? [];
        if (typeof CND.chats.chatsLists.ChatsLastLoaded == 'undefined') { CND.chats.chatsLists.ChatsLastLoaded = 0; }
        if (typeof CND.chats.chatsLists.ChatsListLoaded == 'undefined') { CND.chats.chatsLists.ChatsListLoaded = {}; }
        if (typeof CND.chats.chatsLists.ChatsLoaded == 'undefined') { CND.chats.chatsLists.ChatsLoaded = {}; }
        if (typeof CND.chats.chatsLists.MessagesChatGroupId == 'undefined') { CND.chats.chatsLists.MessagesChatGroupId = 0; }
        if (typeof CND.chats.chatsLists.MessagesLastLoaded == 'undefined') { CND.chats.chatsLists.MessagesLastLoaded = 0; }
        if (typeof CND.chats.chatsLists.MessagesListLoaded == 'undefined') { CND.chats.chatsLists.MessagesListLoaded = []; }
        if (typeof CND.chats.chatsLists.MessagesLoaded == 'undefined') { CND.chats.chatsLists.MessagesLoaded = []; }
        if (typeof CND.chats.chatsLists.LastRead == 'undefined') { CND.chats.chatsLists.LastRead = {}; }
        if (typeof CND.chats.chatsLists.LastScroll == 'undefined') { CND.chats.chatsLists.LastScroll = {}; }
        if (typeof CND.chats.chatsLists.UnreadChats == 'undefined') { CND.chats.chatsLists.UnreadChats = {}; }
        if (typeof CND.chats.chatsLists.NotifiedChats == 'undefined') { CND.chats.chatsLists.NotifiedChats = {}; }
        if (typeof CND.chats.chatsLists.Notifications == 'undefined') { CND.chats.chatsLists.Notifications = {}; }
        if (CND.chats.LastActive > -1) {
            if (typeof successCallback == 'function') {
                setTimeout(function() { successCallback(); }, 1);
            }
        } else {
            if (typeof failureCallback == 'function') {
                setTimeout(function() { failureCallback(); }, 1);
            }
        } // end if valid
        //console.log(CND.date.now(), items);
        if (typeof alwaysCallback == 'function') {
            setTimeout(function() { alwaysCallback(); }, 1);
        }
    }); // end chrome.storage.local.get
}; // end function CND.chats.getChatsLocal


CND.chats.saveChatsHasFocus = function(h=null) {
    if (h === null) {
        h = CND.hasFocus();
    }
    chrome.storage.local.set({ 'chats_has_focus' : h }, function() {
        CND.chats.HasFocus = h;
    }); // end set storage
}; // end function CND.chats.saveChatsHasFocus


CND.chats.saveChatsLocal = function(a=0, s=null, l={}, g=null, h=null, callbackFunction=null) {
    // Set information from the Cookies. Nom Nom
    if (typeof l.LastRead == 'undefined') {
        l = CND.chats.chatsLists;
    } // end if l
    if (g === null) {
        g = CND.chats.chatGroupIds;
    }
    if (h === null) {
        h = CND.hasFocus();
    }
    chrome.storage.local.set({ 'chats_active_id' : a, 'chats_search' : s, 'chats_lists' : l, 'chats_has_focus' : h, 'chat_group_ids': g }, function() {
        CND.chats.LastActive = a;
        CND.chats.LastSearch = s;
        CND.chats.chatsLists = l;
        CND.chats.HasFocus = h;
        CND.chats.chatGroupIds = g;
        if (typeof callbackFunction == 'function') {
            setTimeout(function() { callbackFunction(); }, 1);
        }
    }); // end set storage
}; // end function CND.chats.saveChatsLocal


CND.chats.resetChatsLocal = function(callbackFunction=null) {
    CND.chats.LastActive = 0;
    CND.chats.chatGroupIds = [];
    CND.chats.chatsLists = {};
    CND.chats.chatsLists.ChatsLastLoaded = 0;
    CND.chats.chatsLists.ChatsListLoaded = {};
    CND.chats.chatsLists.ChatsLoaded = {};
    CND.chats.chatsLists.MessagesChatGroupId = 0;
    CND.chats.chatsLists.MessagesLastLoaded = 0;
    CND.chats.chatsLists.MessagesListLoaded = [];
    CND.chats.chatsLists.MessagesLoaded = [];
    CND.chats.chatsLists.LastRead = {};
    CND.chats.chatsLists.LastScroll = {};
    CND.chats.chatsLists.UnreadChats = {};
    CND.chats.chatsLists.NotifiedChats = {};
    CND.chats.chatsLists.Notifications = {};
    let h = CND.hasFocus();
    CND.chats.saveChatsLocal(CND.chats.LastActive, CND.chats.LastSearch, CND.chats.chatsLists, CND.chats.chatGroupIds, h, callbackFunction);
}; // end function CND.chats.resetChatsLocal


CND.chats.handleMessageInput = function(element, evt) {
    //console.log(CND.date.now(), 'input event', evt);
    clearTimeout(CND.chats.handleMonitorSendMsgTimeout);
    CND.chats.handleMonitorSendMsgTimeout = setTimeout(function() { CND.chats.handleMonitorSendMsg(); }, 1);
    CND.chats.autoHeightMessageInput(element, 42, 142, 8);
}; // end function CND.chats.handleMessageInput


CND.chats.handleMonitorSendMsgTimeout = null;
CND.chats.handleMonitorSendMsg = function() {
    let body = CND.dom('#messages-send-msg-text').val();
        body = body.toString().trim();
    if (CND.chats.LastBody !== body) {
        CND.chats.LastBody = body;
        if (body != '') {
            CND.chats.handleClickActionMsgBtn();
        } else {
            CND.chats.unhandleClickActionMsgBtn();
        } // end if body
    } // end if CND.chats.LastBody
}; // end function CND.chats.handleMonitorSendMsg


CND.chats.handleClickActionMsgBtn = function() {
    CND.dom('#messages-send-msg-btn').removeClass('send-msg-btn').removeClass('send-msg-btn-disabled').addClass('send-msg-btn').off('click').on('click', function() {
        CND.chats.handleClickActionMsg();
    });
}; // end function CND.chats.unhandleClickActionMsgBtn


CND.chats.unhandleClickActionMsgBtn = function() {
    CND.dom('#messages-send-msg-btn').removeClass('send-msg-btn').removeClass('send-msg-btn-disabled').addClass('send-msg-btn-disabled').off('click');
}; // end function CND.chats.unhandleClickActionMsgBtn


CND.chats.handleClickActionMsg = function() {
    let sending = CND.dom('#messages-send-msg-btn').attr('data-sending-msg');
    if ((sending == true) || (sending == 'true')) {
        CND.chats.handleCancelMsg();
    } else {
        CND.chats.handleSendMsg();
    } // end if sending
}; // end function CND.chats.handleClickActionMsg


CND.chats.handleCancelMsg = function() {
    try {
        clearTimeout(CND.chats.handleSendMsgTimeout);
        CND.dom('#messages-send-msg-btn').attr('data-sending-msg', false);
        CND.ui.hide('#messages-send-msg-btn-loading');
        CND.ui.show('#messages-send-msg-btn-send');
    } catch (e) { console.log(CND.date.now(), e); }
    CND.chats.handleOnResizeTextarea("messages-send-msg-text");
}; // end function CND.chats.handleCancelMsg


CND.chats.handleSendMsg = function() {
    try {
        var chat_group_id = parseInt(CND.chats.LastActive);
        let body = CND.dom('#messages-send-msg-text').val().toString().trim();
        let destinations = []; // TODO TODO -- Needed for "New Message" only
        if (body != '') {
            CND.dom('#messages-send-msg-btn').attr('data-sending-msg', true);
            CND.ui.hide('#messages-send-msg-btn-send');
            CND.ui.show('#messages-send-msg-btn-loading');
            CND.chats.handleSendMsgTimeout = setTimeout(function() {
                CND.chats.sendMsg(chat_group_id, body, destinations);
            }, 1);
        } // end if body
    } catch (e) { console.log(CND.date.now(), e); }
    CND.chats.handleOnResizeTextarea("messages-send-msg-text");
}; // end function CND.chats.handleSendMsg


CND.chats.sendMsg = function(chat_group_id=0, body='', destinations) {
    if (CND.chats.debug) { console.log(CND.date.now(), 'CND.accountSettings', CND.accountSettings); }
    let domain = CND.accountSettings.domain ?? CND.defaultSettings.domain ?? '';
    let extension = CND.accountSettings.extension ?? CND.defaultSettings.extension ?? '';
    let apikey = CND.accountSettings.apikey ?? '';
    if (apikey != '') {
        //return CND.wss.sendMsg(true, body, chat_group_id);

        let requestApiUrl = CND.getApiUrl(domain, true);
        let dataInputs = {
            'action': 'send_msg',
            'domain': domain,
            'key': apikey,
            'group': chat_group_id,
            'body': body
        };
        CND.ajax({
            type: 'POST',
            dataType: 'json',
            url: requestApiUrl,
            data: dataInputs,
            error: function(xhr, error, message) {
                clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
                clearTimeout(CND.chats.loadChatsListTimeout);

                if (CND.chats.debug) { console.log(CND.date.now(), 'error', requestApiUrl, xhr, error, message); }
                if (typeof xhr.status != 'undefined') {
                    if (xhr.status == 403) { CND.loadExtensionPage('settings.html'); }
                }
                CND.chats.handleShowError('Message Failed to Send!', function() {
                    clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
                    clearTimeout(CND.chats.loadChatsListTimeout);
                    CND.chats.loadChatsListTimeout = setTimeout(function() { CND.chats.handleShowMainLoading(); CND.chats.loadChatsList(); }, CND.chats.IntervalErrorRefresh);
                });
            }, // end ajax error
            offline: function() {
                clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
                clearTimeout(CND.chats.loadChatsListTimeout);

                CND.chats.handleShowOffline();
            }, // end ajax offline
            success: function(data) {
                clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
                clearTimeout(CND.chats.loadChatsListTimeout);

                if (CND.chats.debug) { console.log(CND.date.now(), 'success', requestApiUrl, dataInputs, data); }
                if ((data.status == true) || (data.status == 1)) {
                    //console.log(CND.date.now(), 'message body', body);
                    CND.chats.sendMsgSuccess();
                    clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
                    clearTimeout(CND.chats.loadChatsListTimeout);
                    CND.chats.loadChatsListTimeout = setTimeout(function() { CND.chats.loadChatsList(); }, 2000);
                } // end if data.status
            } // end ajax success
        }); // end ajax
    } else {
        CND.loadExtensionPage('settings.html');
        return false;
    } // end if apikey
    return true;
}; // end function CND.chats.sendMsg


CND.chats.sendMsgSuccess = function() {
    CND.chats.unhandleClickActionMsgBtn();
    CND.dom('#messages-send-msg-text').val('');
    CND.chats.handleMessageInput(CND.dom('#messages-send-msg-text')[0], null);
    CND.dom('#messages-send-msg-btn').attr('data-sending-msg', false);
    CND.ui.hide('#messages-send-msg-btn-loading');
    CND.ui.show('#messages-send-msg-btn-send');
    clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
    clearTimeout(CND.chats.loadChatsListTimeout);
    //CND.chats.loadChatsListTimeout = setTimeout(function() { CND.chats.loadChatsList(); }, 1);
}; // end function CND.chats.sendMsgSuccess


CND.chats.handleSearchMsgsAutoTimeout = null;
CND.chats.handleSearchMsgsAuto = function() {
    clearTimeout(CND.chats.handleSearchMsgsAutoTimeout);
    var search = CND.dom('#chats-list-search-input').val();
    search = search.toString().trim();
    if (search !== CND.chats.LastSearch) {
        if (CND.chats.debug) { console.log(CND.date.now(), 'search', search); }
        CND.ui.hide('#chats-list-search-btn');
        CND.ui.show('#chats-list-search-spin');
        CND.chats.handleSearchMsgsAutoTimeout = setTimeout(function() {
            CND.chats.handleLoadSearchMsgs();
        }, 500);
    } // end if search
}; // end function CND.chats.handleSearchMsgsAuto


CND.chats.handleLoadSearchMsgs = function() {
    clearTimeout(CND.chats.handleSearchMsgsAutoTimeout);
    var search = CND.dom('#chats-list-search-input').val();
    search = search.toString().trim();
    if (CND.chats.debug) { console.log(CND.date.now(), 'search', search, 'last_search', CND.chats.LastSearch); }
    if (search !== CND.chats.LastSearch) {
        CND.chats.LastSearch = search;
        CND.chats.handleShowChatsLoading(true);
        CND.chats.loadChatsList();
    } else {
        CND.ui.hide('#chats-list-search-spin');
        CND.ui.show('#chats-list-search-btn');
    } // end if lastSearch
}; // end function CND.chats.handleLoadSearchMsgs


CND.chats.handleSearchMsgs = function(callbackFunction=null) {
    clearTimeout(CND.chats.handleSearchMsgsAutoTimeout);
    var search = CND.dom('#chats-list-search-input').val();
    search = search.toString().trim();
    if (search != '') {
        if (CND.chats.debug) { console.log(CND.date.now(), 'search', search); }
        CND.chats.chatsListView = CND.getSearchResults(CND.chats.chatsLists.ChatsListLoaded, search, true);
        CND.chats.messagesListView = CND.getSearchResults(CND.chats.chatsLists.MessagesListLoaded, search, true);
        if (CND.chats.debug) { console.log(CND.date.now(), 'chats', CND.chats.chatsListView); }
        if (CND.chats.debug) { console.log(CND.date.now(), 'msgs', CND.chats.messagesListView); }
        CND.chats.LastSearch = search;
        setTimeout(function() {
            CND.chats.updateChatsListHtml(CND.chats.chatsListView, function() {
                CND.chats.updateMessagesListHtml(CND.chats.messagesListView, function() {
                    CND.chats.handleShowMain(callbackFunction);
                }); // end CND.chats.updateMessagesListHtml
            }); // end CND.chats.updateChatsListHtml
        }, 1); // end setTimeout
    } else {
        CND.chats.LastSearch = '';
        CND.chats.handleClearSearchMsgs(callbackFunction);
    } // end if search
}; // end function CND.chats.handleSearchMsgs


CND.chats.handleClearSearchMsgs = function(callbackFunction=null) {
    if (CND.chats.debug) { console.log(CND.date.now(), 'clear search'); }
    CND.chats.chatsListView = CND.chats.chatsLists.ChatsListLoaded;
    CND.chats.messagesListView = CND.chats.chatsLists.MessagesListLoaded;
    setTimeout(function() {
        CND.chats.updateChatsListHtml(CND.chats.chatsListView, function() {
            CND.chats.updateMessagesListHtml(CND.chats.messagesListView, function() {
                CND.chats.handleShowMain(callbackFunction);
            }); // end CND.chats.updateMessagesListHtml
        }); // end CND.chats.updateChatsListHtml
    }, 1); // end setTimeout
}; // end function CND.chats.handleClearSearchMsgs


CND.chats.isOnlyEmojis = function(str='') {
    //console.log(CND.date.now(), 'CND.chats.EmojiRanges', CND.chats.EmojiRanges);
    str = str.toString().trim();
    let regex = /(\p{Emoji_Presentation}|\p{Extended_Pictographic})/gu;
    let emoji = str.match(regex);
    let text = str.replace(regex, '').replace(/[^\x00-\x7F]/g, '').trim();
    let el = 0, tl = 0;
    if ((emoji !== null) && (typeof emoji == 'object')) { el = emoji.length; }
    if ((text !== null) && (typeof text == 'string')) { tl = text.length; }
    //console.log(CND.date.now(), 'str', str);
    //console.log(CND.date.now(), 'emoji', emoji, typeof emoji, el)
    //console.log(CND.date.now(), 'text', text, typeof text, tl);
    if ((el > 0) && (tl == 0)) {
        if (CND.chats.debug) { console.log(CND.date.now(), 'CND.chats.isOnlyEmojis:true'); }
        return true;
    }
    //console.log(CND.date.now(), 'CND.chats.isOnlyEmojis:false');
    return false;
}; // end function CND.chats.isOnlyEmojis


CND.chats.showLoadChatsList = function() {
    CND.chats.handleShowMainLoading();
    CND.chats.loadChatsList();
}; // end function CND.chats.showLoadChatsList


CND.chats.loadBackgroundChatsListTimeout = null;
CND.chats.loadBackgroundChatsList = function() {
    clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
    clearTimeout(CND.chats.loadChatsListTimeout);
    CND.chats.getBackgroundChatsLocal(function() {
        bg_active = CND.chats.bgLastActive ?? -1;
        lc_active = CND.chats.LastActive ?? -1;
        bg_chat_last = CND.chats.bgChatsLists.ChatsLastLoaded ?? 0;
        lc_chat_last = CND.chats.chatsLists.ChatsLastLoaded ?? 0;
        bg_msgs_last = CND.chats.bgChatsLists.MessagesLastLoaded ?? 0;
        lc_msgs_last = CND.chats.chatsLists.MessagesLastLoaded ?? 0;
        //console.log(CND.date.now(), 'active', bg_active, lc_active);
        //console.log(CND.date.now(), 'chat_last', bg_chat_last, lc_chat_last);
        //console.log(CND.date.now(), 'msgs_last', bg_msgs_last, lc_msgs_last);
        if ((bg_active == lc_active) && ((bg_chat_last > lc_chat_last) || (bg_msgs_last > lc_msgs_last))) {
            CND.chats.chatsLists = CND.chats.bgChatsLists;
            //console.log(CND.date.now(), 'active', bg_active, lc_active);
            //console.log(CND.date.now(), 'chat_last', bg_chat_last, lc_chat_last);
            //console.log(CND.date.now(), 'msgs_last', bg_msgs_last, lc_msgs_last);
            setTimeout(function() { CND.chats.handleSearchMsgs(function() {
                clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
                //CND.chats.loadBackgroundChatsListTimeout = setTimeout(function() { CND.chats.loadBackgroundChatsList(); }, CND.chats.IntervalRefresh);
            }); }, 1);
        } else {
            //console.log(CND.date.now(), 'active', bg_active, lc_active);
            //console.log(CND.date.now(), 'chat_last', bg_chat_last, lc_chat_last);
            //console.log(CND.date.now(), 'msgs_last', bg_msgs_last, lc_msgs_last);
            setTimeout(function() { CND.chats.handleSearchMsgs(function() {
                clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
                //CND.chats.loadBackgroundChatsListTimeout = setTimeout(function() { CND.chats.loadBackgroundChatsList(); }, CND.chats.IntervalRefresh);
            }); }, 1);
        } // end if last
    }); // end CND.chats.getBackgroundChatsLocal
}; // end function CND.chats.loadBackgroundChatsList


CND.chats.loadChatsListTimeout = null;
CND.chats.loadChatsList = function() {
    clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
    clearTimeout(CND.chats.loadChatsListTimeout);
    let last = CND.chats.UnixLast ?? 0;
    let domain = CND.accountSettings.domain ?? CND.defaultSettings.domain ?? '';
    let extension = CND.accountSettings.extension ?? CND.defaultSettings.extension ?? '';
    let apikey = CND.accountSettings.apikey ?? '';
    var search = document.getElementById('chats-list-search-input').value;
    var chat_group_id = parseInt(CND.chats.LastActive);
    let hasFocus = CND.hasFocus();
    let lastRead = CND.chats.chatsLists.LastRead ?? {};
    if (apikey != '') {
        if (typeof CND.chats.LastActive == 'undefined') { CND.chats.saveChatsLocal(0, search, CND.chats.chatsLists, CND.chats.chatGroupIds, hasFocus); }
        let requestApiUrl = CND.getApiUrl(domain, true);
        let dataInputs = {
            'action': 'get_chats',
            'domain': domain,
            'key': apikey,
            'search': search,
            'active': chat_group_id,
            'hasFocus': hasFocus,
            'lastRead': lastRead,
            'last': last
        };
        CND.ajax({
            type: 'POST',
            dataType: 'json',
            url: requestApiUrl,
            data: dataInputs,
            error: function(xhr, error, message) {
                clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
                clearTimeout(CND.chats.loadChatsListTimeout);

                if (CND.chats.debug) { console.log(CND.date.now(), 'error', requestApiUrl, xhr, error, message); }
                if (typeof xhr.status != 'undefined') {
                    if (xhr.status == 403) { CND.loadExtensionPage('settings.html'); }
                }
                let chatsErrorMsg = 'Connection to Server Failed.';
                if (xhr.status != 0) {
                  chatsErrorMsg += ' Error: ' + xhr.status + ' ' + error;
                } else {
                  chatsErrorMsg += ' Error: Server is offline or is not responding.';
                }
                CND.chats.handleShowError(chatsErrorMsg, function() {
                    clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
                    clearTimeout(CND.chats.loadChatsListTimeout);
                    CND.dom('#cnd-reset-all-extension-settings').off('click').on('click', function() { CND.resetAllSettings(); return false; });
                    CND.chats.loadChatsListTimeout = setTimeout(function() { CND.chats.handleShowMainLoading(); CND.chats.loadChatsList(); }, CND.chats.IntervalErrorRefresh);
                });
            }, // end ajax error
            offline: function() {
                clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
                clearTimeout(CND.chats.loadChatsListTimeout);

                CND.chats.handleShowOffline();
            }, // end ajax offline
            success: function(data) {
                clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
                clearTimeout(CND.chats.loadChatsListTimeout);

                if (CND.chats.debug) { console.log(CND.date.now(), 'success', requestApiUrl, dataInputs, data); }
                if ((data.status == true) || (data.status == 1)) {
                    //console.log(CND.date.now(), data);
                    if (typeof chat_group_id == 'undefined') { console.log(CND.date.now(), data); chat_group_id = 0; }
                    CND.chats.updateChatsList(data);
                    if (CND.hasFocus()) {
                        CND.dom('#chats-list-scroll-div').find('.chat-list-item[data-chat-group-id="' + chat_group_id + '"]').find('.chat-list-item-badge').html('');
                        CND.dom('#chats-list-scroll-div').find('.chat-list-item[data-chat-group-id="' + chat_group_id + '"]').find('.chat-list-item-badge').each(function() { CND.ui.hide(CND.dom(this)); });
                    }
                    let active = parseInt(data.active ?? 0);
                    if (CND.chats.LastActive !== active) { CND.chats.saveChatsLocal(active, search, CND.chats.chatsLists); }
                    let unread = data.unread ?? 0;
                    CND.chats.UnixLast = data.last ?? last;
                    let chats = data.chats ?? {};
                    let msgs = data.msgs ?? [];
                    CND.chats.chatsLists.LastRead = data.lastRead ?? CND.chats.chatsLists.LastRead ?? {};
                    CND.chats.chatsLists.UnreadChats = data.unreadChats ?? CND.chats.chatsLists.UnreadChats ?? {};
                    CND.chats.chatsLists.ChatsListLoaded = chats;
                    CND.chats.chatsLists.MessagesListLoaded = msgs;
                    //setTimeout(function() { CND.chats.handleSearchMsgs(); }, 1);
                    //setTimeout(function() { CND.chats.handleSearchMsgs(function() {
                        //clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
                        //clearTimeout(CND.chats.loadChatsListTimeout);
                        //CND.chats.loadBackgroundChatsListTimeout = setTimeout(function() { CND.chats.loadBackgroundChatsList(); }, CND.chats.IntervalRefresh);
                    //}); }, 1);
                } else if (typeof data.error != 'undefined') {
                    CND.chats.handleShowError(data.error, function() {
                        clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
                        clearTimeout(CND.chats.loadChatsListTimeout);
                        CND.chats.loadChatsListTimeout = setTimeout(function() { CND.chats.handleShowMainLoading(); CND.chats.loadChatsList(); }, CND.chats.IntervalErrorRefresh);
                    });
                } else {
                    CND.chats.handleShowError('An error occurred loading the chats list.', function() {
                        clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
                        clearTimeout(CND.chats.loadChatsListTimeout);
                        CND.chats.loadChatsListTimeout = setTimeout(function() { CND.chats.handleShowMainLoading(); CND.chats.loadChatsList(); }, CND.chats.IntervalErrorRefresh);
                    });
                } // end if data.status
            } // end ajax success
        }); // end ajax
    } else {
        CND.loadExtensionPage('settings.html');
        return false;
    } // end if apikey
    return true;
}; // end function CND.chats.loadChatsList


CND.chats.updateChatsList = function(data={}) {
    if (typeof chat_group_id == 'undefined') { var chat_group_id = 0; }
    if (typeof search == 'undefined') { var search = ''; }
    //console.log(CND.date.now(), data);
    if (CND.hasFocus()) {
        CND.dom('#chats-list-scroll-div').find('.chat-list-item[data-chat-group-id="' + chat_group_id + '"]').find('.chat-list-item-badge').html('');
        CND.dom('#chats-list-scroll-div').find('.chat-list-item[data-chat-group-id="' + chat_group_id + '"]').find('.chat-list-item-badge').each(function() { CND.ui.hide(CND.dom(this)); });
    }
    let active = parseInt(data.active ?? 0);
    if (CND.chats.LastActive !== active) { CND.chats.saveChatsLocal(active, search, CND.chats.chatsLists); }
    let unread = data.unread ?? 0;
    CND.chats.UnixLast = data.last ?? last;
    let chats = data.chats ?? {};
    let msgs = data.msgs ?? [];
    CND.chats.chatsLists.LastRead = data.lastRead ?? CND.chats.chatsLists.LastRead ?? {};
    CND.chats.chatsLists.UnreadChats = data.unreadChats ?? CND.chats.chatsLists.UnreadChats ?? {};
    CND.chats.chatsLists.ChatsListLoaded = chats;
    CND.chats.chatsLists.MessagesListLoaded = msgs;
    //setTimeout(function() { CND.chats.handleSearchMsgs(); }, 1);
    setTimeout(function() { CND.chats.handleSearchMsgs(function() {
        clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
        clearTimeout(CND.chats.loadChatsListTimeout);
        //CND.chats.loadBackgroundChatsListTimeout = setTimeout(function() { CND.chats.loadBackgroundChatsList(); }, CND.chats.IntervalRefresh);
    }); }, 1);
}; // end function CND.chats.updateChatsList


CND.chats.resetChatsListItemTpl = function() {
    CND.dom('#chat_list_item_tpl').find('.chat-list-item').attr('data-chat-group-id', null);
    CND.dom('#chat_list_item_tpl').find('.chat-list-item').removeClass('chat-selected').removeClass('chat-selected-active');
    CND.dom('#chat_list_item_tpl').find('.chat-list-item-icon').html('');
    CND.dom('#chat_list_item_tpl').find('.chat-list-item-contacts').html('');
    CND.dom('#chat_list_item_tpl').find('.chat-list-item-preview').html('');
    CND.dom('#chat_list_item_tpl').find('.chat-list-item-badge').html('');
    CND.dom('#chat_list_item_tpl').find('.chat-list-item-badge').each(function() { CND.ui.hide(CND.dom(this)); });
}; // end function CND.chats.resetChatsListTpl


CND.chats.getContacts = function(contacts=[]) {
    let icl = 0, o = {
            'count' : 0,
            'text' : '[error]',
            'icon' : CND.dom('<i>').attr('class', 'fad fa-user-friends')
    };
    if (typeof contacts != 'undefined') {
        icl = contacts.length;
        //console.log(CND.date.now(), contacts);
        if (icl > 0) {
            for (ic = 0; ic < icl; ic++) {
                let tcontact = contacts[ic];
                if (ic > 0) { o.text += ', '; } else { o.text = ''; }
                if (tcontact.user_type == 'sms') {
                    o.text += CND.str.phoneNumber(tcontact.user, 'human');
                } else {
                    o.text += tcontact.user;
                } // end if user_type
                ++o.count;
            } // end foreach contacts
        } // end if icl
        if (icl > 1) {
            o.icon = CND.dom('<i>').attr('class', 'fad fa-users');
        } // end if icl
    } // end if contacts
    return o;
}; // end function CND.chats.getContacts


CND.chats.updateChatsListHtml = function(chats={}, callbackFunction=null) {
    if (CND.chats.debug) { console.log(CND.date.now(), 'chats', chats); }
    setTimeout(function() { CND.chats.allowClickChatsList = true; }, 100);
    if (typeof chats == 'undefined') { console.log(CND.date.now(), 'chats empty', chats); return; }
    if (typeof CND.chats.LastActive == 'undefined') { CND.chats.saveChatsLocal(0, CND.chats.LastSearch, CND.chats.chatsLists); }
    let first_id = 0, found_id = false, count = 0, added_new = 0, existing_chats = 0, notifications = 0, chats_last = 0;
    CND.chats.TotalUnreadMsgs = 0;
    if (CND.chats.isLoading('#chats-list-scroll-div')) {
        CND.chats.handleRemoveChatsLoading();
    }
    for (let k in chats) {
        //console.log(CND.date.now(), chats[k]);
        //console.log(CND.date.now(), CND.dom('#chat_list_item_tpl'));
        CND.chats.resetChatsListItemTpl();
        let tchat = chats[k];
        let chat_last = 0; // unix timestamp
        var chat_group_id = 0;
        let contacts_list = '[error]';
        let contacts_icon = CND.dom('<i>').attr('class', 'fad fa-user-friends');
        if (typeof tchat.chat_group_id != 'undefined') {
            chat_group_id = parseInt(tchat.chat_group_id);
            CND.dom('#chat_list_item_tpl').find('.chat-list-item').attr('data-chat-group-id', chat_group_id);
            if (((typeof chat_group_id == 'integer') || (typeof chat_group_id == 'number')) && (chat_group_id > 0)) {
                if (CND.chats.chatGroupIds.includes(chat_group_id) !== true) {
                    CND.chats.chatGroupIds.push(chat_group_id);
                } // end if CND.chats.chatGroupIds
            } else {
                if (CND.chats.debug) { console.log(CND.date.now(), 'chat_group_id', typeof chat_group_id, chat_group_id); }
            } // end if integer
        } else {
            if (CND.chats.debug) { console.log(CND.date.now(), 'tchat', tchat); }
        } // end if chat_group_id
        if (typeof tchat.last != 'undefined') {
            chats_last = chat_last = tchat.last;
        } // end if last
        if (typeof tchat.unread == 'undefined') {
            tchat.unread = 0;
        } // end if unread
        if ((first_id == 0) && (chat_group_id != 0)) { first_id = chat_group_id; }
        if ((chat_group_id != 0) && (((CND.chats.LastActive != 0) && (chat_group_id == CND.chats.LastActive)) || ((CND.chats.LastActive == 0) && (count == 0)))) {
            CND.dom('#chat_list_item_tpl').find('.chat-list-item').addClass('chat-selected').addClass('chat-selected-active');
            if (CND.chats.debug) { console.log(CND.date.now(), 'active', chat_group_id); }
            found_id = true;
            CND.chats.saveChatsLocal(chat_group_id, CND.chats.LastSearch, CND.chats.chatsLists);
        }
        let icl = 0, members_count = 0;
        if (typeof tchat.contacts != 'undefined') {
            let tcontacts = CND.chats.getContacts(tchat.contacts);
            contacts_list = tcontacts.text ?? contacts_list;
            contacts_icon = tcontacts.icon ?? contacts_icon;
            members_count = tcontacts.count ?? members_count;
        } else { tchat.contacts = []; } // end if contacts
        CND.dom('#chat_list_item_tpl').find('.chat-list-item').attr('data-chat-group-members-count', members_count);
        CND.dom('#chat_list_item_tpl').find('.chat-list-item').attr('data-chat-group-last', chat_last);
        CND.dom('#chat_list_item_tpl').find('.chat-list-item').attr('data-chat-group-sort', k);
        CND.dom('#chat_list_item_tpl').find('.chat-list-item-icon').html(contacts_icon);
        CND.dom('#chat_list_item_tpl').find('.chat-list-item-contacts').text(contacts_list);
        if (CND.chats.LastActive == chat_group_id) {
            let active_contacts_icon = contacts_icon.clone();
            CND.dom('#chats-menu-page-info').find('.menu-page-info-icon').html(active_contacts_icon);
            CND.dom('#chats-menu-page-info').find('.menu-page-info-text').text(contacts_list);
            CND.ui.show('#chats-menu-page-info');
        } // end if CND.chats.LastActive
        if (typeof tchat.preview != 'undefined') {
            if (tchat.preview != '') {
                let preview = tchat.preview.toString();
                if (preview.length > 18) {
                    CND.dom('#chat_list_item_tpl').find('.chat-list-item-preview').html(preview.substring(0, 14) + '...');
                } else {
                    CND.dom('#chat_list_item_tpl').find('.chat-list-item-preview').html(preview);
                } // end if preview.length
            } // end if preview
        } else { tchat.preview = ''; } // end if preview

        let chat_in_list = false, chat_in_list_last = 0;
        if (CND.dom('#chats-list-scroll-div').find('.chat-list-item[data-chat-group-id="' + chat_group_id + '"]').length > 0) {
            chat_in_list = true;
            chat_in_list_last = CND.dom('#chats-list-scroll-div').find('.chat-list-item[data-chat-group-id="' + chat_group_id + '"]').attr('data-chat-group-last');
        } // end if chat_in_list
        if (CND.chats.debug) { console.log(CND.date.now(), 'chat_group_id', chat_group_id, 'chat_in_list', chat_in_list, 'chat_in_list_last', chat_in_list_last, 'chat_last', chat_last); }

        if ((chat_group_id == CND.chats.LastActive) && CND.hasFocus()) {
            CND.chats.chatsLists.LastRead[chat_group_id] = chat_last;
            if (typeof CND.chats.chatsLists.UnreadChats[chat_group_id] != 'undefined') {
                delete CND.chats.chatsLists.UnreadChats[chat_group_id];
            } // end if unread
        } else {
            chat_last_read = CND.chats.chatsLists.LastRead[chat_group_id] ?? 0;
            if (chat_last > chat_last_read) {
                if (tchat.unread > 0) {
                    CND.chats.TotalUnreadMsgs += tchat.unread;
                    CND.dom('#chat_list_item_tpl').find('.chat-list-item-badge').html(tchat.unread);
                    CND.dom('#chat_list_item_tpl').find('.chat-list-item-badge').each(function() { CND.ui.show(CND.dom(this)); });
                    old_chat = CND.chats.chatsLists.NotifiedChats[chat_group_id] ?? {};
                    old_last = old_chat.last ?? 0;
                    if ((old_last == 0) || (chat_last > old_last)) {
                        CND.chats.chatsLists.UnreadChats[chat_group_id] = tchat;
                        ++notifications;
                    } else {
                        if (typeof CND.chats.chatsLists.UnreadChats[chat_group_id] != 'undefined') {
                            delete CND.chats.chatsLists.UnreadChats[chat_group_id];
                        } // end if unread
                    } // end if old_last
                } // end if tchat.unread
            } // end if chat_last_read
        } // end if CND.chats.LastActive

        if (chat_in_list && chat_last > chat_in_list_last) {
            CND.dom('#chats-list-scroll-div').find('.chat-list-item[data-chat-group-id="' + chat_group_id + '"]').remove();
            CND.dom('#chats-list-scroll-div').prepend(CND.dom('#chat_list_item_tpl').html());
            ++existing_chats;
        } else if (!chat_in_list) {
            CND.dom('#chats-list-scroll-div').prepend(CND.dom('#chat_list_item_tpl').html());
            ++added_new;
        }
        ++count;
    } // end foreach chats
    if (CND.chats.debug) { console.log(CND.date.now(), 'unread', CND.chats.TotalUnreadMsgs); }
    if (notifications > 0) {
        //console.log(CND.date.now(), 'unread chats', CND.chats.chatsLists.UnreadChats);
        CND.chats.notifications(CND.chats.chatsLists.UnreadChats);
    }
    //console.log(CND.date.now(), 'count', count);
    if (count == 0) {
        CND.dom('#chats-list-scroll-div').html('');
    } else if ((added_new > 0) || (existing_chats > 0)) {
        //CND.ui.sortElements('#chats-list-scroll-div', { 'data-chat-group-starred' : 'desc', 'data-chat-group-last' : 'desc' });
        CND.ui.scrollTo('#chats-list-scroll-div', '.chat-selected', 8, 100, 0, false);
    } // end if count
    if (!found_id && (first_id > 0)) { if (CND.chats.LastActive !== first_id) { CND.chats.saveChatsLocal(first_id, CND.chats.LastSearch, CND.chats.chatsLists); } }
    if (CND.chats.TotalUnreadMsgs > 999) {
        CND.setIconBadge('999+', CND.ui.successBadgeColor);
    } else {
        CND.setIconBadge('' + CND.chats.TotalUnreadMsgs, CND.ui.successBadgeColor);
    }
    CND.chats.resetChatsListItemTpl();
    if (chats_last > CND.chats.chatsLists.ChatsLastLoaded) {
        CND.chats.chatsLists.ChatsLastLoaded = chats_last;
        CND.chats.saveChatsLocal(CND.chats.LastActive, CND.chats.LastSearch, CND.chats.chatsLists);
    } // end if chats_last
    if (typeof callbackFunction == 'function') { setTimeout(function() { callbackFunction(); }, 1); }
    CND.chats.handleOnClickChatsList('#chats-list-scroll-div');
    setTimeout(function() { CND.wss.regUserChatGroups(); }, 1);
}; // end function CND.chats.updateChatsListHtml


CND.chats.updateMessagesListHtml = function(msgs=[], callbackFunction=null) {
    //console.log(CND.date.now(), 'msgs', msgs);
    if (typeof msgs == 'undefined') { console.log(CND.date.now(), 'msgs empty', msgs); return; }
    let last_date = null, last = false, j = 0, any_matched = false, last_id = 0, found_id = false, count = 0, added_new = 0, existing_msgs = 0, chat_group_id = 0, last_sent_by_user_id = 0, msgs_last = 0;
    if (typeof CND.chats.LastActive == 'undefined') { CND.chats.saveChatsLocal(0, CND.chats.LastSearch, CND.chats.chatsLists); }
    if (CND.chats.LastActive != CND.chats.MessagesChatGroupId) {
        CND.chats.chatsLists.MessagesLoaded = {};
    } // end if messages
    CND.chats.MessagesChatGroupId = CND.chats.LastActive;
    if (CND.chats.isLoading('#messages-list-scroll-div')) {
        CND.chats.handleRemoveMsgsLoading();
    }
    try {
        chat_group_id = parseInt(CND.dom('#messages-list-scroll-div').attr('data-chat-group-id'));
        //console.log(CND.date.now(), 'chat groups', chat_group_id, CND.chats.LastActive, CND.chats.MessagesChatGroupId);
        if ((chat_group_id !== null) && (typeof chat_group_id != 'undefined')) {
            if (chat_group_id != CND.chats.LastActive) {
                CND.dom('#messages-list-scroll-div').html('');
            } // end if CND.chats.LastActive
        } // end if chat_group_id
        CND.dom('#messages-list-scroll-div').attr('data-chat-group-id', CND.chats.LastActive);
    } catch (e) { console.log(CND.date.now(), e); }
    let chat_group_members_count = 0;
    let chat_group_list = CND.dom('#chats-list-scroll-div').find('.chat-list-item[data-chat-group-id="' + CND.chats.LastActive + '"]');
    if (typeof chat_group_list != 'undefined') {
        chat_group_members_count = CND.dom(chat_group_list).attr('data-chat-group-members-count');
    } // end if chat_group_list
    if (msgs.length > 0) {
        for (i = 0; i < msgs.length; ++i) {
            chat_group_id = parseInt(CND.dom('#messages-list-scroll-div').attr('data-chat-group-id'));
            //console.log(CND.date.now(), CND.dom('#message_list_chat_tpl'));
            j = i + 1;
            let msg_id = 0;
            let msg = msgs[i];
            //console.log(CND.date.now(), 'msg', msg);
            if (typeof msg.chat_group_id != 'undefined') {
                if (chat_group_id != msg.chat_group_id) {
                    if (CND.chats.debug) { console.log(CND.date.now(), 'msgs chat group doesnt match', chat_group_id ?? null, msg?.chat_group_id ?? null); }
                    clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
                    clearTimeout(CND.chats.loadChatsListTimeout);
                    CND.chats.resetChatsLocal(function() {
                        chat_group_id = CND.dom('#chats-list-scroll-div').find('.chat-selected').attr('data-chat-group-id');
                        CND.chats.LastActive = parseInt(chat_group_id ?? "0");
                        CND.chats.loadChatsList();
                    });
                    //CND.reload();
                    return;
                } // end if chat_group_id
            } // end if chat_group_id
            let msg_last = 0; // unix timestamp
            let matched_result = msg.matched_result ?? false;
            let sent_by = msg.sent_by ?? {};
            let sent_by_type = sent_by.user_type ?? '';
            let sent_by_user = sent_by.user ?? '';
            let sent_by_user_id = sent_by.c2d_user_id ?? msg.sent_by_chat_user_id ?? 0;
            if ((sent_by_type == 'sms') && (sent_by_user_id != last_sent_by_user_id)) {
                sent_by_user = CND.str.phoneNumber(sent_by_user, 'human');
            } // end if sent_by_user
            let c1 = CND.date.convertTZ(msg.created, null, null, true);
            let date = CND.date.getDate(c1);
            let time = CND.date.getTime(c1);
            //console.log(CND.date.now(), 'msg.created', msg.created, ' -> ', 'c1', c1);
            if (matched_result) { any_matched = true; }
            last = false;
            if (j >= msgs.length) {
                last = true;
            } else {
                let next = msgs[j];
                let next_msg_is_only_emojis = CND.chats.isOnlyEmojis(next.message);
                let c2 = CND.date.convertTZ(next.created, null, null, true);
                let next_date = CND.date.getDate(c2);
                let next_sent_by = next.sent_by ?? {};
                let next_sent_by_type = next_sent_by.user_type ?? '';
                let next_sent_by_user = next_sent_by.user ?? '';
                let next_sent_by_user_id = next_sent_by.c2d_user_id ?? next.sent_by_chat_user_id ?? 0;
                if ((next.direction != msg.direction) || (sent_by_user_id != next_sent_by_user_id) || (next_date != date) || next_msg_is_only_emojis) {
                    last = true;
                } // end if next
            } // end if j
            if ((chat_group_members_count > 1) && (sent_by_user_id != last_sent_by_user_id)) {
                CND.dom('#message_list_chat_tpl').find('.message-list-sender').removeClass('none').text(sent_by_user);
            } else {
                if (!CND.dom('#message_list_chat_tpl').find('.message-list-sender').hasClass('none')) {
                    CND.dom('#message_list_chat_tpl').find('.message-list-sender').addClass('none').text('');
                } // end if none
            } // end if sent_by_user_id
            CND.dom('#message_list_chat_tpl').find('.message-list-main').removeClass('message-emoji-only');
            if (typeof msg.message_id != 'undefined') {
                msg_id = parseInt(msg.message_id);
                CND.dom('#message_list_chat_tpl').find('.message-list-item').attr('data-chat-message-id', msg_id);
            }
            if (typeof msg.last != 'undefined') {
                msgs_last = msg_last = parseInt(msg.last);
                CND.dom('#message_list_chat_tpl').find('.message-list-item').attr('data-chat-message-last', msg_id);
            }
            CND.dom('#message_list_chat_tpl').find('.message-list-main').removeClass('message-sent-last').removeClass('message-received-last');
            if (msg.direction == 'sent') {
                CND.dom('#message_list_chat_tpl').find('.message-list-item').removeClass('message-received');
                CND.dom('#message_list_chat_tpl').find('.message-list-item').addClass('message-sent');
                CND.dom('#message_list_chat_tpl').find('.message-list-sender').removeClass('message-received');
                CND.dom('#message_list_chat_tpl').find('.message-list-sender').addClass('message-sent').text('You');
                if (last) {
                    CND.dom('#message_list_chat_tpl').find('.message-list-main').addClass('message-sent-last');
                }
            } else {
                CND.dom('#message_list_chat_tpl').find('.message-list-item').removeClass('message-sent');
                CND.dom('#message_list_chat_tpl').find('.message-list-item').addClass('message-received');
                CND.dom('#message_list_chat_tpl').find('.message-list-sender').removeClass('message-sent');
                CND.dom('#message_list_chat_tpl').find('.message-list-sender').addClass('message-received');
                if (last) {
                    CND.dom('#message_list_chat_tpl').find('.message-list-main').addClass('message-received-last');
                }
            } // end if direction
            //console.log(CND.date.now(), 'last_date', last_date, '=?=', 'date', date);
            if ((last_date === null) || (last_date != date)) {
                CND.dom('#message_list_chat_tpl').find('.message-list-date').attr('data-message-date', date).text(date);
                if (CND.dom('#messages-list-scroll-div').find('.message-list-date[data-message-date="' + date + '"]').length > 0) {
                    CND.ui.hide(CND.dom('#message_list_chat_tpl').find('.message-list-date'));
                } else {
                    CND.ui.show(CND.dom('#message_list_chat_tpl').find('.message-list-date'));
                }
            } else {
                CND.dom('#message_list_chat_tpl').find('.message-list-date').attr('data-message-date', date).text(date);
                CND.ui.hide(CND.dom('#message_list_chat_tpl').find('.message-list-date'));
            }
            last_date = date;
            last_sent_by_user_id = sent_by_user_id;
            let msg_is_only_emojis = CND.chats.isOnlyEmojis(msg.message);
            if (msg_is_only_emojis) {
                //console.log(CND.date.now(), 'msg_is_only_emojis', msg_is_only_emojis);
                CND.dom('#message_list_chat_tpl').find('.message-list-main').removeClass('message-sent-last').removeClass('message-received-last');
                CND.dom('#message_list_chat_tpl').find('.message-list-main').addClass('message-emoji-only');
            }
            CND.dom('#message_list_chat_tpl').find('.message-list-body').html(msg.message).attr('data-matched-result', matched_result);
            //console.log(CND.date.now(), 'message-list-time', time);
            CND.dom('#message_list_chat_tpl').find('.message-list-time').html(time);
            let existing = null, msg_in_list = false, msg_in_list_last = 0;
            if (CND.dom('#messages-list-scroll-div').find('.message-list-item[data-chat-message-id="' + msg_id + '"]').length > 0) {
                msg_in_list = true;
                existing = CND.dom('#messages-list-scroll-div').find('.message-list-item[data-chat-message-id="' + msg_id + '"]');
                msg_in_list_last = CND.dom(existing).attr('data-chat-message-last');
            } // end if msg_in_list
            if (msg_in_list && msg_last > msg_in_list_last) {
                //CND.dom(existing).replaceWith(CND.dom('#message_list_chat_tpl').html());
                ++existing_msgs;
            } else if (!msg_in_list) {
                CND.dom('#messages-list-scroll-div').append(CND.dom('#message_list_chat_tpl').html());
                ++added_new;
            } // end if msg_in_list
            last_id = msg_id;
            ++count;
        } // end foreach list
    } // end if list
    if (count == 0) {
        CND.dom('#messages-list-scroll-div').html('');
    } else if (added_new > 0) {
        setTimeout(function() { CND.ui.scrollTo('#messages-list-scroll-div', 'div[data-matched-result="true"]', 0, 100, 'end', false); }, 10);
    } // end if count
    if (msgs_last > CND.chats.chatsLists.MessagesLastLoaded) {
        CND.chats.chatsLists.MessagesLastLoaded = msgs_last;
        CND.chats.saveChatsLocal(CND.chats.LastActive, CND.chats.LastSearch, CND.chats.chatsLists);
    } // end if msgs_last
    if (typeof callbackFunction == 'function') { setTimeout(function() { callbackFunction(); }, 1); }
}; // end function CND.chats.updateMessagesListHtml


CND.chats.newMessage = function(chat_group_id=0, msgData={}) {
    // For now, just call ajax to refresh all messages... later we can rebuild to load one message at a time in all cases (even page load with the full list of messages)
    clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
    clearTimeout(CND.chats.loadChatsListTimeout);
    CND.chats.loadChatsListTimeout = setTimeout(function() { CND.chats.loadChatsList(); }, 100);
}; // end function CND.chats.newMessage


CND.chats.notificationsClickChat = function(id) {
    clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
    clearTimeout(CND.chats.loadChatsListTimeout);

    let chat = CND.chats.chatsLists.Notifications[id] ?? {};
    var chat_group_id = chat.chat_group_id ?? 0;
    if (chat_group_id > 0) {
        let h = CND.hasFocus();
        CND.chats.saveChatsLocal(chat_group_id, CND.chats.LastSearch, CND.chats.chatsLists, h, function() {
            CND.loadPopupWindow(false, 'chat.html');
        });
    } // end if chat_group_id
}; // end function CND.chats.notificationsClickChat


CND.background = {};
CND.background.loadPopupWindowSettings = function() {
    clearTimeout(CND.chats.loadBackgroundChatsListTimeout);
    clearTimeout(CND.chats.loadChatsListTimeout);

    CND.loadPopupWindow(false, 'settings.html');
}; // emd function CND.background.loadPopupWindowSettings

CND.chats.notificationsSent = 0;
CND.chats.notifications = function(chats=[]) {
    let notificationsSent = 0;
    if (typeof chats != 'undefined') {
        for (let k in chats) {
            // 1612674000 == 2021-02-07 05:00 UTC
            let c = chats[k] ?? {};
            let l = c.last ?? 0;
            if (l == 0) {
                if (CND.chats.debug) { console.log(CND.date.now(), 'chat', c); }
            } else if (l > 1612674000) {
                let t = CND.chats.getContacts(c.contacts ?? []);
                let preview = c.preview ?? '';
                let contacts = t.text ?? '';
                let options = {
                    'title' : contacts,
                    'message' : preview
                };

                //console.log(CND.date.now(), 'new chat', c);
                CND.createNotification(options, function(id) {
                    //console.log(CND.date.now(), 'chat notification shown', c);
                    CND.chats.chatsLists.Notifications[id] = c;
                    chrome.notifications.onClicked.removeListener(CND.background.loadPopupWindowSettings);
                    chrome.notifications.onClicked.addListener(CND.chats.notificationsClickChat);

                });
                CND.chats.chatsLists.NotifiedChats[k] = c;
                ++notificationsSent;
            } // end if last
        } // end for k
    } // end if chats
    CND.chats.notificationsSent += notificationsSent;
}; // end function CND.chats.notifications








// dec2hex :: Integer -> String
// i.e. 0-255 -> '00'-'ff'
const dec2hex = (dec) => {
  return dec.toString(32).padStart(2, "0");
};

// generateId :: Integer -> String
const generateId = (len) => {
  let arr = new Uint8Array((len || 40) / 2);
  self.crypto.getRandomValues(arr);
  return Array.from(arr, dec2hex).join('');
};

const fe_client_uuid = generateId(20);

// WSS Chat Test Javascript
if (typeof CND.wss == 'undefined') { CND.wss = {}; }
CND.wss = {
    contentChan : null,
    contentMembers : {},
    reconnectingTimeout : null,
    reconnectingTimeoutDelay : 250,
    chanIsConnected : false,
    wssIsConnected : false,
    input : null,
    output : null,
    button : null,

    onDocReady : function() {
        if (typeof CND.jQueryLoader != 'undefined') {
            CND.jQueryLoader(function() {
                //console.log(CND.date.now(), 'CND ready');
                if (typeof CND.getAccountInfo !== 'undefined') {
                    //console.log(CND.date.now(), 'Body is VAI CND Enabled');
                    CND.getAccountInfo(function() {

                        CND.wss.initChatDOM();
                        CND.wss.initChatSocket(function(ch) { CND.wss.sendMsg(false, '', 0); });
                        //CND.wss.button.addEventListener("click", function(e){
                            //CND.wss.sendMsg();
                        //});
                        //document.addEventListener("keypress", function(e){
                            //if (e.keyCode == 13) {
                                //CND.wss.sendMsg();
                            //}
                        //});
                    }, function() { console.error(CND.date.now(), 'Failed to load Account Info'); }); // end CND.getAccountInfo
                } else { console.error('Failed to load VAI CND'); } // end if CND.getAccountInfo
            }, function() { console.error('Failed to init CND'); }); // end CND.jQueryLoader
        } else {
            console.error('Missing required dependency: /js/voipawesome.js');
        } // end if CND.jQueryLoader
    }, // end function onDocReady

    initChatDOM : function() {
        if (typeof document != 'undefined') {
            CND.wss.input = document.getElementById("input");
            CND.wss.output = document.getElementById("output");
            CND.wss.button = document.getElementById("send");
        } else {
            if (CND.chats.debug) { console.error(CND.date.now(), 'No document DOM to attach to.'); }
        }
    }, // end function initChatDOM

    initChatSocket : function(successCallback=null, failureCallback=null) {
        // Open a message channel to the background js
        let chan;
        try {
            chan = chrome.runtime.connect({name: "message_relay"});
        } catch(err) {
            console.error(CND.date.now(), 'Failed to connect to chrome message_relay channel', err);
            return false;
        } // end try chan

        if (typeof chan != 'object') { console.error(CND.date.now(), 'BG JS Socket Failed to initialize', chan); return false; }

        chan.onMessage.addListener(CND.wss.onMsg);
        chan.onDisconnect.addListener(CND.wss.onDc);

        // Send the subscribe to the bg js
        let postSuccess = false;
        try {
            chan.postMessage({'action': "subscribe", 'fe_client_uuid': fe_client_uuid});
            postSuccess = true;
        } catch(e) {
            console.error(CND.date.now(), 'Failed to postMessage to the chan', e);
            postSuccess = false;
        }
        if (postSuccess) {
            if (typeof successCallback == 'function') {
                successCallback(chan);
            }
        } else {
            if (typeof failureCallback == 'function') {
                failureCallback(chan);
            }
        }
        return true;
    }, // end function initChatSocket

    recheckWebSocketStatus : function(recheck=true, callback=null) {
        clearTimeout(CND.wss.reconnectingTimeout);
        if (recheck && !CND.wss.wssIsConnected) {
            CND.wss.reconnectingTimeout = setTimeout(function() {
                if (CND.wss.reconnectingTimeoutDelay < 300) { CND.wss.reconnectingTimeoutDelay = 250; }
                if (CND.wss.reconnectingTimeoutDelay < 29000) {
                    CND.wss.reconnectingTimeoutDelay += 1000;
                }
                if (CND.wss.chanIsConnected && !CND.wss.wssIsConnected) {
                    CND.wss.contentChan.postMessage({action: "check_wss_status"});
                    if (typeof callback == 'function') {
                        setTimeout(function() { callback(); }, 1);
                    }
                }
            }, CND.wss.reconnectingTimeoutDelay);
        } // end if recheck
    }, // end function recheckWebSocketStatus

    onDc : function(chan) {
            clearTimeout(CND.wss.reconnectingTimeout);
            CND.wss.chanIsConnected = false;
            CND.wss.setStatusIcon();
            if (typeof CND.wss.contentChan !== null) {
                CND.wss.contentChan = null;
            }
            CND.wss.initChatSocket(function(ch) { CND.wss.sendMsg(false, '', 0); });
            return true;
    },

    onMsg : function(msg, ch) {
            //console.log(CND.date.now(), 'msg', msg, ch);
            if (msg.action === "subscribe") {
                if (msg.status === "ok") {
                    CND.wss.chanIsConnected = true;
                    CND.wss.setStatusIcon();
                    if (CND.wss.contentChan === null || typeof CND.wss.contentChan === 'undefined') {
                        CND.wss.contentChan = ch;
                    }
                    if (!CND.wss.wssIsConnected) {
                        CND.wss.recheckWebSocketStatus(true);
                    }
                }
            } else if (msg.action === "new_msg") {
                //console.log(CND.date.now(), "New msg from C2D server to user", msg, ch);
                let msgText = "";
                let msgData = msg.data || {};
                if (msgData !== null && typeof msgData == 'string') {
                    msgData = JSON.parse(msgData);
                }
                if (typeof msgData.body != 'undefined') {
                    msgText = msgData.body;
                } else if (typeof msgData.message != 'undefined') {
                    msgText = msgData.message;
                }
                let chat_group_id = msgData.chat_group_id ?? 0;
                let sending_user = msgData.user ?? '';
                if ((msgText != "") && (chat_group_id > 0)) {
                    //CND.wss.output?.innerHTML += "[" + CND.date.now() + "] Received: " + msgText + "\n";
                    //if (typeof CND.wss.output != 'undefined') { if (CND.wss.output !== null) { if ('scrollTop' in CND.wss.output) {
                        //CND.wss.output.scrollTop = CND.wss.output?.scrollHeight;
                    //} } }
                    //console.log(CND.date.now(), 'wss server sent us msgData', msgData);
                    CND.chats.newMessage();
                } else {
                    if (CND.chats.debug) { console.log(CND.date.now(), 'wss server sent us msgData', msgData, msgText, chat_group_id); }
                } // end if msgText
            } else if (msg.action === "wss_status") {
                if (msg.status) {
                    /// WSS Backend is Online!
                    //if (!CND.wss.wssIsConnected) {
                        // Should have a WSS connected icon for this: Green (ok) / Grey (d/c)
                        //if (CND.wss.output?.innerHTML.includes('Not Connected')) {
                            //CND.wss.output?.innerHTML = "[" + CND.date.now() + "] Status: Connected\n";
                        //} else {
                            //CND.wss.output?.innerHTML += "[" + CND.date.now() + "] Status: Connected\n";
                        //}
                        //if (typeof CND.wss.output != 'undefined') { if (CND.wss.output !== null) { if ('scrollTop' in CND.wss.output) {
                            //CND.wss.output.scrollTop = CND.wss.output?.scrollHeight;
                        //} } }
                    //}
                    CND.wss.wssIsConnected = true;
                    CND.wss.setStatusIcon();
                    clearTimeout(CND.wss.reconnectingTimeout);
                    CND.wss.reconnectingTimeoutDelay = 250;
                    setTimeout(function() { CND.wss.regUserChatGroups(); }, 1);
                } else {
                    /// WSS Backend is Offline!
                    //if (CND.wss.wssIsConnected) {
                        // Should have a WSS connected icon for this: Green (ok) / Grey (d/c)
                        //CND.wss.output?.innerHTML += "[" + CND.date.now() + "] Status: Disconnected. Reconnecting...\n";
                        //if (typeof CND.wss.output != 'undefined') { if (CND.wss.output !== null) { if ('scrollTop' in CND.wss.output) {
                            //CND.wss.output.scrollTop = CND.wss.output?.scrollHeight;
                        //} } }
                    //}
                    CND.wss.wssIsConnected = false;
                    CND.wss.setStatusIcon();
                    CND.wss.recheckWebSocketStatus(true);
                } // end if msg.status
            } // end if msg.action
            return true;
    }, // end function onMsg

    regUserChatGroups : function() {
        if (typeof CND.chats.chatGroupIds == 'object') {
            if (CND.chats.chatGroupIds.length > 0) {
                //let chat_groups_csv = CND.chats.chatGroupIds.toString();
                let regData = {
                    'action': "reg_user_chat_groups",
                    'chat_groups': CND.chats.chatGroupIds,
                };
                if (CND.wss.wssIsConnected === true) {
                    CND.wss.sendMsg(true, '', 0, true, regData);
                } // end if connected
            } else {
                if (CND.chats.debug) { console.log(CND.date.now(), 'CND.chats.chatGroupIds', CND.chats.chatGroupIds); }
            } // end if length
        } else {
            if (CND.chats.debug) { console.log(CND.date.now(), 'CND.chats.chatGroupIds', CND.chats.chatGroupIds); }
        } // end if array
    }, // end function regUserChatGroups

    sendMsg : function(retryOnChanOffline=true, msgText='', chat_group_id=0, inputIsMsgData=false, msgData={}) {
        if (CND.wss.chanIsConnected && CND.wss.wssIsConnected) {
            let domain = CND.accountSettings.domain ?? CND.defaultSettings.domain ?? '';
            let extension = CND.accountSettings.extension ?? CND.defaultSettings.extension ?? '';
            let apikey = CND.accountSettings.apikey ?? '';
            if (apikey != '') {
                if (inputIsMsgData !== true) {
                    msgText = msgText.toString().trim();
                    if (msgText != '') {
                        return CND.chats.sendMsg(chat_group_id, msgText, []);
                    }
                    return false;
                } // end if inputIsMsgData

                try {
                    CND.wss.contentChan.postMessage({action: "send_msg", data: msgData}); // {action: "new_msg", body: msgText, domain: domain, group: chat_group_id, key: apikey}});
                    CND.chats.sendMsgSuccess();
                    return true;
                } catch(e) {
                    console.error(CND.date.now(), 'ERROR: We couldnt post the message to the content channel', e);
                } // end try postMessage

                //if (typeof CND.wss.input != 'undefined') { if ('value' in CND.wss.input) {
                    //CND.wss.input.value = "";
                //} }
                //if (msgText != "") {
                    //console.log(CND.date.now(), "Sending message", msgText);
                    // Need to get a message status icon for this: queued, sending, sent, error
                    //CND.wss.output?.innerHTML += "[" + CND.date.now() + "] Sent: " + msgText + "\n";
                    //if (typeof CND.wss.output != 'undefined') { if (CND.wss.output !== null) { if ('scrollTop' in CND.wss.output) {
                        //CND.wss.output.scrollTop = CND.wss.output?.scrollHeight;
                    //} } }
                //}
            } else {
                return false;
            } // end if apikey
        } else if (!CND.wss.chanIsConnected) {
            if (CND.chats.debug) { console.log(CND.date.now(), "BG JS Channel is offline! Can't send message", msgText); }
        } else if (!CND.wss.wssIsConnected) {
            if (CND.chats.debug) { console.log(CND.date.now(), "WSS Backend is offline! Can't send message", msgText); }
        } // end if isConnected
        if (retryOnChanOffline) {
            if (!CND.wss.chanIsConnected) {
                CND.wss.initChatSocket(function(ch) { CND.wss.sendMsg(false, msgText, chat_group_id); });
            } else if (!CND.wss.wssIsConnected) {
                CND.wss.reconnectingTimeoutDelay = 1;
                CND.wss.recheckWebSocketStatus(true, function() { CND.wss.sendMsg(false, msgText, chat_group_id); });
            } // end if connected
        } // end if retryOnChanOffline
        return false;
    }, // end function sendMsg

    setStatusIcon : function () {
        if (CND.wss.chanIsConnected) {
            if (CND.wss.wssIsConnected) {
                CND.dom('#chats-online-status-icon').removeClass('fal').removeClass('text-danger').removeClass('fad').removeClass('text-warning').addClass('fas').addClass('text-success');
            } else {
                CND.dom('#chats-online-status-icon').removeClass('fal').removeClass('text-danger').removeClass('fas').removeClass('text-success').addClass('fad').addClass('text-warning');
            }
        } else {
            CND.dom('#chats-online-status-icon').removeClass('fas').removeClass('text-success').removeClass('fad').removeClass('text-warning').addClass('fal').addClass('text-danger');
        }
    } // end function setStatusIcon
}; // end object CND.wss


// Document Ready
if (typeof document != 'undefined') {
    if (typeof document.addEventListener != 'undefined') {
        // Use the handy event callback
        document.addEventListener("DOMContentLoaded", function(){
            setTimeout(CND.wss.onDocReady, 1);
            CND.handleIsLoaded('getAccountInfo', function() {
                CND.chats.handleOnReady();
            });
        }, false);

        window.addEventListener('offline', function(e) {
            if (CND.chats.debug) { console.log(CND.date.now(), 'offline now'); }
            if (CND.online) {
                CND.chats.handleShowOffline();
            } // end if CND.online
            CND.online = false;
        }); // end offline

        window.addEventListener('online', function(e) {
            if (CND.chats.debug) { console.log(CND.date.now(), 'online now'); }
            if (!CND.online) { setTimeout(function() { CND.chats.handleShowMainLoading(); CND.chats.loadChatsList(); }, 1); }
            CND.online = true;
        }); // end online

    } // end if document.addEventListener
} // end if document


