(function() {
	var ns = MOA.ns('SafeFlag.Utils');
	var Ci = Components.interfaces;
	var Cc = Components.classes;
	
	ns.getTabIDForHttpChannel = function (oHttpChannel) {
		if (!gBrowser)
			return null;
		
		try {
			if (oHttpChannel.notificationCallbacks) {
				var interfaceRequestor = oHttpChannel.notificationCallbacks.QueryInterface(Ci.nsIInterfaceRequestor);
				var targetDoc = interfaceRequestor.getInterface(Ci.nsIDOMWindow).document;
		
				var tab = null;
				var targetBrowserIndex = gBrowser.getBrowserIndexForDocument(targetDoc);
				
				// handle the case where there was no tab associated with the request (rss etc.)
				if (targetBrowserIndex != -1) {
					tab = gBrowser.tabContainer.childNodes[targetBrowserIndex];
				} else {
					return null;
				}
				
				return tab.linkedPanel;
			}
		} catch (ex) {
			return null;
		}
		
		return null;
	};
		
	ns.getRequestWebProgress = function(request) {
		try {
			if (request && request.notificationCallbacks)
				return request.notificationCallbacks.getInterface(Ci.nsIWebProgress);
		} catch (err ) {
			// MOAC.log(err);
		}
			
		try {
			if (request && request.loadGroup && request.loadGroup.groupObserver)
				return request.loadGroup.groupObserver.QueryInterface(Ci.nsIWebProgress);
		} catch (err) {
			// MOAC.log(err);
		}
	};
		
	ns.getWindowForRequest = function(request) {
		return this.getWindowForWebProgress(this.getRequestWebProgress(request));
	};
		
	ns.getWindowForWebProgress = function(webProgress) {
		try {
			if (webProgress)
				return webProgress.DOMWindow;
		} catch (err) {
			// MOAC.log(err);
		}
		
		return null;
	};
		
	ns.getRootWindow = function(win) {
		for (; win; win = win.parent) {
			if (!win.parent || win == win.parent || !(win.parent instanceof Window))
				return win;
		}
		
		return null;
	};
		
	ns.getTabForWindow = function(win) {
		aWindow = this.getRootWindow(win);
		
		if (!aWindow || !gBrowser.getBrowserIndexForDocument)
			return null;
			
		try {
			var targetDoc = aWindow.document;
			
			var tab = null;
			var targetBrowserIndex = gBrowser.getBrowserIndexForDocument(targetDoc);
			
			if (targetBrowserIndex != -1) {
				tab = gBrowser.tabContainer.childNodes[targetBrowserIndex];
				return tab;
			}
		} catch (err) {
			MOAC.log(err);
		}
		
		return null;
	};
		
	ns.getTabIdForWindow = function(win) {
		var tab = this.getTabForWindow(win);
		return tab ? tab.linkedPanel : null;
	};
		
	ns.getCurrentWindow = function() {
		return Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator).getMostRecentWindow("navigator:browser");
	};
	
	ns.getCurrentURI = function() {
		return this.getCurrentWindow().getBrowser().currentURI;
	};
	
	ns.get = function(id) {
		return document.getElementById(id);
	};
	
	// extend object
	ns.extend = function(src, target) {
		for (var key in src) {
			target[key] = src[key];
		}
		return target;
	};
	
	ns.bindFunc = function(func, context) {
		var __method = func, args = Array.prototype.slice.call(arguments, 2);
		return function() {
			return __method.apply(context, args.concat(Array.prototype.slice.call(arguments)));
		}
	};
	
	ns.getPrefs = function() {
		var oldBranch = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefService).getBranch('safeflag.');
		var newBranch = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefService).getBranch('extensions.safeflag.');
		if (oldBranch.getChildList('', {}).length) {
			['background.safe', 'background.unsafe'].forEach(function(key) {
				if (oldBranch.prefHasUserValue(key)) {
					newBranch.setBoolPref(key, oldBranch.getBoolPref(key))
				}
			});
			oldBranch.deleteBranch('')
		}
		return newBranch;
	};
	
	// Returns a string version of an exception object with its stack trace
	function parseException(e) {
		if (!e)
			return "";
		else if (!e.stack)
			return String(e);
		else
			return String(e) + " \n" + String(e.stack);
	}
	
	ns.error = function(msg, exception) {
		Components.utils.reportError(msg + ' \n' + parseException(exception));
	};
	
	ns.PrefListener = function(branchName, onChanged) {
		var branch = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefBranch).getBranch(branchName);
		branch.QueryInterface(Ci.nsIPrefBranch2);
		branch.addObserver('', this, false);
		
		this.unregister = function() {
			if (branch) {
				branch.removeObserver('', this);
			}
			branch = null;
		};
		
		this.observe = function(subject, topic, data) {
			MOA.debug('subject: ' + subject);
			if (topic == 'nsPref:changed') {
				onChanged(branch, data);
			}
		};
	};

	ns.getString = function(stringID) {
		var stringBundle = document.getElementById("safeflag-strings");
		return stringBundle.getString(stringID)
	};
})();
