var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;

// Make sure that we've got JSON additions to fundamental objects
var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
    getService(Ci.mozIJSSubScriptLoader);
loader.loadSubScript("chrome://foxmarks/content/foxmarks-json.js", null);
loader.loadSubScript("chrome://foxmarks/content/foxmarks-utils.js", null);

var Xmarks = {};

Cu.import("resource://xmarks/network.jsm", Xmarks); // import Request
Cu.import("resource://xmarks/settings.jsm", Xmarks); // import gSettings et al

var EXPORTED_SYMBOLS = ["Read", "Write", "Changed", "IsDirty"]

var clean = false;
var IDLE_SECONDS = 15 * 60;

function Changed() {
    // Called when something we're interested in (windows and tabs)
    // has changed.
    clean = false;
}

function IsDirty() !clean;

var observer = {
    observe: function(s, t, d) { 
        if (t == 'idle' && Xmarks.gSettings.tabSyncOnIdle) {
            this.sync(t);
        } else if (t == "sleep_notification" && Xmarks.gSettings.tabSyncOnSleep) {
            this.sync(t);
        }
    },

    sync: function(t) {
        if (!Xmarks.gSettings.isSyncEnabled('tabs') || !IsDirty()) {
            return;
        }
        Xmarks.Notify(
            { 
                status: 1, msg: 
                Xmarks.Bundle().GetStringFromName('dialog.status.working') 
            });
        Write(function(status) {
            if (!status) {
                Xmarks.Notify(
                    { 
                        status: 0, 
                        msg: Xmarks.Bundle().
                            GetStringFromName('msg.synccompleted') 
                    });
            } else {
                Xmarks.Notify(
                    { 
                        status: status,
                        msg: Xmarks.MapErrorMessage(status)
                    });
            }
        }, false);
    }
};

if (Xmarks.gSettings.tabSyncOnIdle) {
    var is = Cc["@mozilla.org/widget/idleservice;1"].
        getService(Ci.nsIIdleService);
    is.addIdleObserver(observer, IDLE_SECONDS);
}

if (Xmarks.gSettings.tabSyncOnSleep) {
    var os = Cc["@mozilla.org/observer-service;1"].
        getService(Ci.nsIObserverService);
    os.addObserver(observer, "sleep_notification", false);
}

function FetchOpenWindows() {
    var wins = [];

    var mediator = Cc['@mozilla.org/appshell/window-mediator;1'].
        getService(Ci.nsIWindowMediator);

    var windows = mediator.getEnumerator("navigator:browser");

    while (windows.hasMoreElements()) {
        var tabs = [];
        wins.push( { tabs: tabs });        
        var win = windows.getNext();
        var tabbrowser = win.gBrowser;
        var tablen = tabbrowser.browsers.length;
        for (var i = 0; i < tablen; i++) {
            var browser = tabbrowser.getBrowserAtIndex(i);
            var url = browser.currentURI.spec;
            if (url.indexOf("http") != 0)
                continue;
            tabs.push( { 
                    url: url, 
                    title: browser.contentTitle, 
                    icon: browser.mIconURL,
                    scrollX: browser.contentWindow.scrollX,
                    scrollY: browser.contentWindow.scrollY } );
        }
        if (!tabs.length) {
            wins.pop();
        }
    }
    return wins;
}

var isSyncing = false;
function Write(callback, manual) {
    if (clean || Xmarks.gSettings.privateBrowsing || isSyncing) {
        if (callback) callback(0);
        return;
    }

    isSyncing = true;

    // Gather current window/tab state and write it to the server.
    var req = new Xmarks.Request("POST", 
        { 
            host: Xmarks.gSettings.cloudHost, 
            path: "/cloud/tabs/write" 
        },
        { 
            mymid: Xmarks.gSettings.machineId, 
            data: {
                clientName: Xmarks.gSettings.clientName, 
                browserName: "firefox",
                windows: FetchOpenWindows() 
            }
        },
        {
            noauthdialog: !manual
        } );
    req.Start(function(resp) {
        isSyncing = false;
        if (!resp.status) {
            clean = true;
        }
        if (callback) {
            callback(resp.status);
        }
    });
}

function Read(callback) {
    var req = new Xmarks.Request("POST", 
        { 
            host: Xmarks.gSettings.cloudHost, 
            path: "/cloud/tabs/read" 
        },
        { mymid: Xmarks.gSettings.machineId }  );
    req.Start(function(resp) {
        if (resp.status || !resp.mids) {
            callback(resp.status || 500);
            return;
        }
        var clients = {};
        var mids = resp.mids;
        forEach(mids, function(v, mid) {
            if (mid == Xmarks.gSettings.machineId) {
                return;   // Skip ourselves.
            }
            var clientName = v.clientName || "Unknown";
            if (!(clientName in clients)) {
                clients[clientName] = { mids: {}};
            }
            clients[clientName].mids[mid] = v;
        });

        // Attach the total number of tabs to each client
        forEach(clients, function(client, clientName) {
                client.length = 0;
                forEach(client.mids, function(mid) {
                        mid.length = 0;
                        forEach(mid.windows, function(win) {
                                client.length += win.tabs.length;
                                mid.length += win.tabs.length;
                            });
                    });
            });

        callback(0, clients);
        return;
    });
}

function Delete() {
    var req = new Xmarks.Request("POST", 
        { 
            host: Xmarks.gSettings.cloudHost, 
            path: "/cloud/tabs/delete" 
        },
        { mymid: Xmarks.gSettings.machineId }  );
    req.Start(function(resp) {
        Xmarks.LogWrite("Tab data deleted with status " + resp.status);
    });
}
