/* You may find the license in the LICENSE file */

const EXPORTED_SYMBOLS = [
	'browsingPrivately',
	'registerCallbacks',
	'unregisterCallbacks'
];

const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const Cu = Components.utils;
const Ctor = Components.Constructor;
const module = Cu.import;
const Exception = Components.Exception;

module("resource://gre/modules/XPCOMUtils.jsm");

/**
 * Returns whether in PBM or not
 */
function browsingPrivately() false;

/**
 * Register a callback
 * @param obj Callback object.
 * 		The callback object can implement enter-/exitPrivateBrowsing.
 *    These functions have no parameters. No return value is expected.
 *    If Private Browsing Mode is currently active enterPrivateBrowsingMode will be called immediately
 *    
 *    Furthermore canEnterPrivateBrowsing/canLeavePrivateBrowsing functions may be implemented.
 *    These have no parameters, but a boolean return value is expected stating whether a mode switch might be performed.
 *    
 *    All callbacks will be called in the scope of obj.
 */
function registerCallbacks() {};

/**
 * Unregister a callback again
 */
function unregisterCallbacks() {};

if (("@mozilla.org/privatebrowsing-wrapper;1" in Cc) && ("nsIPrivateBrowsingService" in Ci)) {
	const pbm = Cc["@mozilla.org/privatebrowsing-wrapper;1"].getService(Ci.nsIPrivateBrowsingService);
	const os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);

	delete browsingPrivately;
	delete registerCallbacks;
	delete unregisterCallbacks;

	let _callbacks = [];
	
	function Observer() {
		os.addObserver(this, "private-browsing", false);
		os.addObserver(this, "private-browsing-cancel-vote", false);
		os.addObserver(this, "quit-application", false);
	}
	Observer.prototype = {
		QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),			
		observe: function(aSubject, aTopic, aData) {
			switch (aTopic) {
			case 'private-browsing-cancel-vote':
				if (aData == 'enter') {
					this.doVote('canEnterPrivateBrowsing', aSubject);
				}
				else if (aData == 'exit') {
					this.doVote('canExitPrivateBrowsing', aSubject);
				}
				break;
			case 'private-browsing':
				this.notify(aData + "PrivateBrowsing");
				break;
			case 'quit-application':
				this.teardown();
			}
		},
		doVote: function(prop, cancel) {
			cancel.QueryInterface(Ci.nsISupportsPRBool);
			if (cancel.data) {
				// already canceled
				return;
			}
			cancel.data = !_callbacks.every(function(c) {
				if (prop in c) {
					return c[prop].call(c);
				}
				return true;				
			});
		},
		notify: function(prop) {
			_callbacks.forEach(function(c) !(prop in c) || c[prop].call(c));
		},
		teardown: function() {
			ps.removeObserver(this, "private-browsing");
			os.removeObserver(this, "private-browsing-cancel-vote");
			os.removeObserver(this, "quit-application");
			_callbacks = [];
			delete os;
		}
	};
	const observer = new Observer();
	
	function browsingPrivately() pbm.privateBrowsingEnabled;
	function registerCallbacks(obj) {
		_callbacks.push(obj);
		if (browsingPrivately() && 'enterPrivateBrowsing' in obj) {
			obj['enterPrivateBrowsing'].call(obj);
		}
	}
	function unregisterCallbacks(obj) {
		_callbacks = _callbacks.filter(function(e) e != obj); 
	}	
}