Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/AddonManager.jsm");  
const Cc = Components.classes;
const Ci = Components.interfaces;
const gObserver = Cc['@mozilla.org/observer-service;1'].getService(Ci.nsIObserverService);
var self, avgReg, avgPrefs;
DumpLog("AVG XPCOM IS HERE");

var placeholders = {
	PARTNERIDENTIFIER: "avg",
	BASESEARCHURL: "http://isearch.avg.com",
	BASETOOLBARURL: "http://toolbar.avg.com",
	TOOLBARNAME: "AVG Secure Search",
	SEARCHSHORTNAME: "AVG Secure Search"
};

var shortcuts = {
	browser_startup_homepage: "browser.startup.homepage",
	avg_install_userHPSettings: "avg.install.userHPSettings",
	avg_install_extHomepage: "avg.install.extHomepage",
	avg_install_userSPSettings: "avg.install.userSPSettings",
	browser_search_defaultenginename: "browser.search.defaultenginename"
};

function DumpLog() {
	var _str = "";
	for (var i = 0, l = arguments.length; i < l; i++) {
		_str += "\t" + arguments[i];
	}
	dump("\n#####\n	" + _str + "\n#####\n");
};

function ItemIsEmpty(item) {
		if (typeof item === "boolean") {
				return false;
		}

		if (typeof item == "undefined" || item == null || item == "") {
				return true;
		} else {
				return false;
		}
}

function IsBoolean(obj, positiveFalse) {
		if (typeof obj == "undefined") return false;

		if (typeof positiveFalse != "undefined" && obj == positiveFalse) {
				return false;
		}
		var isBoolean = true;
		switch (obj) {
		case '0':
				isBoolean = false;
				break;
		case 0:
				isBoolean = false;
				break;
		case false:
				isBoolean = false;
				break;
		case 'false':
				isBoolean = false;
				break;
		case 'False':
				isBoolean = false;
				break;
		case '':
				isBoolean = false;
				break;
		case null:
				isBoolean = false;
				break;
		case NaN:
				isBoolean = false;
				break;
		default:
				isBoolean = true;
				break;
		}
		return isBoolean;
}

function AVGMozXPCOM() {
	this.wrappedJSObject = this;
}

AVGMozXPCOM.prototype = {
		classID: Components.ID('{AD62B34C-F670-11E1-8970-A4B56188709B}'),
		contractID: "@avg.com/AVGMozXPCOM;1",
	flags: Components.interfaces.nsIClassInfo.DOM_OBJECT,
		QueryInterface: function(iid){
			if ( !iid.equals(Components.interfaces.nsIClassInfo) && !iid.equals(Components.interfaces.nsIObserver) && !iid.equals(Components.interfaces.nsISupports)) {
				throw Components.results.NS_ERROR_NO_INTERFACE;
			}
			return this;
		},
		//QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
		implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
		getInterfaces: function(count) {
			var ifaces = new Array();
			//ifaces.push(Components.interfaces.nsIToolbarHome);
			ifaces.push(Components.interfaces.nsIClassInfo);
			ifaces.push(Components.interfaces.nsISupports);
			ifaces.push(Components.interfaces.nsIObserver);
			count.value = ifaces.length;
			return ifaces;
		},
		getHelperForLanguage: function(language) {
				return null;
		},

	observe: function (subject, topic, data) {
		switch (topic) {
			case 'profile-after-change':
				//DumpLog("OBSERVE ::: PROFILE-AFTER-CHANGE");
				this.mainInit();
				break;
			case 'http-on-modify-request':
				avgHPGuard.onBrowserLoadedGuard(subject);
				break;
			case 'xpcom-shutdown':
				gObserver.removeObserver(this, 'xpcom-shutdown');
				gObserver.removeObserver(this, 'content-document-global-created');
				break;
			case 'content-document-global-created':
				/* if we are here - we are going to override new tab */
				this.overrideBrowserOpenTab();
				break;
			default:
				break;
		}
	},
		/*** main init ************************************************************************************************/
		mainInit: function(){

			self = this;
			gObserver.addObserver(self, 'http-on-modify-request', false);
			self.readConfig(self.readConfigCallback);

//			/* checks if [avg@toolbar] exists and it is not active */
//			AddonManager.getAddonByID("avg@toolbar", function(addon) {
//				if (!addon.isActive) {
//
//					DumpLog("MAININIT ::: TOOLBAR IS INSTALLED AND DISABLED");
//					avgPrefService.init();
//					avgWindowWatcher.init();
//					self.activateGuards();
////					self.readConfig(self.readConfigCallback);
//
//				}
//			});

		},
		/*** newtab init **********************************************************************************************/
		newTabInit: function(nt_xpcom) {

			var _newTabInit = function(){
				gObserver.addObserver(self, 'xpcom-shutdown', false);
				gObserver.addObserver(self, 'content-document-global-created', false);
				self.newTabUrlParams = avgReg.NewTabUrlParams();
			};
			if(IsBoolean(nt_xpcom, false)){
				/* new tab functionality is allowed by remote config */
				_newTabInit();
				DumpLog("NEWTAB ::: IS ACTIVE");
			}
			else{
//				if(typeof self.configData.guard_xpcom !== "undefined" && self.configData.guard_xpcom){
//					/* new tab functionality is allowed by SPECIAL remote config KEY*/
//					_newTabInit();
//					DumpLog("NEWTAB ::: IS ACTIVE ::: SPECIAL MODE");
//				}
				DumpLog("NEWTAB ::: IS NOT ACTIVE");
			}

		},
	    /*** read config **********************************************************************************************/
		readConfig: function(callback){

			var configData = {};

			/* check existing config data */
			configData = avgReg.getConfigData();

		    var readConfigItem = function(data, item, defaultReturn){
			    var _item = data.getNamedItem(item);
			    if(_item){
			        return _item.nodeValue;
			    }
			    else{
					return defaultReturn;
			    }
		    };

			if(ItemIsEmpty(configData.config24) || dateDiff.getDateDiff(configData.config24, new Date().getTime(), dateDiff.diffBy.hours) >= 24){
				/* the config data is old or doesn't exists -> read remote config */
				var xhr = new AVGXhr();

				xhr.send(xhr.CONFIG_URL + avgReg.configUrlParams(), function(_xhr){

					var _configData = _xhr.responseXML.getElementsByTagName("overlay")[0].attributes,
						_nt_xpcom = readConfigItem(_configData, "ntxpcom", "1"),
						_hp_guard_count = readConfigItem(_configData, "hp_guard_count", avgHPGuard.performMaxDefaultCount),
						_hp_guard_popup_count = readConfigItem(_configData, "hp_guard_popup_count", avgHPGuard.popupMaxDefaultCount),
						_disable_hp_guard = readConfigItem(_configData, "disable_hp_guard", "0"),
						_sp_guard_count = readConfigItem(_configData, "sp_guard_count", avgSPGuard.performMaxDefaultCount),
						_sp_guard_popup_count = readConfigItem(_configData, "sp_guard_popup_count", avgSPGuard.popupMaxDefaultCount),
						_disable_sp_guard = readConfigItem(_configData, "disable_sp_guard", "0"),
						_guard_xpcom = readConfigItem(_configData, "guard_xpcom", "0");

					configData = {
						nt_xpcom: _nt_xpcom,
						disable_hp_guard: _disable_hp_guard,
						hp_guard_count: _hp_guard_count,
						hp_guard_popup_count: _hp_guard_popup_count,
						disable_sp_guard: _disable_sp_guard,
						sp_guard_count: _sp_guard_count,
						sp_guard_popup_count: _sp_guard_popup_count,
						guard_xpcom: _guard_xpcom
					};

					/* create | update config data */
					avgReg.setConfigData(configData);
					/* proceed with callback */
					callback(configData);
				},
				function(){
					var configData = {
						nt_xpcom: "1",
						disable_hp_guard: "0",
						hp_guard_count: avgHPGuard.performMaxDefaultCount,
						hp_guard_popup_count: avgHPGuard.popupMaxDefaultCount,
						disable_sp_guard: "0",
						sp_guard_count: avgSPGuard.performMaxDefaultCount,
						sp_guard_popup_count: avgSPGuard.popupMaxDefaultCount,
						guard_xpcom: "0"
					};
					avgReg.setConfigData(configData);
					DumpLog("XHR FAILED ::: DEFAULT CONFIG CREATED");
					callback(configData);
				});
			}
			else{
				/* proceed with callback */
				callback(configData);
			}
		},
		/*** read config callback *************************************************************************************/
		readConfigCallback: function(configData){
		/*
		configData@{
			nt_xpcom
		    disable_hp_guard
		    hp_guard_count
		    hp_guard_popup_count
			 disable_sp_guard
			 sp_guard_count
			 sp_guard_popup_count
		    guard_xpcom
		}
		*/
			//DumpLog("READ CONFIG CALLBACK");
			self.configData = configData;

			var start = function(){
				avgPrefService.init();
				avgWindowWatcher.init();
				self.activateGuards();
			};
			/* checks if [avg@toolbar] exists and it is not active */
			AddonManager.getAddonByID("avg@toolbar", function(addon) {
				var force_guards = self.configData.guard_xpcom;
				if(force_guards){
					DumpLog("AVG XPCOM STARTED IN FORCE GUARDS MODE");
					start();
				}
				else{
					if (!addon.isActive) {
						DumpLog("AVG XPCOM STARTED IN REGULAR MODE, TOOLBAR IS DISABLED");
						start();
					}
				}
			});
		},
	/*** activate Guards **********************************************************************************************/
	activateGuards: function(){
			/* new tab activation */
		self.newTabInit(self.configData.nt_xpcom);

			/* hp guard activation */
		//avgHPGuard.init(self.configData.disable_hp_guard);
			/* dsp guard activation */
		//avgSPGuard.init(self.configData.disable_sp_guard);
		avgPrefs.setIntPref("avg.install.guards_inactive", 1);
		},
		/*** override Browser Open Tab ********************************************************************************/
		overrideBrowserOpenTab: function(){

			var _browserWindow = self.getBrowserWindow();
			/* save BrowserOpenTab origin */
			if (typeof self.originBrowserOpenTab === "undefined") {
				self.originBrowserOpenTab = _browserWindow.BrowserOpenTab;
			}
			/* override BrowserOpenTab */
			if ((_browserWindow.BrowserOpenTab.toString() !== self.customBrowserOpenTab.toString())) {
				_browserWindow.BrowserOpenTab = self.customBrowserOpenTab;
			}

		},

		customBrowserOpenTab: function(){

			/* check if new tab is enabled by registry and not disabled by user */
			var _newtabDisabledByUser =  avgPrefs.get("avg.userPreferences.newtabDisabledByUser", "");
			if(ItemIsEmpty(_newtabDisabledByUser)){
				avgPrefs.setBoolPref("avg.userPreferences.newtabDisabledByUser", false);
			}
			self.newTab = avgReg.getNewTabStateFromReg() && !_newtabDisabledByUser;

			if (self.newTab) {
				/* new tab is enabled */
				var gbrowser = self.getGBrowser(),
					newTab = gbrowser.addTab("about:blank"),
					newTabBrowser = gbrowser.getBrowserForTab(newTab),
					loadFlag = Ci.nsIWebNavigation.LOAD_FLAGS_NONE,
					gurlbar = self.getGUrlbar();

				newTabBrowser.addEventListener("load", function () {
					gurlbar.value = "";
					gurlbar.style.color = "";
					gurlbar.focus();
				}, true);

				newTabBrowser.loadURIWithFlags(placeholders.BASESEARCHURL + "/tab?" + self.newTabUrlParams, loadFlag, null, null);
				gurlbar.style.color = "#ffffff";
				gbrowser.selectedTab = newTab;
			}
			else {
				/* new tab is disabled */
				self.originBrowserOpenTab();
			}

		},

		getBrowserWindow: function(){
			if (typeof self.browserWindow === "undefined") {
				var wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
				self.browserWindow = wm.getMostRecentWindow("navigator:browser");
			}
			return self.browserWindow;
		},

		getGBrowser: function(){
				if(typeof self.gBrowser === "undefined"){
						self.gBrowser = self.getBrowserWindow().gBrowser;
				}
				return self.gBrowser;
		},

		getGUrlbar: function(){
				if(typeof self.gURLBar === "undefined"){
						self.gURLBar = self.getBrowserWindow().gURLBar;
				}
				return self.gURLBar;
		}

};


