/*
    Copyright (C) 2017 Kai Uwe Broulik <kde@privat.broulik.de>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation; either version 3 of
    the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

// URL - data URL
let favIconDataForUrl = {};
let clearFavIconDataTimeoutId = 0;
let runningGetTabsQueries = 0;

addCallback("tabsrunner", "activate", function (message) {
    var tabId = message.tabId;

    console.log("Tabs Runner requested to activate tab with id", tabId);

    raiseTab(tabId);
});

addCallback("tabsrunner", "setMuted", function (message) {

    var tabId = message.tabId;
    var muted = message.muted;

    chrome.tabs.update(tabId, {muted: muted}, function (tab) {

        if (chrome.runtime.lastError || !tab) { // this "lastError" stuff feels so archaic
            // failed to mute/unmute
            return;
        }
    });

});

// only forward certain tab properties back to our host
var whitelistedTabProperties = [
    "id", "active", "audible", "favIconUrl", "incognito", "title", "url", "mutedInfo"
];

// FIXME We really should enforce some kind of security policy, so only e.g. plasmashell and krunner
// may access your tabs
addCallback("tabsrunner", "getTabs", function (message) {
    ++runningGetTabsQueries;

    chrome.tabs.query({}, function (tabs) {
        if (clearFavIconDataTimeoutId) {
            clearTimeout(clearFavIconDataTimeoutId);
            clearFavIconDataTimeoutId = 0;
        }

        // remove incognito tabs and properties not in whitelist
        let filteredTabs = tabs;

        // Firefox before 67 runs extensions in incognito by default
        // but we keep running after an update, so exclude those tabs for it
        if (IS_FIREFOX) {
            filteredTabs = filteredTabs.filter(function (tab) {
                return !tab.incognito;
            });
        }

        filteredTabs = filterArrayObjects(filteredTabs, whitelistedTabProperties);

        let favIconUrlsToFetch = new Set();

        // Collect a set of fav icons to be requested
        filteredTabs.forEach((tab) => {
            const url = tab.favIconUrl;
            if (!url) {
                return;
            }

            // Already a data URL
            if (url.match(/^data:image/)) {
                return;
            }

            // Already in cache
            if (favIconDataForUrl[url]) {
                return;
            }

            favIconUrlsToFetch.add(url);
        });

        // Prepare the download requests for all fav icons
        let requests = [];
        favIconUrlsToFetch.forEach((url) => {
            requests.push(new Promise((resolve) => {
                // Send a request to fill the cache (=no timeout)
                let xhrForCache = new XMLHttpRequest();
                xhrForCache.open("GET", url);
                xhrForCache.send();

                // Try to fetch from (hopefully) the cache (100ms timeout)
                let xhr = new XMLHttpRequest();
                xhr.onreadystatechange = function() {
                    if (xhr.readyState !== XMLHttpRequest.DONE) {
                        return;
                    }

                    if (!xhr.response) {
                        return resolve();
                    }

                    var reader = new FileReader();
                    reader.onloadend = function() {
                        favIconDataForUrl[url] = reader.result;
                        return resolve();
                    }
                    reader.readAsDataURL(xhr.response);
                };
                xhr.open('GET', url);
                xhr.responseType = 'blob';
                xhr.timeout = 100;
                xhr.send();
            }));
        });

        // Download all favicons and send them out
        Promise.all(requests).then(() => {
            filteredTabs = filteredTabs.map((tab) => {
                const favIconUrl = tab.favIconUrl;
                if (!favIconUrl) {
                    return tab;
                }

                if (favIconUrl.match(/^data:image/)) {
                    tab.favIconData = favIconUrl;
                    return tab
                }

                const data = favIconDataForUrl[favIconUrl];
                if (data) {
                    tab.favIconData = data;
                }
                return tab;
            });

            --runningGetTabsQueries;
            if (runningGetTabsQueries === 0) {
                clearFavIconDataTimeoutId = setTimeout(() => {
                    favIconDataForUrl = {};
                    clearFavIconDataTimeoutId = 0;
                }, 60000);
            }

            port.postMessage({
                subsystem: "tabsrunner",
                event: "gotTabs",
                tabs: filteredTabs
            });
        });
    });
});
