/* 
 Copyright 2007-2010 Xmarks Inc.

 foxmarks-statusbar.js: implement the Xmarks status bar
 */

/*
 To Do:
  * Decide on statusbar features.
  * Decide on tooltip, including disabled state.
  * Do another color for user's own rating?
  * Respect global xmarks settings and privacy settings.
*/

(function() {
if (typeof(Cc) == "undefined") var Cc = Components.classes;
if (typeof(Ci) == "undefined") var Ci = Components.interfaces;
if (typeof(Cu) == "undefined") var Cu = Components.utils;

Cu.import("resource://xmarks/reviews.jsm", Xmarks)

Xmarks.SBS = {};

var currentURL;
var fetching = false;

var urlBarListener = {
    QueryInterface: function(aIID) {
        if (aIID.equals(Ci.interfaces.nsIWebProgressListener) ||
            aIID.equals(Ci.nsISupportsWeakReference) ||
            aIID.equals(Ci.nsISupports))
        return this;
        throw Components.results.NS_NOINTERFACE;
    },

    onLocationChange: function(aProgress, aRequest, aURI) {
        fetching = false;
        if (!aURI || aURI.spec.indexOf('http') != 0) {
            currentURL = null;
            return Xmarks.SBS.ShowOrHide();
        } else {
            currentURL = aURI.spec;
            Xmarks.SBS.UpdateState();
            Xmarks.SBS.ShowOrHide();
        }
    },

    onStateChange: function(a, b, c, d) {},
    onProgressChange: function(a, b, c, d, e, f) {},
    onStatusChange: function(a, b, c, d) {},
    onSecurityChange: function(a, b, c) {}
};



Xmarks.SBS.UpdateState = function() {
    var review = Xmarks.Review.Get(currentURL);
    var s;
    if (review === undefined) {
        s = "unknown";
    } else if (!review) {
        s = "unreviewable";
    } else if (review.locked) {
        s = "locked";
    } else if (!review.full) {
        s = "partial";
    } else if (!review.numratings) {
        s = "notyetreviewed";
    } else if (!review.rating) {
        s = "hasreviews";
    } else {
        s = "userreviewed";
    }
    Xmarks.SBS.SetState(s);
}

Xmarks.SBS.SetState = function(newState) {
    var stars = document.getElementById("xmarks-sbs-stars");
    var review = Xmarks.Review.Get(currentURL);

    switch (newState) {
        case "unknown":
            stars.usermode = false;
            stars.stars = 0;
            stars.disabled = true;
            stars.clickable = false;
            break;
        case "notreviewable":
        case "locked":
            stars.usermode = false;
            stars.stars = 0;
            stars.disabled = true;
            stars.clickable = false;
            break;
        case "partial":
            stars.usermode = false;
            stars.rating = review.average;
            stars.disabled = true;
            stars.clickable = false;
            break;
        case "notyetreviewed":
            stars.usermode = true;
            stars.rating = 0;
            stars.disabled = false;
            stars.clickable = true;
            break;
        case "hasreviews":
            stars.usermode = false;
            stars.rating = review.average;
            stars.disabled = false;
            stars.clickable = true;
            break;
        case "userreviewed":
            stars.usermode = true;
            stars.rating = review.rating;
            stars.disabled = true;
            stars.clickable = true;
            break;
    }
    state = newState;
    SetHover();
}


var waitingFor = null;
Xmarks.SBS.Click = function(event) {
    const openable = ['notyetreviewed', 'hasreviews', 'userreviewed'];
    if (event.button < 2) {
        var panel = document.getElementById("xmarks-review-panel");
        var sbs = document.getElementById("xmarks-sbs");

        if (state == 'unknown') {
            waitingFor = currentURL;
            return;
        } else {
            waitingFor = null;
        }

        if (openable.indexOf(state) >= 0) {
            panel.openPopup(sbs, "before_end", 0, 0, false, true);
        }
    }
}

Xmarks.SBS.ShowOrHide = function() {
    var sbs = document.getElementById('xmarks-sbs');
    sbs.hidden = !currentURL || Xmarks.gSettings.useOwnServer ||
                !Xmarks.gSettings.haveSynced ||
                Xmarks.gSettings.privateBrowsing || Xmarks.gSettings.hideSBS;
}

function SetHover() {
    // Display the hover if the user is hovering, we have data, and
    // the popup isn't showing.
    var show = hovering && !reviewPopupShowing;
    var hover = document.getElementById("xmarks-sbs-hover");

    if (!show) {
        hover.hidePopup();
        return;
    }

    var label = document.getElementById("xmarks-sbs-hover-label");
    var review = Xmarks.Review.Get(currentURL);
    var str = "";
    try {
        str = Xmarks.Bundle().GetStringFromName("reviews.tooltip." + state);
    } catch (e) {}

    label.value = str;

    var sbs = document.getElementById("xmarks-sbs");
    hover.openPopup(sbs, "before_end", 0, -5, false, true);
}

var hovering = false;
Xmarks.SBS.MouseOver = function(event) {
    hovering = true;
    SetHover();

    if (state == 'unknown' || state == 'partial') {
        if (!fetching) {
            FetchReview(currentURL);
        }
    }
}

Xmarks.SBS.MouseOut = function(event) {
    hovering = false;
    SetHover();
}


var reviewPopupShowing = false;

Xmarks.ReviewPopupShowing = function() {
    var review = Xmarks.Review.Get(currentURL);
    var rating = document.getElementById("xmarks-sbs-stars").rating;
    var widget = document.getElementById("xmarks-popup-review");
    if (state == 'notyetreviewed' || 
            (state == 'userreviewed' && review.numratings == 1)) {
        widget.alt_row.hidden = true;
    } else {
        widget.alt_status.url = review.url;
        widget.alt_status.numratings = review.numratings || 1;
        widget.alt_stars.usermode = false;
        widget.alt_stars.stars = review.average;
        widget.alt_row.hidden = false;
    }
    widget.stars.usermode = true;
    widget.rating = rating;
    widget.body = review.body;
    widget.url = review.url;
    widget.url_id = review.url_id;
    widget.title = document.title;
    widget.description = Xmarks.Review.GetDescriptionFromDocument(document);
    widget.numratings = 1;
    widget.fb_session = Xmarks.FB.has_session;
    widget.post_to_fb.checked = Xmarks.FB.has_session && 
        Xmarks.gSettings.postToFB && !review.rating;
    widget.alt_row.collapsed = false;
    reviewPopupShowing = true;
    review.originalrating = review.rating;
    review.rating = rating;
    Xmarks.SBS.SetState("userreviewed");
    SetHover();
    return true;
}

Xmarks.ReviewPopupDone = function(ok) {
    var panel = document.getElementById("xmarks-review-panel");
    if (ok) {
        panel.setAttribute("accepted", true);
    } else {
        panel.removeAttribute("accepted");
    }
    panel.hidePopup();
}

Xmarks.ReviewPopupHiding = function() {
    var panel = document.getElementById("xmarks-review-panel");
    var popup = document.getElementById("xmarks-popup-review");
    var review = Xmarks.Review.Get(popup.url);

    reviewPopupShowing = false;
    SetHover();

    // Restore to previous state. When the server
    // confirms the update, we'll get back the new values.
    review.rating = review.originalrating;
    delete review.originalrating;

    if (!panel.hasAttribute("accepted")) {
        // Restore to previous state.
        Xmarks.SBS.UpdateState();
        return;
    }

    panel.removeAttribute("accepted");
    Xmarks.Review.Update(window, popup);
}

Xmarks.SBS.Disable = function() { 
    var stars = document.getElementById("xmarks-sbs-stars");
    stars.disabled = true;
}

Xmarks.SBS.OnMenuShowing = function() {
    Xmarks.SetChecked("xmarks-status-showicon", 
        !Xmarks.gSettings.hideStatusIcon);
    Xmarks.SetChecked("xmarks-status-showstars", 
        !Xmarks.gSettings.hideSBS);
}
function FetchReview(url) {
    fetching = true;
    Xmarks.FetchTurboTags(url, null, null, function(response) {
        fetching = false;
        if (!response.status) {
            Xmarks.Review.AddFromResponse(response);
        } else {
            Xmarks.Review.Add(url, null);
        }
    });
}

function ReviewAdded(subj, topic, url) {
    if (url == currentURL) {
        Xmarks.SBS.UpdateState();
    }
    if (url == waitingFor) {
        Xmarks.SBS.Click( { button: 0 });
    }
}

function SettingsChanged(subj, topic, url) {
    Xmarks.SBS.ShowOrHide();
}

var STATE_MAP = {
    ready: { src: "chrome://foxmarks/skin/images/ready.png", 
        tooltip: "icon.tooltip.ready" },
    dirty: { src: "chrome://foxmarks/skin/images/dirty.png",
        tooltip: "icon.tooltip.dirty" },
    working: { src: "chrome://foxmarks/skin/images/wheel_16.gif",
        tooltip: "icon.tooltip.working2" },
    error: { src: "chrome://foxmarks/skin/images/error.png",
        tooltip: "icon.tooltip.error" }
};


function FoxmarksQuietSync() {
    var foxmarks = Cc["@foxcloud.com/extensions/foxmarks;1"]
        .getService(Ci.nsIFoxmarksService);

    foxmarks.synchronize();
}

var stateObserver = {
    observe: function(subject, topic, data) {
        UpdateStateIndicator(data);
    }
}

function UpdateStateIndicator(state) {
    if (state == "hide" || state == "show") {
        UpdateHiddenState();
    } else {
        var panel = document.getElementById("foxmarks-statusimage");
        panel.src = STATE_MAP[state].src;
        panel.tooltipText = Cc["@mozilla.org/intl/stringbundle;1"].
            getService(Ci.nsIStringBundleService).
            createBundle("chrome://foxmarks/locale/foxmarks.properties").
            GetStringFromName(STATE_MAP[state].tooltip);
    }
}


function UpdateHiddenState(state) {
    if (state == null) {
        state = Xmarks.gSettings.hideStatusIcon;
    } else {
        Xmarks.gSettings.hideStatusIcon = state;
    }
    document.getElementById("foxmarks-statusimage").hidden = state;
}

function StatusBarLoad() {
    var os = Cc["@mozilla.org/observer-service;1"].
        getService(Ci.nsIObserverService);
    os.addObserver(stateObserver, "foxmarks-statechange", false);
    os.addObserver( { observe: ReviewAdded }, "xmarks-reviewadded", false);
    os.addObserver( { observe: SettingsChanged }, "foxmarks-settingschange", 
        false);
    os.addObserver( { observe: SettingsChanged }, "private-browsing", false);

    var foxmarks = Cc["@foxcloud.com/extensions/foxmarks;1"]
        .getService(Ci.nsIFoxmarksService);
    var state = foxmarks.getState();
    UpdateStateIndicator(state);
    UpdateHiddenState();
    SettingsChanged();

    // Listen for webpage loads
    gBrowser.addProgressListener(urlBarListener,
        Ci.nsIWebProgress.NOTIFY_LOCATION);

    return;
}

function StatusBarUnload() {
    var os = Cc["@mozilla.org/observer-service;1"].
        getService(Ci.nsIObserverService);

    try {
        os.removeObserver(stateObserver, "foxmarks-statechange");
    } catch (e) {
        Xmarks.LogWrite("Warning: removeObserver failed.");
    }
    try {
        gBrowser.removeProgressListener(urlBarListener);
    } catch (e) {
        Xmarks.LogWrite("Warning: removeProgressListener failed.");
    }
}

window.addEventListener("load", StatusBarLoad, false);
window.addEventListener("unload", StatusBarUnload, false);
})();