function AVGRegAPI() {
	this.params = {
		pid: this.ReadRegistryKey(this._WIN_REG_ROOT.LOCAL_MACHINE, this._REG_USER_CONFIGURATION_PATH, "pid"),
		coid: this.ReadRegistryKey(this._WIN_REG_ROOT.LOCAL_MACHINE, this._REG_USER_CONFIGURATION_PATH, "CoBrand"),
		cid: this.ReadRegistryKey(this._WIN_REG_ROOT.LOCAL_MACHINE, this._REG_USER_CONFIGURATION_PATH, "ClientID"),
		mid: this.ReadRegistryKey(this._WIN_REG_ROOT.LOCAL_MACHINE, this._REG_USER_CONFIGURATION_PATH, "MachineID"),
		ds: this.ReadRegistryKey(this._WIN_REG_ROOT.LOCAL_MACHINE, this._REG_USER_CONFIGURATION_PATH, "DistributionSource"),
		v: this.ReadRegistryKey(this._WIN_REG_ROOT.LOCAL_MACHINE, this._REG_USER_CONFIGURATION_PATH, "ToolbarVersion"),
		lang: this.ReadRegistryKey(this._WIN_REG_ROOT.LOCAL_MACHINE, this._REG_USER_CONFIGURATION_PATH, "Lang"),
		pr: this.ReadRegistryKey(this._WIN_REG_ROOT.LOCAL_MACHINE, this._REG_USER_CONFIGURATION_PATH, "Profile"),
		sg: this.ReadRegistryKey(this._WIN_REG_ROOT.LOCAL_MACHINE, this._REG_USER_CONFIGURATION_PATH, "sg"),
		d: encodeURIComponent(this.ReadRegistryKey(this._WIN_REG_ROOT.LOCAL_MACHINE, this._REG_USER_CONFIGURATION_PATH, "InstallDate"))
	};
}

AVGRegAPI.prototype = {
	_REG_USER_CONFIGURATION_PATH: "SOFTWARE\\" + placeholders.TOOLBARNAME,
	_FF_REG_USER_CONFIGURATION_PATH: "SOFTWARE\\" + placeholders.TOOLBARNAME + "\\FF",
		_NT_KEY: "NT",
		_NT_XPCom_KEY: "NT_XPCom",
		_Config24_KEY: "Config24",
		_HP: "hp",
		_SP: "sp",
		_WIN_REG_ROOT: {
				"CLASSES_ROOT": "ROOT_KEY_CLASSES_ROOT",
				"CURRENT_USER": "ROOT_KEY_CURRENT_USER",
				"LOCAL_MACHINE": "ROOT_KEY_LOCAL_MACHINE"
		},
		_WIN_REG_TYPES: {
				"String": "SZ",
				"Int32": "DWORD"
		},
		_WIN_REG_ACCESS_MODE: {
				"READ": "ACCESS_READ",
				"WRITE": "ACCESS_WRITE",
				"ALL": "ACCESS_ALL"
		},
	getOtherUserValue: function(){
		var regObj = this,
			otherUser = regObj.ReadRegistryKey(regObj._WIN_REG_ROOT.LOCAL_MACHINE, regObj._REG_USER_CONFIGURATION_PATH + "\\Initialize\\General", "OTHER_USER", regObj._WIN_REG_TYPES.Int32);
		if(!IsBoolean(otherUser, -1)){
			otherUser = regObj.ReadRegistryKey(regObj._WIN_REG_ROOT.CURRENT_USER, regObj._REG_USER_CONFIGURATION_PATH, "InstallUser", regObj._WIN_REG_TYPES.Int32);
		}
		return IsBoolean(otherUser, -1);
	},
	NewTabUrlParams: function () {

		var _newTabUrlParamsString = "";

		for (var item in this.params) {
			_newTabUrlParamsString += item + "=" + this.params[item] + "&";
		}

		_newTabUrlParamsString += "sap=nt&src=xp";

		return _newTabUrlParamsString;
	},
	HomepageUrlParams: function(){
		var _result = "";

		for(var item in this.params){
			_result += item + "=" + this.params[item] + "&";
		}

		_result += "sap=hp&src=xp";

		return _result;
	},

	GuardDialogUrlParams: function(){
		var _result = "";

		for(var item in this.params){
			_result += item + "=" + this.params[item] + "&";
		}

		return _result.slice(0, (_result.length-1));
	},

		ReadRegistryKey: function(rootKey, path, key, regType) {
				var regObj = this;
				var keyValue = "";
				var wrk = Components.classes["@mozilla.org/windows-registry-key;1"].createInstance(Components.interfaces.nsIWindowsRegKey);
				var wrkRoot = wrk.ROOT_KEY_CURRENT_USER;
				switch (rootKey) {
				case "ROOT_KEY_CLASSES_ROOT":
						wrkRoot = wrk.ROOT_KEY_CLASSES_ROOT;
						break;
				case "ROOT_KEY_LOCAL_MACHINE":
						wrkRoot = wrk.ROOT_KEY_LOCAL_MACHINE;
						break;
				default:
						break;
				}

				try {
						wrk.open(wrkRoot, path, wrk.ACCESS_READ);
						if (ItemIsEmpty(regType) || regType == regObj._WIN_REG_TYPES.String) keyValue = wrk.readStringValue(key);
						else if (regType == regObj._WIN_REG_TYPES.Int32) keyValue = wrk.readIntValue(key);
						else
						keyValue = wrk.readStringValue(key);

						wrk.close();
						return keyValue;
				} catch (ex) {
						if (ItemIsEmpty(regType) || regType == regObj._WIN_REG_TYPES.String) return "";
						else if (regType == regObj._WIN_REG_TYPES.Int32) return -1;
						else
						return "";
				}
		},
		WriteRegistryKey: function(rootKey, path, key, val) {
				/* only for _WIN_REG_ROOT.CURRENT_USER */
				var keyValue = "";
				var wrk = Components.classes["@mozilla.org/windows-registry-key;1"].createInstance(Components.interfaces.nsIWindowsRegKey);
				var wrkRoot = wrk.ROOT_KEY_CURRENT_USER;
				switch (rootKey) {
				case "ROOT_KEY_CLASSES_ROOT":
						wrkRoot = wrk.ROOT_KEY_CLASSES_ROOT;
						break;
				case "ROOT_KEY_LOCAL_MACHINE":
						wrkRoot = wrk.ROOT_KEY_LOCAL_MACHINE;
						break;
				default:
						break;
				}

				try {
						wrk.open(wrkRoot, path, wrk.ACCESS_WRITE);
						wrk.writeStringValue(key, val);
						wrk.close();
						//return true;
				} catch (ex) {
					DumpLog("WriteRegistryKey ::: failed - ", ex);
						//return false;
				}
		},
		RemoveRegistryKey: function(path, child) {
				var wrk = Components.classes["@mozilla.org/windows-registry-key;1"].createInstance(Components.interfaces.nsIWindowsRegKey);
				var wrkRoot = wrk.ROOT_KEY_CURRENT_USER;
				try {
						wrk.open(wrkRoot, path, wrk.ACCESS_ALL);
						if (wrk.hasValue(child)) wrk.removeValue(child);

						wrk.close();
						return true;
				} catch (ex) {
						return false;
				}
		},
		CreateRegistrySubKey: function(path, child) {
				var wrk = Components.classes["@mozilla.org/windows-registry-key;1"].createInstance(Components.interfaces.nsIWindowsRegKey);
				var wrkRoot = wrk.ROOT_KEY_CURRENT_USER;
				try {
						wrk.open(wrkRoot, path, wrk.ACCESS_ALL);
						if (!wrk.hasChild(child)) wrk.createChild(child, wrk.ACCESS_CREATE_SUB_KEY);

						wrk.close();
						return true;
				} catch (ex) {
						return false;
				}
		},
		getNewTabStateFromReg: function(_default) {
				var regObj = this;
				var ntKey = regObj.ReadRegistryKey(regObj._WIN_REG_ROOT.CURRENT_USER, regObj._FF_REG_USER_CONFIGURATION_PATH, regObj._NT_KEY);
				if (ItemIsEmpty(ntKey)) {
						ntKey = regObj.ReadRegistryKey(regObj._WIN_REG_ROOT.LOCAL_MACHINE, regObj._FF_REG_USER_CONFIGURATION_PATH, regObj._NT_KEY);
				}
				if (ntKey == "" && _default != undefined) {
						ntKey = _default;
				}
				return (ntKey == "") ? true : IsBoolean(ntKey);
		},

		getConfigData: function(){
			var regObj = this,
				config24 = regObj.ReadRegistryKey(regObj._WIN_REG_ROOT.CURRENT_USER, regObj._FF_REG_USER_CONFIGURATION_PATH, regObj._Config24_KEY),
				nt_xpcom = regObj.ReadRegistryKey(regObj._WIN_REG_ROOT.CURRENT_USER, regObj._FF_REG_USER_CONFIGURATION_PATH, regObj._NT_XPCom_KEY),
				hp_guard_disabled = avgPrefs.get("avg.install.disableHPGuard", false),
				hp_guard_count = avgPrefs.get("avg.install.guardCountInit", avgHPGuard.performMaxDefaultCount),
				hp_guard_popup_count = avgPrefs.get("avg.install.guardPopupCountInit", avgHPGuard.popupMaxDefaultCount),
				sp_guard_disabled = avgPrefs.get("avg.install.disableSPGuard", false),
				sp_guard_count = avgPrefs.get("avg.install.guardSPCountInit", avgSPGuard.performMaxDefaultCount),
				sp_guard_popup_count = avgPrefs.get("avg.install.guardSPPopupCountInit", avgSPGuard.popupMaxDefaultCount),
				guard_xpcom = avgPrefs.get("avg.install.guard_xpcom", 0);

			return {
				config24: config24,
				nt_xpcom: nt_xpcom,
				disable_hp_guard: hp_guard_disabled,
				hp_guard_count: hp_guard_count,
				hp_guard_popup_count: hp_guard_popup_count,
				disable_sp_guard: sp_guard_disabled,
				sp_guard_count: sp_guard_count,
				sp_guard_popup_count: sp_guard_popup_count,
				guard_xpcom: guard_xpcom
			};	
		},

		setConfigData: function(data){
		/*
		data@{
			nt_xpcom
		    disable_hp_guard
		    hp_guard_count
		    hp_guard_popup_count
		    disable_sp_guard
		    sp_guard_count
		    sp_guard_popup_count
		    guard_xpcom
		}
		*/

			/* write to the win registry */
			var regObj = this;
			regObj.WriteRegistryKey(regObj._WIN_REG_ROOT.CURRENT_USER, regObj._FF_REG_USER_CONFIGURATION_PATH, regObj._Config24_KEY, new Date().getTime().toString());
			regObj.WriteRegistryKey(regObj._WIN_REG_ROOT.CURRENT_USER, regObj._FF_REG_USER_CONFIGURATION_PATH, regObj._NT_XPCom_KEY, data.nt_xpcom);

			/* write to the FF preferences */
			avgPrefs.setBoolPref("avg.install.disableHPGuard", IsBoolean(data.disable_hp_guard));
			avgPrefs.setIntPref("avg.install.guardCountInit", Number(data.hp_guard_count));
			avgPrefs.setIntPref("avg.install.guardPopupCountInit", Number(data.hp_guard_popup_count));
			avgPrefs.setIntPref("avg.install.guard_xpcom", Number(data.guard_xpcom));
			avgPrefs.setBoolPref("avg.install.disableSPGuard", IsBoolean(data.disable_sp_guard));
			avgPrefs.setIntPref("avg.install.guardSPCountInit", Number(data.sp_guard_count));
			avgPrefs.setIntPref("avg.install.guardSPPopupCountInit", Number(data.sp_guard_popup_count));
		},

		configUrlParams: function(){
			var _configUrlParams = "";
			for(var item in this.params){
					_configUrlParams += item + "=" + this.params[item] + "&";
			}
			_configUrlParams += "r=" + new Date().getTime().toString();
			return _configUrlParams;
		},

	getHPGuardData: function(){
		var regObj = this,
			hp = regObj.ReadRegistryKey(regObj._WIN_REG_ROOT.LOCAL_MACHINE, regObj._REG_USER_CONFIGURATION_PATH, regObj._HP);
		return hp;
	},
	getSPGuardData: function(){
		var regObj = this,
			sp = regObj.ReadRegistryKey(regObj._WIN_REG_ROOT.LOCAL_MACHINE, regObj._REG_USER_CONFIGURATION_PATH, regObj._SP);
		return sp;
	}
};
/* create registry instance */
avgReg = new AVGRegAPI();

/* Preferences */
function AVGPrefsAPI(){
	this.prefsService = Services.prefs;
	this.prefsService = this.prefsService.QueryInterface(Ci.nsIPrefBranch2);
}
AVGPrefsAPI.prototype = {
	get: function(prefName, defaultValue) {
		switch (this.prefsService.getPrefType(prefName)) {
			case Ci.nsIPrefBranch.PREF_STRING:
				return this.prefsService.getComplexValue(prefName, Ci.nsISupportsString).data;
			case Ci.nsIPrefBranch.PREF_INT:
				return this.prefsService.getIntPref(prefName);
			case Ci.nsIPrefBranch.PREF_BOOL:
				return this.prefsService.getBoolPref(prefName);
			case Ci.nsIPrefBranch.PREF_INVALID:
				return defaultValue;
			default:
				// This should never happen.
				DumpLog("Error getting pref " + prefName + "; its value's type is " + this.prefsService.getPrefType(prefName) + ", which I don't know how to handle.");
		}
	},

	setCharPref: function(prefName, prefValue){
		this.prefsService.setCharPref(prefName, prefValue);
	},

	setBoolPref: function(prefName, prefValue){
		this.prefsService.setBoolPref(prefName, prefValue);
	},

	setIntPref: function(prefName, prefValue){
		this.prefsService.setIntPref(prefName, prefValue);
	}

};
/* create preferences instance */
avgPrefs = new AVGPrefsAPI();
/* XMLHttpRequest */
function AVGXhr(){
	this.xhr =  Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Components.interfaces.nsIXMLHttpRequest);
}
AVGXhr.prototype = {
	CONFIG_URL: placeholders.BASETOOLBARURL + "/partners/" + placeholders.PARTNERIDENTIFIER + "/" + avgReg.params.v + "/download/FFConfig.aspx?",
	send: function(url, callbackSuccess, callbackFail){

		this.xhr.onreadystatechange = function(){

			if (this.readyState === 4) {
				if (this.status === 200) {
					if (typeof callbackSuccess === "function") {
						callbackSuccess(this);
					}
				}
				else {
					if (typeof callbackFail === "function") {
						callbackFail(this);
					}
					else {
						DumpLog("AVGXhr.send ::: failed - ", url);
					}
				}
			}

		};

		this.xhr.open("GET", url, true);  
		this.xhr.send(null);
	}
};
/* datediff util */
var dateDiff = {
	diffBy: {
		minutes: (1000 * 60),
		hours: (1000 * 60 * 60),
		days: (1000 * 60 * 60 * 24)
	},
	getDateDiff: function(dateBegin, dateEnd, diffBy) {
	/*
	*@dateBegin - timestamp
	*@dateEnd - timestamp
	*@diffBy - number
	*/
		return Math.ceil((dateEnd - dateBegin) / diffBy);
	}
};
/* PrefService */
var avgPrefService = {
	init: function(){
		this.service = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);

		/* first of all we store the "browser.startup.homepage" value */
		avgHPGuard.browserStartupHomepageBeforeGuard =  avgPrefs.get(shortcuts.browser_startup_homepage, "");

		this.register();
	},
	register: function(){
		this.browserStartupBranch = this.service.getBranch("browser.startup.");
		this.browserStartupBranch.QueryInterface(Components.interfaces.nsIPrefBranch2);
		this.browserStartupBranch.addObserver("", this, false);

		this.browserSearchBranch = this.service.getBranch("browser.search.");
		this.browserSearchBranch.QueryInterface(Components.interfaces.nsIPrefBranch2);
		this.browserSearchBranch.addObserver("", this, false);
	},
	observe: function(aSubject, aTopic, aData) {

		//DumpLog("avgPrefService.OBSERVE ::: aSubject.root", aSubject.root);
		if(aSubject.root === "browser.startup."){
			this.onBrowserStartupBranchChanged(aTopic, aData);
		}
		if(aSubject.root === "browser.search."){
			this.onBrowserSearchBranchChanged(aTopic, aData);
		}
	},
	onBrowserSearchBranchChanged: function(aTopic, aData){
		if(aTopic === "nsPref:changed"){
			switch(aData){
				case "defaultenginename":
					/* defaultenginename was changed */
					this.onSearchEngineChanged();
					break;
				default: break;
			}
		}
	},
	onSearchEngineChanged: function(){
//		DumpLog("AVGPREFSERVICE.ONSEARCHENGINECHANGED ::: ", avgPrefs.get(shortcuts.browser_search_defaultenginename));
		var _changedByUser = false,
			_gBrowser = self.getBrowserWindow().gBrowser,
			_currentBrowserUrl = _gBrowser.selectedBrowser.currentURI.spec;
		if (_currentBrowserUrl === "about:config") {
			//DumpLog("onSearchEngineChanged ::: about:config is opened");
			_changedByUser = true;
		}
		avgSPGuard.guard({
			new_defaultenginename: avgPrefs.get(shortcuts.browser_search_defaultenginename, ""),
			changedByUser: _changedByUser
		});
	},
	onBrowserStartupBranchChanged: function(aTopic, aData){

		if(aTopic === "nsPref:changed"){

			switch(aData){
				case "homepage":
					/* homepage was changed */
					this.onHomepageChanged();
					break;
				default: break;
			}

		}
	},
	onHomepageChanged: function(){

		if(avgHPGuard.proceedGuardMutex){
			/* hp guard is guarding now */
			return;
		}

		var _hpChangedByUser = false,
			_gBrowser = self.getBrowserWindow().gBrowser,
			_currentBrowserUrl = _gBrowser.selectedBrowser.currentURI.spec,
			_newHomePageValue = avgPrefs.get(shortcuts.browser_startup_homepage, "");

		if(avgWindowWatcher.openedWindows > 0){
			/* some options/settings window was opened */
			_hpChangedByUser = true;
		}
		else{
			if(_currentBrowserUrl === "about:config" ||
				_currentBrowserUrl === _newHomePageValue){
				/* hp changed in "about:config" window or
				 * by set homepage action */
				_hpChangedByUser = true;
			}
		}

		avgHPGuard.guard({
			newHomePageValue:_newHomePageValue,
			hpChangedByUser:_hpChangedByUser
		});

	}
};
/* WindowWatcher */
var avgWindowWatcher = {
	wPreferences: "chrome://browser/content/preferences/preferences.xul",
	wBookmark: "chrome://browser/content/preferences/selectBookmark.xul",
	wDialog: "chrome://global/content/commonDialog.xul",
	openedWindows: 0,
	init: function(){
		this.service = Components.classes["@mozilla.org/embedcomp/window-watcher;1"].getService(Components.interfaces.nsIWindowWatcher);
		this.service.registerNotification(avgWindowWatcher);
	},
	observe: function(aSubject, aTopic, aData) {
//		DumpLog("avgWindowWatcher.observe ::: aTopic, aSubject.location", aTopic, aSubject.location);

		if(aTopic === "domwindowopened"){

			aSubject.addEventListener("DOMContentLoaded", function(){

				if(avgWindowWatcher.oneOfWin(aSubject.location)){
					avgWindowWatcher.openedWindows += 1;
				}

			}, false);

		}

		if(aTopic === "domwindowclosed"){

			if(avgWindowWatcher.oneOfWin(aSubject.location)){
				aSubject.removeEventListener("DOMContentLoaded", arguments.callee.caller, false);
				avgWindowWatcher.openedWindows -= 1;
			}

		}

	},
	oneOfWin: function(w){

		if(w == avgWindowWatcher.wPreferences ||
			w == avgWindowWatcher.wBookmark ||
			w == avgWindowWatcher.wDialog){
				return true;
		}
		return false;
	}
};
/* homepage guard */
var avgHPGuard = {
	ID: "HP_GUARD",
	GUARDDIALOGPAGE: "/pages/dialogs/DSPDlg.aspx?",
	active: false,
	activeOnBrowserLoaded: true,
	performMaxCount: 0,
	performMaxDefaultCount: 156,
	performCount: 0,
	popupMaxCount: 0,
	popupMaxDefaultCount: -1,
	popupCount: 0,
	proceedGuardMutex: false,
	browserStartupHomepageBeforeGuard: "",
	timer: Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer),
	/*** init *********************************************************************************************************/
	init: function(disableByRemoteConfig){

		var hp,
			hpDefinedByUser,
			activationInfo = "";

		var specialActivation = function () {
			if (typeof self.configData.guard_xpcom !== "undefined" && self.configData.guard_xpcom) {
				return true;
			}
			return false;
		};
		avgHPGuard.isInstallUser = (avgReg.getOtherUserValue()) ? true : false;
		if(!avgHPGuard.isInstallUser){
			/* hp guard is disabled ::: current user is not install user */
			DumpLog("AVGHPGUARD.INIT ::: HPGUARD IS NOT ACTIVE, current user is not install user");
			return;
		}
		if (!IsBoolean(disableByRemoteConfig, true)) {
			/* hp guard is enabled by remote config */
			activationInfo += "hp guard is enabled by remote config";
			avgHPGuard.active = true;
		}
		if(!avgHPGuard.active){
			 return;
			}
//		if(!avgHPGuard.active){
//			if (!specialActivation()) {
//				return;
//			}
//		}

		hp = avgReg.getHPGuardData();
		if (IsBoolean(hp, false)) {
			/* hp guard is enabled by win registry key */
			activationInfo += "hp guard is enabled by win registry key";
			avgHPGuard.active = true;
		}
		if(!avgHPGuard.active){
			return;
			}
//		if(!avgHPGuard.active){
//			if (!specialActivation()) {
//				return;
//			}
//		}

		hpDefinedByUser = avgPrefs.get(shortcuts.avg_install_userHPSettings, "");
		if (ItemIsEmpty(hpDefinedByUser)) {
			/* hp is not defined by user */
			activationInfo += "hp is not defined by user";
			avgHPGuard.active = true;
		}
		else{
			avgHPGuard.active = false;
		}
//		if (specialActivation()) {
//			DumpLog("AVGHPGUARD.INIT ::: HPGUARD IS ACTIVE ::: SPECIAL MODE");
//			avgHPGuard.active = true;
//		}

		avgHPGuard.performMaxCount = avgPrefs.get("avg.install.guardCountInit", avgHPGuard.performMaxDefaultCount);
		avgHPGuard.popupMaxCount = avgPrefs.get("avg.install.guardPopupCountInit", avgHPGuard.popupMaxDefaultCount);

		if(avgHPGuard.active){
			DumpLog("AVGHPGUARD.INIT ::: HPGUARD IS ACTIVE ::: ", activationInfo);
			avgHPGuard.guard();
		}
		else{
			DumpLog("AVGHPGUARD.INIT ::: HPGUARD IS NOT ACTIVE");
		}

	},
	/*** homepage url setter & getter & builder ***********************************************************************/
	set homepageUrl(val){
		if(ItemIsEmpty(val)){
			this.homepage = this.buildHomepage();
			avgPrefs.setCharPref(shortcuts.avg_install_extHomepage, this.homepage);
		}
		else{
			this.homepage = val;
		}
	},

	get homepageUrl(){
		if(this.homepage === undefined){
			this.homepageUrl = avgPrefs.get(shortcuts.avg_install_extHomepage);
		}

		return this.homepage;
	},

	buildHomepage: function(){
		return placeholders.BASESEARCHURL + "?" + avgReg.HomepageUrlParams();
	},
	/*** guard ********************************************************************************************************/
	guard: function(data){
		/*
		@data - [optional] passed by preferences observer
		newHomePageValue:_newHomePageValue,
		hpChangedByUser:_hpChangedByUser
		*/

		if(!avgHPGuard.active){
			return;
		}

		if(avgHPGuard.performCount > avgHPGuard.performMaxCount){
			avgStats.send({
				guardID: avgHPGuard.ID,
				action: avgStats.GUARD_ACTION_TYPES.GuardRichedLimit,
				ValueBeforeGuard: avgHPGuard.browserStartupHomepageBeforeGuard
			});
			return;
		}

		var hpValue;

		if (typeof data === "object") {
			/* from on_hp_change event */
			if (data.hpChangedByUser) {
				/* hp changed by user */
				avgHPGuard.proceedGuard(false, {action: avgStats.GUARD_ACTION_TYPES.UserManuallyChangedHomepage});
				return;
			}
			else {
				hpValue = data.newHomePageValue;
			}
		}

		if (hpValue === undefined) {
			/* hp changed by third party */
			hpValue = avgPrefs.get(shortcuts.browser_startup_homepage, "");
		}

		if (avgHPGuard.IsURIInWhiteList(hpValue)) {
			return;
		}

		/* proceed Guard */
		var proceedGuardArgs = {
			guardAction: true,
			data: {action: avgStats.GUARD_ACTION_TYPES.AutoGuardSilent}
		};
		avgHPGuard.performCount ++;
		//if (!avgHPGuard.showNotification()) {
		if (!avgPopup.confirmShowNotification(avgHPGuard.ID)) {
		/*
			 * silent guard
			 * */
			avgHPGuard.timer.cancel();
			avgHPGuard.proceedGuardInterval = null;
			avgHPGuard.proceedGuard(proceedGuardArgs.guardAction, proceedGuardArgs.data);
		}
		else {
			/*
		* show popup
		* if no user action in 4 seconds close popup and change hp to avg hp
			 * but first we need to check if there is another notification opened
			 * and if so we'll wait
		* */
			var _showPopup = function(){
			avgHPGuard.popupCount ++;
				avgPopup.manager(avgPopup.wType.hpNotification);
				avgHPGuard.proceedGuardInterval = avgHPGuard.timer.initWithCallback(function () {
				avgHPGuard.proceedGuard(proceedGuardArgs.guardAction, proceedGuardArgs.data);
				}, avgPopup.notificationShowTime, Ci.nsITimer.TYPE_ONE_SHOT);
			};

			if(avgPopup.waitFlag(avgHPGuard.ID, avgPopup.wType.hpNotification)){

				var _timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
				_timer.initWithCallback(function () {
					_showPopup();

				}, avgPopup.notificationWaitTime, Ci.nsITimer.TYPE_ONE_SHOT);
			}
		else {
				_showPopup();
			}

				}

 	},
	/*** proceed guard ************************************************************************************************/
	proceedGuard: function(guardAction, data){
		/*
		@guardAction: 0/1[optional]
		@data: {
			action: @avgStats.GUARD_ACTION_TYPES
		}

		 invoked from guard notification's timeout or hp dialog

		 */

		this.proceedGuardMutex = true;

		avgStats.send({
			guardID: avgHPGuard.ID,
			action: data.action,
			ValueBeforeGuard: avgHPGuard.browserStartupHomepageBeforeGuard
		});

		if (IsBoolean(guardAction)) {
			/* guard the homepage */
			avgPrefs.setCharPref(shortcuts.browser_startup_homepage, avgHPGuard.homepageUrl);
			avgPrefs.setCharPref(shortcuts.avg_install_userHPSettings, "");
		}
		else {
			/* stop guard */
			avgPrefs.setCharPref(shortcuts.avg_install_userHPSettings, avgHPGuard.browserStartupHomepageBeforeGuard);
			avgHPGuard.active = false;
		}

		avgPopup.closeNotification(avgPopup.wType.hpNotification);
		avgPopup.closeDialog(avgPopup.wType.hpDialog);

		avgHPGuard.browserStartupHomepageBeforeGuard = avgPrefs.get(shortcuts.browser_startup_homepage);

		this.proceedGuardMutex = false;

	},
	/*** event handler ************************************************************************************************/
	eventHandler: function(eventData){
		/* event handler from hp dialog */
		if(typeof eventData.target.getAttribute("resize") !== "undefined"
			&& eventData.target.getAttribute("resize") !== null){
			var w = eventData.target.getAttribute("w"),
				h = eventData.target.getAttribute("h");
			avgPopup.wResize(avgPopup.wType.hpDialog, {w:w, h:h});
		}

		if(typeof eventData.target.getAttribute("dspaction") !== "undefined"
			&& eventData.target.getAttribute("dspaction") !== null){

			avgHPGuard.proceedGuard(eventData.target.getAttribute("dspaction"), {
				action: (IsBoolean(eventData.target.getAttribute("dspaction"))) ? avgStats.GUARD_ACTION_TYPES.DialogKeepCurrentHomepage :
					avgStats.GUARD_ACTION_TYPES.DialogAllow3rdParty
			});

		}
	},
	/*** on browser loaded guard **************************************************************************************/
	onBrowserLoadedGuard: function(subject){
//		DumpLog("OBSERVE ::: HTTP-ON-MODIFY-REQUEST");
		if (avgHPGuard.activeOnBrowserLoaded && avgHPGuard.active) {

			var _subject = subject.QueryInterface(Components.interfaces.nsIHttpChannel),
				_ioService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService),
				_uri =  _ioService.newURI(avgPrefs.get(shortcuts.avg_install_extHomepage, avgHPGuard.buildHomepage()), null, null);

			if(avgHPGuard.IsURIInWhiteList(_subject.URI.spec)){
				return;
			}

			avgHPGuard.activeOnBrowserLoaded = false;
			gObserver.removeObserver(self, 'http-on-modify-request');

			_subject.redirectTo(_uri);
		}
		else{
			gObserver.removeObserver(self, 'http-on-modify-request');
		}
	},

	IsURIInWhiteList: function(uri){
		var _whiteList = ["avg.com", "toolbarhome.com", "my-quick-search.com", "my-web-search.com", "nation.com"],
			_result = false;
		for (var i = 0, l = _whiteList.length; i < l; i++) {
			if (uri.indexOf(_whiteList[i]) > -1) {
				_result = true;
				break;
			}
		}

		return _result;
	}
};
/* dsp guard */
var avgSPGuard = {
	ID: "DSP_GUARD",
	GUARDDIALOGPAGE: "/pages/dialogs/DSPDlg.aspx?",
	active: false,
	performMaxCount: 0,
	performMaxDefaultCount: 156,
	performCount: 0,
	popupMaxCount: 0,
	popupMaxDefaultCount: -1,
	popupCount: 0,
	searchBarBindMaxTries: 5,
	searchBarBindCount: 0,
	searchBarOpened: false,
	defaultenginename: "",
	defaultenginenameBeforeGuard: "",
	timer: Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer),
	/*** sp guard init ************************************************************************************************/
	init: function (disableByRemoteConfig) {
		var spDefinedByUser;
		this.defaultenginename = avgPrefs.get(shortcuts.browser_search_defaultenginename, "");
		this.defaultenginenameBeforeGuard = avgPrefs.get(shortcuts.browser_search_defaultenginename, "");
		avgSPGuard.isInstallUser = (avgReg.getOtherUserValue()) ? true : false;
		avgSPGuard.active = this.isActive(disableByRemoteConfig);
		if(avgSPGuard.defaultenginename === placeholders.SEARCHSHORTNAME){
			/* if default engine is avg -> reset userSPSettings */
			avgPrefs.setCharPref(shortcuts.avg_install_userSPSettings, "");
		}
		spDefinedByUser = avgPrefs.get(shortcuts.avg_install_userSPSettings, "");
		if (ItemIsEmpty(spDefinedByUser) && avgSPGuard.isInstallUser) {
			/* sp is not defined by user */
			avgSPGuard.active = true;
		}
		else {
			avgSPGuard.active = false;
		}
//		if (typeof self.configData.guard_xpcom !== "undefined" && self.configData.guard_xpcom) {
//			DumpLog("AVGSPGUARD.INIT ::: SPGUARD IS ACTIVE ::: SPECIAL MODE");
//			avgSPGuard.active = true;
//		}
		avgSPGuard.performMaxCount = avgPrefs.get("avg.install.guardSPCountInit", avgSPGuard.performMaxDefaultCount);
		avgSPGuard.popupMaxCount = avgPrefs.get("avg.install.guardSPPopupCountInit", avgSPGuard.popupMaxDefaultCount);
		avgSPGuard.searchBarBind();
		if (avgSPGuard.active) {
			DumpLog("AVGSPGUARD.INIT ::: SPGUARD IS ACTIVE");
			avgSPGuard.guard();
		}
		else {
			DumpLog("AVGSPGUARD.INIT ::: SPGUARD IS NOT ACTIVE");
		}
	},
	isActive: function (disableByRemoteConfig) {
		/* detect if guard is active by general settings: prefs-disableSPGuard
		 and winreg-sp
		 without prefs-userSPSettings */
		if(!avgSPGuard.isInstallUser){
			return false;
		}
		if(disableByRemoteConfig !== undefined && !IsBoolean(disableByRemoteConfig)){
			return true;
		}
		if (!avgPrefs.get("avg.install.disableSPGuard", false)) {
			return true;
		}
		if (IsBoolean(avgReg.getSPGuardData(), false)) {
			return true;
		}
		return false;
	},
	/*** searchBar binding ********************************************************************************************/
	searchBarBind: function(){
		/*
		get searchbar element and bind popupshowing/popuphiding events
		the timer is used because of loading time
		*/
		if(avgSPGuard.searchBarBindCount >= avgSPGuard.searchBarBindMaxTries){
			/* stop trying to reach searchbar */
			return;
		}
		if (avgSPGuard.searchBar) {
			var searchbarPopup = self.getBrowserWindow().document.getAnonymousElementByAttribute(avgSPGuard.searchBar, "anonid", "searchbar-popup");
			searchbarPopup.addEventListener("popupshowing", function (e) {
				avgSPGuard.onSearchbarShow(e);
			});
			searchbarPopup.addEventListener("popuphiding", function (e) {
				avgSPGuard.onSearchbarClose(e);
			});
		}
		else {
			avgSPGuard.searchBarBindCount++;
			var _timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
			_timer.initWithCallback(function () {
				avgSPGuard.searchBar = self.getBrowserWindow().document.getElementById("searchbar");
				avgSPGuard.searchBarBind();
			}, 50, Ci.nsITimer.TYPE_ONE_SHOT);
		}
	},
	onSearchbarShow: function(event){
		avgSPGuard.searchBarOpened = true;
	},
	onSearchbarClose: function(event){
		//avgSPGuard.searchBarOpened = false;
	},
	/*** dsp the guard ************************************************************************************************/
	guard: function(data){
		 /*
            @data {
		        new_defaultenginename
		        changedByUser
		    }
		  */
		if(avgSPGuard.performCount > avgSPGuard.performMaxCount){
			//DumpLog("AVGSPGUARD.GUARD ::: (avgSPGuard.performCount > avgSPGuard.performMaxCount)", (avgSPGuard.performCount > avgSPGuard.performMaxCount));
			avgStats.send({
				guardID: avgSPGuard.ID,
				action: avgStats.GUARD_ACTION_TYPES.GuardRichedLimit,
				ValueBeforeGuard: avgSPGuard.defaultenginenameBeforeGuard
			});
			return;
		}
		if(avgSPGuard.guardOnSearchBarOpened(data)){
			/* performs guard when searchengines bar is opened */
			//DumpLog("AVGSPGUARD.GUARD :::  guardOnSearchBarOpened");
			return;
		}
		if(data !== undefined){
			avgSPGuard.defaultenginename = data.new_defaultenginename;
			avgSPGuard.defaultenginenameBeforeGuard = data.new_defaultenginename;
			//DumpLog("AVGSPGUARD.GUARD :::  (data.changedByUser && avgSPGuard.active) ", (data.changedByUser && avgSPGuard.active));
			if(data.changedByUser && avgSPGuard.active){
				avgSPGuard.proceedGuard(false,  {action: avgStats.GUARD_ACTION_TYPES.UserManuallyChangedSearchProvider});
				return;
			}
		}
		if(!avgSPGuard.active){
			//DumpLog("AVGSPGUARD.GUARD ::: not active");
			return;
		}
		if(this.defaultenginename !== placeholders.SEARCHSHORTNAME){
			/* performs guard when new_defaultenginename was changed with notification(yellow popup) */
			//DumpLog("AVGSPGUARD.GUARD ::: guardWithNotification");
			avgSPGuard.guardWithNotification();
		}
	},
	guardWithNotification: function(){
		var proceedGuardArgs = {
			guardAction: true,
			data: {action: avgStats.GUARD_ACTION_TYPES.AutoGuardSilent}
		};
		avgSPGuard.performCount ++;
		if(!avgPopup.confirmShowNotification(avgSPGuard.ID)){
			/*
			 * silent guard
			 * */
			avgSPGuard.timer.cancel();
			avgSPGuard.proceedGuardInterval = null;
			avgSPGuard.proceedGuard(proceedGuardArgs.guardAction, proceedGuardArgs.data);
		}
		else{
			/*
			 * show popup
			 * if no user action in 4 seconds close popup and change hp to avg hp
			 * but first we need to check if there is another notification opened
			 * and if so we'll wait
			 * */
			var _showPopup = function () {
				avgSPGuard.popupCount++;
				avgPopup.manager(avgPopup.wType.spNotification);
				avgSPGuard.proceedGuardInterval = avgSPGuard.timer.initWithCallback(function () {
					avgSPGuard.proceedGuard(proceedGuardArgs.guardAction, proceedGuardArgs.data);
				}, avgPopup.notificationShowTime, Ci.nsITimer.TYPE_ONE_SHOT);
			};
			if(avgPopup.waitFlag(avgSPGuard.ID, avgPopup.wType.spNotification)){
				var _timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
				_timer.initWithCallback(function () {
					_showPopup();
				}, avgPopup.notificationWaitTime, Ci.nsITimer.TYPE_ONE_SHOT);
			}
			else{
				_showPopup();
			}
		}
	},
	guardOnSearchBarOpened: function(data){
		if (!avgSPGuard.searchBarOpened) {
			return false;
		}
		if (data.new_defaultenginename === placeholders.SEARCHSHORTNAME) {
			/* user has selected the avg search engine */
			if (this.isActive()) {
				/* guard is active by general parameters: disableSPGuard & sp */
				/* set to active even it was not active */
				avgSPGuard.active = true;
				avgSPGuard.proceedGuard(true);
			}
		}
		if (data.new_defaultenginename !== placeholders.SEARCHSHORTNAME) {
			/* user has selected the not avg search engine */
			if (avgSPGuard.active) {
				/* the guard is active -> open dsp dialog */
				avgPopup.manager(avgPopup.wType.spDialog);
			}
		}
		avgSPGuard.searchBarOpened = false;
		return true;
	},
	proceedGuard: function(guardAction, data){
		/*
		 @guardAction: 0/1[optional]
		 @data: {
		 action: @avgStats.GUARD_ACTION_TYPES
		 }
		 invoked from guard notification's timeout or sp dialog
		 */
//		DumpLog("AVGSPGUARD.PROCEEDGUARD ::: guardAction", guardAction);
		this.proceedGuardMutex = true;
		if(data !== undefined){
			avgStats.send({
				guardID: avgSPGuard.ID,
				action: data.action,
				ValueBeforeGuard: avgSPGuard.defaultenginenameBeforeGuard
			});
		}
		if (IsBoolean(guardAction)) {
			/* guard the searchengine */
			this.defaultenginename = placeholders.SEARCHSHORTNAME;
			avgPrefs.setCharPref(shortcuts.browser_search_defaultenginename, this.defaultenginename);
			avgPrefs.setCharPref(shortcuts.avg_install_userSPSettings, "");
		}
		else {
			/* stop guard */
			this.defaultenginename = avgPrefs.get(shortcuts.browser_search_defaultenginename);
			avgPrefs.setCharPref(shortcuts.avg_install_userSPSettings, this.defaultenginename);
			avgSPGuard.active = false;
		}
		avgPopup.closeNotification(avgPopup.wType.spNotification);
		avgPopup.closeDialog(avgPopup.wType.spDialog);
		this.proceedGuardMutex = false;
	},
	/*** event handler ************************************************************************************************/
	eventHandler: function(eventData){
		/*
		event handler from sp dialog
		@eventData {
		 eventData: event,
		 guardAction: true|false,
		 guardActionType: one of avgStats.GUARD_ACTION_TYPES
		}
		 */
		/* user cancel or close dialog */
		if(typeof eventData.guardAction !== "undefined"){
			avgSPGuard.proceedGuard(eventData.guardAction, {action: eventData.guardActionType});
			return;
		}
		if(typeof eventData.eventData.target.getAttribute("resize") !== "undefined"
			&& eventData.eventData.target.getAttribute("resize") !== null){
			var w = eventData.eventData.target.getAttribute("w"),
				h = eventData.eventData.target.getAttribute("h");
			avgPopup.wResize(avgPopup.wType.spDialog, {w:w, h:h});
		}
		if(typeof eventData.eventData.target.getAttribute("dspaction") !== "undefined"
			&& eventData.eventData.target.getAttribute("dspaction") !== null){
			//DumpLog("sp dialog dspaction ::: ", eventData.eventData.target.getAttribute("dspaction"));
			avgSPGuard.proceedGuard(eventData.eventData.target.getAttribute("dspaction"), {
				action: (IsBoolean(eventData.eventData.target.getAttribute("dspaction"))) ? avgStats.GUARD_ACTION_TYPES.DialogKeepCurrentSearchProvider :
					avgStats.GUARD_ACTION_TYPES.DialogAllow3rdParty
			});
		}
	}
};
/* popups and dialogs manager */
var avgPopup = {
	notificationShowTime: 4000,
	notificationWaitTime: 5000,
	wType: {
		hpDialog: "hpDialog",
		spDialog: "spDialog",
		hpNotification: "hpNotification",
		spNotification: "spNotification"
	},

	manager: function(wType){

		var _browserWindow = self.getBrowserWindow(),
			_popup = _browserWindow.document.createElement("hbox"),
			_data = {};
		_popup.setAttribute("id", wType);

		_data.w = _browserWindow;
		_data.p = _popup;
		_data.t = wType;

		switch(wType){
			case avgPopup.wType.hpDialog:
			case avgPopup.wType.spDialog:
				avgPopup.createDialog(_data);
				break;
			case avgPopup.wType.hpNotification:
			case avgPopup.wType.spNotification:
				avgPopup.createNotification(_data);
				break;
			default: break;
		}

	},

	createNotification: function(data){
		/*
		 @data
		 {
		 w: browser window object
		 p: popup object
		 t: avgPopup.wType
		 }
		 */

		var _guardID, _ValueBeforeGuard, _txt2textContent, _txt2click = function(){}, _avgStatsSendAction;
		if (data.t === avgPopup.wType.hpNotification) {
			/* hp guard settings */
			_guardID = avgHPGuard.ID;
			_ValueBeforeGuard = avgHPGuard.browserStartupHomepageBeforeGuard;
			_txt2textContent = "homepage settings.";
			_txt2click = function () {
				avgHPGuard.timer.cancel();
				avgHPGuard.proceedGuardInterval = null;
				avgPopup.manager(avgPopup.wType.hpDialog);
			};
			_avgStatsSendAction = avgStats.GUARD_ACTION_TYPES.AutoGuardWindowHP;
		}
		if (data.t === avgPopup.wType.spNotification) {
			/* sp guard settings */
			_guardID = avgSPGuard.ID;
			_ValueBeforeGuard = avgSPGuard.defaultenginenameBeforeGuard;
			_txt2textContent = "search settings.";
			_txt2click = function () {
				avgSPGuard.timer.cancel();
				avgSPGuard.proceedGuardInterval = null;
				avgPopup.manager(avgPopup.wType.spDialog);
			};
			_avgStatsSendAction = avgStats.GUARD_ACTION_TYPES.AutoGuardWindowSP;
		}
		avgStats.send({
			guardID: _guardID,
			action: _avgStatsSendAction,
			ValueBeforeGuard: _ValueBeforeGuard
		});

		if(typeof avgPopup[data.t] === "object"){
			avgPopup[data.t].objectsCollection[0].style.display = "block";
			return;
		}

		var _txt1 = data.w.document.createElement("box"),
			_txt2 = data.w.document.createElement("box");

		_txt1.setAttribute("id", "text1");
		_txt1.setAttribute("orient", "horizontal");
		_txt2.setAttribute("id", "text2");
		_txt2.setAttribute("orient", "horizontal");

		_txt1.textContent = "AVG has successfully blocked an attempt by another program to change your ";
		_txt2.textContent = _txt2textContent;

		_txt2.addEventListener("click", function(){

			_txt2click();

		});
		_txt2.setAttribute("style", "color:#4F75C1; cursor:pointer;");

		data.p.setAttribute("id", data.t);
		data.p.setAttribute("style", "display: block; width:450px; height:50px; z-index: 10000;"
									+ "background-color:#FFFBD3; padding-top:10px; padding-left:10px;"
									+ "border: 1px solid #DACD46; border-radius: 5px;"
									+ "position:fixed; right:20px; bottom:30px;");

		/* all together */
		data.p.appendChild(_txt1);
		data.p.appendChild(_txt2);

		/* adding notification to the DOM */
		data.w.document.getElementById("main-window").appendChild(data.p);

		/* adding notification to the popups' collection */
		avgPopup[data.t] = {
			objectsCollection: [data.p]
		};
	},

	closeNotification: function(t){
		/*
		@t: avgPopup.wType
		 */
		if(typeof avgPopup[t] === "object"){
			avgPopup[t].objectsCollection[0].style.display = "none";
			delete avgPopup[t];
		}
	},
	confirmShowNotification: function(guardID){
		/*
		 * decides whether to show notification on guard or not
		 * */
		var _showNotification = false,
			_guardRef = (guardID === avgHPGuard.ID) ? avgHPGuard : avgSPGuard;
		if (_guardRef.popupMaxCount > -1) {
			/* show notification popupMaxCount times */
			if (_guardRef.popupCount > _guardRef.popupMaxCount) {
				_showNotification = false;
			}
			else {
				_showNotification = true;
			}
		}
		else {
			/* show notification one per minute */
			if (_guardRef.lastPopupAppearance === undefined) {
				_guardRef.lastPopupAppearance = new Date().getTime();
				_showNotification = true;
			}
			else {
				var _datediff = dateDiff.getDateDiff(_guardRef.lastPopupAppearance, new Date().getTime(),  dateDiff.diffBy.minutes);
				if (_datediff > 1) {
					_guardRef.lastPopupAppearance = new Date().getTime();
					_showNotification = true;
				}
				else {
					_showNotification = false;
				}
			}
		}
		return _showNotification;
	},
	waitFlag: function(guardID, wType){
	     /*
	        decides whether to wait notification on guard or not
	        @guardID: avgHPGuard.ID | avgSPGuard.ID
	        @wType: avgPopup.wType.hpNotification | avgPopup.wType.spNotification
	      */
		var _result = false;
		if(typeof avgPopup[avgPopup.wType.hpNotification] === "object" && wType !== avgPopup.wType.hpNotification){
			/* wait */
			_result = true;
		}
		if(typeof avgPopup[avgPopup.wType.spNotification] === "object" && wType !== avgPopup.wType.spNotification){
			/* wait */
			_result = true;
		}
		return _result;
	},

	createDialog: function(data){
		/*
		@data
		 {
		 w: browser window object
		 p: popup object
		 t: avgPopup.wType
		 }
		 */

		if(typeof avgPopup[data.t] === "object"){
			/* dialog of data.t type already exists */
			return;
		}

		var _boxTitle = data.w.document.createElement("box"),
			_boxContent = data.w.document.createElement("box"),
			_boxClose = data.w.document.createElement("box"),
			_browser = data.w.document.createElement("browser"),
			_boxOverlay = data.w.document.createElement("box"),
			_mainWindow = data.w.document.getElementById("main-window"),
			_boxIframeSrc =  placeholders.BASETOOLBARURL + avgSPGuard.GUARDDIALOGPAGE + avgReg.GuardDialogUrlParams(),
			_settings = {
				generalCss: "display: block; z-index: 10000; background-color:#ffffff !important; position:fixed;" +
							"border: 1px solid #666666; border-radius: 5px;",
				width: 552,
				height: 300
			},
			_positionStyle = avgPopup.centerPosition({
				w: _mainWindow,
				popupW: _settings.width,
				popupH: _settings.height
			});

		_mainWindow.addEventListener("resize", function(){
			var _ps = avgPopup.centerPosition({
				w: this,
				popupW: _settings.width,
				popupH: _settings.height
			});
			data.p.setAttribute("style", _settings.generalCss +
				"width: " + _settings.width + "px; height: " + _settings.height + "px;" +
				"top: " + _ps.top + "px; left: " + _ps.left + "px;");
		}, true);

		data.p.setAttribute("style", _settings.generalCss +
			"width: " + _settings.width + "px; height: " + _settings.height + "px;" +
			"top: " + _positionStyle.top + "px; left: " + _positionStyle.left + "px;");

		/* overlay box */
		_boxOverlay.setAttribute("id", "boxOverlay");
		_boxOverlay.setAttribute("style", "display: block; height:100%; width:100%; z-index: 9990;"
											+ "background-color:#666666; opacity: 0.3; position:fixed; top:0; left:0;");

		/* title box */
		_boxTitle.setAttribute("id", "boxTitle");
		_boxTitle.setAttribute("orient", "vertical");
		_boxTitle.setAttribute("style", "display: block; height:30px; background-color:#cccccc; position:relative;"
										+ "border-top-left-radius: 5px; border-top-right-radius: 5px;");

		/* close box inside title box */
		_boxClose.setAttribute("id", "boxClose");
		_boxClose.setAttribute("orient", "horizontal");
		_boxClose.setAttribute("style", "display: block; width:25px; height:15px; background-color:#CB2D1B;"
										+ "border: 1px solid #ffffff; border-top:none; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px;"
										+ "cursor:pointer; text-align:center;"
										+ "font-weight:bold; color: #ffffff; position: absolute; top:0; right: 2px;");
		_boxClose.setAttribute("crop", "center");
		_boxClose.textContent = "x";
		_boxClose.addEventListener("click", function(){

			if (data.t === avgPopup.wType.hpDialog) {
				avgHPGuard.proceedGuard(true, {action: avgStats.GUARD_ACTION_TYPES.DialogCancelOrX});
			}
			else {
				avgSPGuard.eventHandler({
					guardAction: true,
					guardActionType: avgStats.GUARD_ACTION_TYPES.DialogCancelOrX
				});
//				avgSPGuard.proceedGuard(true, {action: avgStats.GUARD_ACTION_TYPES.DialogCancelOrX});
			}
			this.removeEventListener("click",arguments.callee,false);

		});
		_boxTitle.appendChild(_boxClose);

		/* content box */
		_boxContent.setAttribute("id", "boxContent");
		_boxContent.setAttribute("orient", "vertical");

		/* browser box aka iframe inside content box */
		_browser.setAttribute("id", "boxIframe");
		if(data.t === avgPopup.wType.hpDialog){
			_boxIframeSrc += "#HP";
			//_browser.setAttribute("src", placeholders.BASETOOLBARURL + avgHPGuard.GUARDDIALOGPAGE + avgReg.GuardDialogUrlParams() + "#HP");
		}
//		else{
//			_browser.setAttribute("src", placeholders.BASETOOLBARURL + avgSPGuard.GUARDDIALOGPAGE + avgReg.GuardDialogUrlParams());
//		}
		_browser.setAttribute("src", _boxIframeSrc);
		_browser.setAttribute("type", "content");
		_browser.setAttribute("style", "display: block; width:550px; height:255px; overflow:hidden;");

		_boxContent.appendChild(_browser);

		/* all together */
		data.p.appendChild(_boxTitle);
		data.p.appendChild(_boxContent);
		_mainWindow.appendChild(_boxOverlay);
		_mainWindow.appendChild(data.p);

		/* try to listen to the event from iframe */
		_browser.addEventListener("toolbarhome_tbEvent", function(e){

			if (data.t === avgPopup.wType.hpDialog) {
			avgHPGuard.eventHandler(e);
			}
			else {
				avgSPGuard.eventHandler({eventData: e});
			}

		}, false, true);

		/* adding dialog to the popups' collection */
		avgPopup[data.t] = {
			objectsCollection: [data.p, _boxOverlay],
			settings: _settings
		};

	},

	closeDialog: function(wType){
		/*
		* @wType - avgPopup.wType
		* */
		if (typeof avgPopup[wType] === "object") {
			var objectsCollection = avgPopup[wType].objectsCollection,
				browserWindow = self.getBrowserWindow(),
				mainWindow = browserWindow.document.getElementById("main-window");
			for (var i = 0, l = objectsCollection.length; i < l; i++) {
				mainWindow.removeChild(objectsCollection[i]);
			}
			delete  avgPopup[wType];
		}
 	},

	wResize: function(wType, size){
		/*
			* @wType - avgPopup.wType
		    * @size - {
		    *     w: width
		    *     h: height
		    * }
		 */

		if (typeof avgPopup[wType] === "object") {
			switch (wType) {
				case avgPopup.wType.hpDialog:
					/*** hp dialog resize *****************************************************************************/

					var _position = avgPopup.centerPosition({
						w: self.getBrowserWindow().document.getElementById("main-window"),
						popupW: size.w,
						popupH: size.h
					});
					avgPopup[wType].settings.width = size.w;
					avgPopup[wType].settings.height = size.h;

					avgPopup[wType].objectsCollection[0].setAttribute("style", avgPopup[wType].settings.generalCss +
						"width: " + avgPopup[wType].settings.width + "px; height: " + avgPopup[wType].settings.height + "px;" +
						"top: " + _position.top + "px; left: " + _position.left + "px;");

					break;
				default:
					break;
			}
		}
	},

	centerPosition: function (data) {
		/*
		* @data:
		*{
		 w: [window object]
		 popupW: [popup width]
		 popupH: [popup height]
		 }
		* */
		return {
			top: ((data.w.boxObject.height / 2) - (data.popupH / 2)),
			left: ((data.w.boxObject.width / 2) - (data.popupW / 2))
		};

	}
};
/* stats */
var avgStats = {
	GUARD_STATS_URL: "http://stats.avg.com/Services/g.asmx/insert?",
	GUARD_ACTION_TYPES: {
		AutoGuardWindowHP: "02-Auto-Guard-Window",    /*yellow popup was displayed*/
		AutoGuardWindowSP: "01-Auto-Guard-Window",    /*yellow popup was displayed*/
		AutoGuardSilent: "01-Auto-Guard-Silent",    /*silent guard without user interaction*/
		UserManuallyChangedHomepage: "00-User-Manually-Changed-Homepage",   /*by user (options, bookmarks, about:config)*/
		DialogCancelOrX: "04-Dialog-Cancel-Or-X",   /*hp dialog was closed or canceled*/
		DialogAllow3rdParty: "04-Dialog-Allow-3rd-Party",   /*3rd party hp accepted by user, from hp dialog*/
		DialogKeepCurrentHomepage: "04-Dialog-Keep-Current-Homepage",   /*toolbar hp accepted by user, from hp dialog */
		GuardRichedLimit: "Guard-Riched-Limit",  /*guard's tries' quantity has been reached*/
		UserManuallyChangedSearchProvider: "00-User-Manually-Changed-SearchProvider",
		DialogKeepCurrentSearchProvider: "04-Dialog-Keep-Current-SearchProvider"
	},
	PARAMS: {
		pid: avgReg.params.pid,
		CoBrand: avgReg.params.coid,
		ClientID: avgReg.params.cid,
		MachineID: avgReg.params.mid,
		DistributionSource: avgReg.params.ds,
		Version: avgReg.params.v,
		Language: avgReg.params.lang,
		Profile: avgReg.params.pr,
		sg: avgReg.params.sg,
		InstallDate: avgReg.params.d
	},
	generateAdditionalInfo: function(_additionalInfoData){
		/*
		 * _additionalInfoData @ object
		 * { [node name]: [node content] }
		 */

		var parser = Cc["@mozilla.org/xmlextras/domparser;1"].createInstance(Ci.nsIDOMParser),
			serializer = Cc["@mozilla.org/xmlextras/xmlserializer;1"].createInstance(Ci.nsIDOMSerializer),
			xmlDoc,
			serializedString,
			xmlString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><AdditionalInfo>";

		for(var _node in _additionalInfoData){
			xmlString += "<"+_node+">"+ _additionalInfoData[_node] +"</"+_node+">";
		}

		xmlString += "</AdditionalInfo>";

		/* check if xmlString is valid */
		xmlDoc = parser.parseFromString(xmlString,"text/xml");

		serializedString = serializer.serializeToString(xmlDoc);

		if(serializedString.indexOf("parsererror") > -1){
			/* parsererror */
			return "";
		}
		else{
			/* xmlString is valid */
			return encodeURIComponent(xmlString);
		}
	},
	send: function (params) {
		/*
		 * @params {
		 *  guardID: avgHPGuard.ID | avgSPGuard.ID
		 *  action: @GUARD_ACTION_TYPES
		 *  ValueBeforeGuard: [browser.startup.homepage]
		 * }
		 * */

		var TrackingCode = avgReg.ReadRegistryKey(avgReg._WIN_REG_ROOT.LOCAL_MACHINE, avgReg._REG_USER_CONFIGURATION_PATH, "TrackingCode"),
			guardParams = {
				AdditionalInfoXML: "",  //  this.generateAdditionalInfo({"TrackingCode": TrackingCode}),
				FeatureToGuard: params.guardID,
				ValueBeforeGuard: encodeURIComponent(params.ValueBeforeGuard),
				Action: params.action
			},
			xhr = new AVGXhr(),
			strGuardParams = "";

		for (var p in this.PARAMS) {
			strGuardParams += p + "=" + this.PARAMS[p] + "&";
		}

		for(var item in guardParams){
			strGuardParams += item + "=" + guardParams[item] + "&";
		}

		/**************************************************************************************************************/
		xhr.send(this.GUARD_STATS_URL + strGuardParams.slice(0, (strGuardParams.length - 1)),
			function (_xhr) {
				/* success */
			});
	}
};

var NSGetFactory = XPCOMUtils.generateNSGetFactory([AVGMozXPCOM]);