/**
 * @author LLeslie
 */
if(Ext.QuickTips)
	Ext.QuickTips.init();
/** @class NP
 *  a static class that contians references to frequently used variables and method
 * in our case, it represents the base class or for a lack of a better word the namespace
 */
var NP = {
	/**
	 * @property AllApplications
	 * @projectDescription an array that stores a list of applications that the users can execute
	 */
	AllApplications: [],
	/**
	 * @property Applications
	 * @projectDescription an array that stores the main applications that the users can execute
	 */
	Applications: [],
	/**
	 * @property AllSubAppIDs
	 * @projectDescription a list of all the sub applications
	 */
	AllSubAppIDs: [6, 7, 8, 9, 11, 12, 13, 14, 16, 18, 20, 21, 22, 23, 24, 25, 26, 27, 33, 34],
	/**
	 * @property MapRunningApps uses the application id as the indexer to derive the class name
	 */
	MapRunningApps: [],
	/**
	 * @property GlobalRunningApps stores all the global applications
	 */
	GlobalRunningApps: [],
	/**
	 * @property ApplicationPool stores a reference to all active apps base on their class name and instanceId
	 */
	//ApplicationPool: [],
	/**
	 * @property RunningApps stores a reference to all the using application base on their class name
	 * @deprecated use RunningObjects
	 */
	RunningApps: [],
	RunningObjects: [],
	/**
	 * @property ErrorMsgs stores a list of all the js errors
	 */
	//ErrorMsgs: [],
	/**
	 * @property FilterCharList stores a list of invalid characters
	 */
	FilterCharList: ['&', '%', ';', ':', ',', ' '],
	/**
	 * @property PendingRequests stores a list of pending ajax request
	 */
	PendingRequests: [],
	/**
	 * @property Months stores a list of months
	 */
	Months: {
		JAN: 0,
		FEB: 1,
		MAR: 2,
		APR: 3,
		MAY: 4,
		JUN: 5,
		JUL: 6,
		AUG: 7,
		SEP: 8,
		OCT: 9,
		NOV: 10,
		DEC: 11
	},
	/**
	 * @property Counter
	 * @projectDescription an auto incremented number that is used to help create unique ids
	 * @deprecated
	 */
	Counter: 1,
	/**
	 * @property TabContainer represents the current application
	 */
	TabContainer: null,
	View: null,
	WelcomeMenu: null,
	Token: "",
	ImpersonateButton: null,
	LoadMask: null,
	HistoryDelimiter: ":",
	/**
	 * @deprecated
	 * @param {Object} obj
	 * @param {Object} obj2
	 */
	Concat: function(obj, obj2){
		return Ext.apply(obj, obj2);
	},
	CreateApplications: function(){
		NP.LaunchApp(NP.CreateApplicationList());
	},
	GetObjectById: function(objectId){
		return NP.RunningObjects[objectId];
	},
	GetRunningObjects: function(){
		return NP.RunningObjects;
	},
	RemoveAllRunningObj: function(){
		try {
			NP.Applications = [];
			NP.SubApplication = [];
			NP.AllApplications = [];
			//NP.ApplicationPool = new Array();
			
			NP.Applications.length = 0;
			NP.AllApplications.length = 0;
			NP.SubApplication.length = 0;
			NP.MapRunningApps.length = 0;
			//NP.ApplicationPool.length = 0;
			
			for (var item in NP.RunningObjects) {
				try {
					var app = NP.RunningObjects[item];
					if (!app || !NP.GlobalRunningApps[app.ClassName]) {
						app = NP.RunningObjects[item];
						
						if (app && app.Dispose) 
							NP.RunningObjects[item].Dispose();
						
						delete NP.RunningObjects[item];
					}
				} 
				catch (ee) {
				}
			}
			try {
				for (app in NP.RunningApps) {
					try {
						delete NP.RunningApps[app];
					} 
					catch (e) {
					};
				}
			} 
			catch (ee) {
			};
			NP.RunningApps.length = 0;
			NP.RunningObjects.length = 0;
		} 
		catch (ex) {
		}
	},
	MessageBox: function(title, msg, isError){
		if(msg && msg.length==0) return;
		
		if (isError) {
			Ext.Msg.show({
				title: title,
				msg: msg,
				modal: false,
				icon: Ext.Msg.ERROR,
				buttons: Ext.Msg.OK
			});
		}
		else 
		{
			Ext.Msg.show({
				title: title,
				msg: msg,
				modal: false,
				icon: Ext.Msg.INFO,
				buttons: Ext.Msg.OK
			});
			//Ext.example.msg(title, msg,true);
		}
			
	},
	StartMainApp: function(){
		//-------------------Set up history management-------------------------------
		Ext.History.init();
		// Needed if you want to handle history for multiple components in the same page.
		// Should be something that won't be in component ids.
		NP.HistoryDelimiter = ':';
		
		// Handle this change event in order to restore the UI to the appropriate history state
		Ext.History.on('change', function(token){
			try {
				if (token) {
					if (NP.IgnoreTabHistory === true) {
						NP.IgnoreTabHistory= false;
						return;
					}
					var parts = token.split(NP.HistoryDelimiter);
					
					var tabPanel = Ext.getCmp(parts[0]);
					var tabId = parts[1];
					
					tabPanel.show();
					tabPanel.setActiveTab(tabId);
				}
				else {
					// This is the initial default state.  Necessary if you navigate starting from the
					// page without any existing history token params and go back to the start state.
					tp.setActiveTab(0);
					tp.getItem(0).setActiveTab(0);
				}
			} 
			catch (e) {
			}
		});
		
		//----------------------------Start Application------------------------------------
		if (!NP.Token) {
			try {
				var param = document.location.search.split("a=");
				NP.Token = param[1];
			} 
			catch (e) {
				NP.Token = ""
			}
		}
		//NP.GlobalRunningApps['NP.WelcomePanel'].Items.Logout.show();	
		NP.GetApplications(NP.CreateApplicationList, NP.FailureCB);
	},
	/**
	 * @deprecated
	 */
	IncrementCounter: function(){
		this.Counter += 1;
		return this.Counter;
	},
	Remove: function(id, array){
		var item = array;
		
		for (var i = 0; i < array.length; i++) {
			if (id == array[i]) {
				item = array.slice(0, i);
				item.concat(array.slice(i + 1, array.length));
				break;
			}
		}
		
		return item;
	},
	CreateTab: function(object, title, height){
		return new Ext.Panel({
			autoWidth: true,
			autoHeight: height ? false : true,
			height: height,
			bodyBorder: false,
			border: false,
			header: false,
			bodyStyle: 'padding-bottom:5px',
			title: title,
			loadMask: true,
			autoScroll: true,
			items: object
		});
	},
	CreateForm: function(items, title, id, showborder, layout, header){
		var form = new Ext.form.FormPanel({
			title: title,
			id: id,
			url: '/broker.asmx/PerformOperationJson',
			header: (header === false ? false : true),
			bodyStyle: 'margin:12px',
			bodyBorder: showborder == "undefined" ? true : showborder,
			autoWidth: true,
			autoHeight: true,
			layout: layout == undefined ? 'form' : layout,
			defaultType: 'textfield',
			enableDragDrop: true,
			defaults: {
				// applied to each contained item
				width: 230,
				msgTarget: 'side'
			},
			items: items
		});
		
		return form;
	},
	CreateTabContainer: function(items, id, tbar){
		var tab = new Ext.TabPanel({
			anchor: '100%',
			id: id,
			activeTab: 0,
			frame: false,
			plain: true,
			defaults: {
				autoHeight: true
			},
			items: items,
			listeners: {
				'tabchange': function(tabPanel, tab){
					// Ignore profile tab since it is a separate tab panel and we're managing history for it also.
					// We'll use its handler instead in that case so we don't get duplicate nav events for sub tabs.
					if (NP.RunningApps["NP.Profile"] && NP.RunningApps["NP.Profile"].Tab.id != tab.id) {
						Ext.History.add(tabPanel.id + NP.HistoryDelimiter + tab.id);
					}
					
					/*if (NP.GlobalRunningApps['NP.BreadCrumb']) {
					 var crumb = NP.GlobalRunningApps['NP.BreadCrumb'];
					 crumb.AddToCrumb(app,true);
					 }*/
				}
			},
			tbar: tbar
		
		});
		
		var panel = new Ext.Panel({
			autoWidth: true,
			autoHeight: true,
			bodyBorder: false,
			border: false,
			header: false,
			frame: false,
			plain: true,
			//bodyBorder: false,
			loadMask: true,
			bodyStyle: 'padding:5px',
			//            autoScroll:true,
			items: [tab]
		});
		
		return panel;
	},
	FireEvent: function(element, event){
		if (document.createEvent) {
			// dispatch for firefox + others
			var evt = document.createEvent("HTMLEvents");
			evt.initEvent(event, true, true); // event type,bubbling,cancelable
			return !element.dispatchEvent(evt);
		}
		else {
			// dispatch for IE
			var evt = document.createEventObject();
			return element.fireEvent('on' + event, evt)
		}
	},
	Mask: function(msg){
		if (NP.LoadMask) 
			delete NP.LoadMask;
		
		NP.LoadMask = new Ext.LoadMask(Ext.getBody(), {
			msg: msg,
			removeMask: true
		});
		NP.LoadMask.show();
	},
	UnMask: function(){
		if (NP.LoadMask) 
			NP.LoadMask.hide();
	},
	
	/**
	 * Create and initialize an applications
	 * @param {Object} appName
	 */
	CreateMainApp: function(appName){
		var app = {};
		try {
			switch (appName.ApplicationID) {
				case "0":
					app = new NP.GreetingPanel();
					break;
				case "1":
					app = new NP.Invoices();
					break;
				case "2":
					app = new NP.Orders();
					break;
				case "3":
					app = new NP.Profile();
					break;
				case "4":
					app = new NP.PocReport();
					break;
				case "5":
					app = new NP.Support();
					if (app.IsEmpty()) {
						try {
							app.Dispose();
							delete app;
						} 
						catch (e) {
						}
					}
					break;
				case "6":
				case "7":
					break;
				case "10":
					/*app = new NP.Iframe({
						DefaultSrc: '/scripts/Osiris/ols.html',
						ClassName: 'NP.Iframe.OLS',
						ID: 'iframeOLS',
						Src: '/scripts/Osiris/authneo.aspx',
						Settings: appName.Settings
					});*/
					app = new NP.OnlineServices({
						Settings: appName.Settings,
						Name: appName.ApplicationName
					});
					
					break;
				case "15":
					//if (appName.Settings) {
					app = new NP.Iframe({
						ClassName: 'NP.Iframe.NeoFunds',
						ID: 'iframeNeoFunds',
						Src: NP.AllApplications[appName.ApplicationID].Settings? '/scripts/NeoFunds/NeoFunds.htm' : '/scripts/NeoFunds/noNeoFunds.htm',
						Height: 515,
						Settings: (appName.Settings || '')
					});
					//}
					break;
				case "17":
					app = new NP.DocumentViewer();
					break;
				case "19":
					app = new NP.Commission();
					break;
				case "28":
					app = new NP.OnlineQuotes({
						Name: appName.ApplicationName
					});
					break;
				case "29":
					app = new NP.Invoices();
					break;
				case "30":
					app = new NP.OnlineServices({
						Settings: appName.Settings,
						Name: appName.ApplicationName
					});
					break;
				case "31":
					app = new NP.RateChange({
						Settings: appName.Settings,
						Name: appName.ApplicationName
					});
					break;
				case "39":
					app = new NP.RateChangeAdmin({
						Settings: appName.Settings,
						Name: appName.ApplicationName
					});
					tab = app.Tab;
					break;
				case "42":
					app = new NP.Locator({
						Settings: appName.Settings,
						Name: appName.ApplicationName
					});
					break;
				case "43":
					app = new NP.PostageOnCall({
						Settings: appName.Settings,
						Name: appName.ApplicationName
					});
					break;
				case "44":
					app = new NP.Report({
						Settings: appName.Settings,
						Name: appName.ApplicationName
					});
					break;
				case "45":
					app = new NP.Support.RBI({
						Settings: appName.Settings,
						Name: appName.ApplicationName
					});
					break;
				case "46":
					/*app = new NP.Locator({
						Settings: appName.Settings,
						Name: appName.ApplicationName
					});*/
					app = new NP.Support.Find({
						Settings: appName.Settings,
						Name: appName.ApplicationName
					});
					break;
				case "48":
					app = new NP.Support.CategoryManagement({
						Settings: appName.Settings,
						Name: appName.ApplicationName
					});
					break;
				case "50":
					app = new NP.Osiris.Contract({
						Settings: appName.Settings,
						Name: appName.ApplicationName
					});
					break;
				case "51":
					//debugger;
					app = new NP.RCMetrics.AdminReport({
						Settings: appName.Settings,
						Name: appName.ApplicationName
					});
					break;
				case "56":
					debugger;
					app = new NP.Leasing.Invoices({
						Settings: appName.Settings,
						Name: appName.ApplicationName
					});
					break;
				case "59":
					app = new NP.MyUsers({
						Settings: appName.Settings,
						Name: appName.ApplicationName
					});
					break;
				case "61":
					app = new NP.ReturnCenter({
						Settings: appName.Settings,
						Name: appName.ApplicationName
					});
					break;
			}
			
			appName.ClassName = app.ClassName;
			app.History.AppID = appName.ApplicationID;
			
			NP.MapRunningApps[appName.ApplicationID] = app.ClassName;
		} 
		catch (e) {
			//NP.ErrorMsgs[NP.ErrorMsgs.length] = e.message;
			debugger;
			delete app;
			delete tab;
			tab = null;
		}
		return app;
	},
	
	/**
	 * @method ParseApplicationData parse the response object an retrieve the application lists
	 * @param {Object} response
	 * @param {Object} cbFunctionFailure
	 */
	ParseApplicationData: function(response, cbFunctionFailure){
		//removes this transaction from the pending list of tranactions...
		//this list is used to kill all pending requests 
		NP.PendingRequests = NP.Remove(id, NP.PendingRequests);
		var json = NP.Object.prototype.ParseResponseJson(response);
		var data = null;
		
		try {
			NP.RemoveAllRunningObj();
			
			//parse the json string 
			data = Ext.util.JSON.decode(json);
			if (!data) {
				throw {
					message: "JsonReader.read: Json object not found"
				};
			}
			if (typeof data.rows == 'string') {
			
				if (data.rows.indexOf("Session expired: Please Login again") != -1) {
					NP.Token = "";
					var login = new NP.MainLogin();
					login.Show();
					
					return;
				}
				
				if (data.rows.indexOf("Impersonation failed") != -1) {
					if (NP.ImpersonateButton) 
						NP.ImpersonateButton.hide();
					
					NP.IsImpersonatingUser = false;
				}
				throw {
					message: data.rows
				};
			}
			
			//--------------determine if impersonation is turned on----------------	
			if ((typeof data.Impersonate == 'string' && data.Impersonate.toLowerCase() == "true")) {
				NP.IsImpersonatingUser = true;
				if (!NP.RunningApps["NP.Support.FindUser"]) 
					NP.RunningApps["NP.Support.FindUser"] = new NP.Support.FindUser({
						init: function(){}
					});
				
				NP.RunningApps["NP.Support.FindUser"].Impersonate('', NP.RunningApps["NP.Support.FindUser"].SendImRequest, data.User + "'s");
			}
			else 
				NP.IsImpersonatingUser = false;
			//---------------------------------------------------------------------
			//----------------------Welcome Panel-------------------------------
			var wpMsg = '<div>Welcome, ' + data.MUser + '</div>';
			
			wpMsg += (NP.IsImpersonatingUser === true) ? '<div>You are logged in as:</div><div>' + data.User + ((data.Status && data.Status.toLowerCase() == "locked") ? ' [' + data.Status.toLowerCase() + ']</div>' : '</div>') : '';
			
			NP.GlobalRunningApps['NP.WelcomePanel'].UpdateGreeting(wpMsg);
			
			var hdng = Ext.query("*[id$=hdnMsgApp]")[0];
			if (hdng && data.MGroup) 
				hdng.value = data.MGroup
			
			//-----------------------------------------------------------------
			
			//create application list
			for (var i = 0; i < data.rows.length; i++) {
				if (NP.Exists(data.rows[i].ApplicationID, NP.AllSubAppIDs)) 
					NP.SubApplication[NP.SubApplication.length] = data.rows[i].ApplicationID;
				else 
					NP.Applications[NP.Applications.length] = data.rows[i];
				
				data.rows[i].index = i;
				NP.AllApplications[data.rows[i].ApplicationID] = data.rows[i];
			}
		} 
		catch (e) {
			if (cbFunctionFailure) 
				cbFunctionFailure.call(this, {}, null, "read", [], response, "");
			else 
				throw e;
		}
	},
	
	/**
	 * @method CreateApplicationList creates and initialize a set of application base on the application list
	 */
	CreateApplicationList: function(){
		var gr = new NP.GreetingPanel(); //new NP.Iframe({Src:'welcome.html'});
		NP.TabContainer = gr.Tab;
		NP.MapRunningApps[0] = gr.ClassName;
		
		NP.Applications = [{
			ApplicationName: gr.Tab.title,
			ApplicationID: 0
		}].concat(NP.Applications);
		
		if(NP.GlobalRunningApps['NP.LeftNav'])
			NP.GlobalRunningApps['NP.LeftNav'].ClearNav();
			
		var leftNav = new NP.LeftNav();
		
		NP.LaunchApp(gr.Tab);
	},
	
	/**
	 * @method LaunchApp adds a lists of pre- initialized controls to the main container;
	 * and renders the object
	 * @param {Object} items
	 */
	LaunchApp: function(items){
		var a = document.getElementById("divMyNeopostCnts");
		var b = Ext.get('divMyNeopostCnts');
		var c = Ext.getDom('divMyNeopostCnts');
		
		try {
			b.update("");
		} 
		catch (ee) {
			try {
				c.update("");
			} 
			catch (eee) {
			}
		}
		
		if (NP.View) 
			NP.View.destroy();
		
		NP.View = new Ext.Panel({
			activeTab: 0,
			renderTo: 'divMyNeopostCnts',
			frame: false,
			border: false,
			plain: true,
			width: 795,
			region: 'center',
			defaults: {
				height: 720
			},
			items: [NP.TabContainer || items]// NP.TabContainer]
		});
		
		NP.View.render();
		
		NP.View.el.highlight("eeeeee", {
			attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
			easing: 'easeIn',
			duration: 1
		});
		
		NP.View.show();
		
		//NP.History.StartLastApp();
	},
	GetApplications: function(cbFunction, cbFunctionFailure){
		NP.Mask("Loading Applications...");
		var obj = new NP.Object();
		obj.SendTextRequest({
			token: NP.Token,
			settings: "{\"isToken\":\"false\",\"isXml\":\"true\",\"xAction\":\"38\",\"ActionGroup\":\"3\"}",
			paramList: ["null"]
		}, function(response){
		
			NP.ParseApplicationData(response, cbFunctionFailure);
			
			cbFunction.call(this);
			
			//NP.ErrorMsgs = [];
			NP.UnMask();
		});
	},
	
	NewWindow: function(param, width, height, file, name){
		var win = window.open(file + '?' + param, name, 'width=' + width + ',height=' + height + ',toolbar=no,scrollbars=yes');
	},
	SuccessCB: function(dataStore, data, param){
	},
	FailureCB: function(DataProxy, type, action, options, response, arg){
		var showMsg = true;
		//
		//var msg='Unable to '+action+' your order data at this time: Please try again later.';
		var msg = 'Unable to process your request at this time: Please try again later.';
		if (response.status == 200) {
			var json = response.responseText.substring(response.responseText.indexOf('/">', 0) + 3, response.responseText.indexOf('</anyType>', 0));
			var o = null;
			try {
				o = Ext.util.JSON.decode(json);
				if (!o) {
					throw {
						message: "JsonReader.read: Json object not found"
					};
				}
				else 
					(o.success == false || (typeof o.success == 'string' && o.success.toLowerCase() == "false"))
				
				if (o.rows instanceof Array) 
					return;
				msg = o.rows;
			} 
			catch (e) {
			}
			
			if (msg == "{}" || msg == "" || msg == undefined) {
				showMsg = false;
			}
		}
		if (showMsg) 
			NP.MessageBox('Neopost Inc. Error Message', msg, true);
	},
	/**
	 * Notification service that pops out a window with a message
	 * @param {Object} msg represents the  message to display to the user
	 * @param {Object} pName represents the property name that stores the value
	 * @param {Object} title - the title of the window
	 * @param {Object} cb - the function that is called after the button click
	 * @param {Object} scope
	 * @param {Object} animEl - animate from that control
	 * @param {Object} checkboxCB - the method that is called if the checkbox is checked
	 * @param {Object} buttonType - represents the type of button to display; valid entries are
	 * @param {Object} checkboxDes - respresents the display beside the checkbox. NOTE a default description is displayed if none is not provided
	 */
	Notify: function(msg, pName, title, cb, scope, animEl, checkboxCB, buttonType, checkboxDes){
		scope = scope || this;
		if (!this.History.AppID || this.History.AppID == '') 
			return;
		
		if (!this.Items.UserOptions[pName] || this.Items.UserOptions[pName] == 'false') {
			msg = msg || '';
			NP.Notify.Counter = NP.Notify.Counter || 1;
			
			var chkName = 'chk_' + pName.replace(/' ',/g, '_') + (NP.Notify.Counter++) + '_Msg';
			var des = checkboxDes || 'Do not display this message again';
			
			msg += '<br/><br/><div class="x-form-check-wrap"><INPUT id="' + chkName + '" class=" x-form-checkbox x-form-field" type=checkbox name="' + chkName + '" autocomplete="off" ><LABEL  class=x-form-cb-label for="' + chkName + '">' + des + '</LABEL></div>';
			
			Ext.Msg.show({
				title: title,
				msg: msg,
				closeAction: 'close',
				autoDestroy: true,
				autoHeight: true,
				buttons: buttonType || Ext.Msg.OK,
				scope: scope,
				animEl: animEl,
				fn: function(status){
					var el = Ext.get(chkName);
					
					if (el.dom.checked == true) {
						this.Items.UserOptions[pName] = true;
						if (checkboxCB) 
							checkboxCB.call(this, status);
						
						this.SendTextRequest({
							token: NP.Token,
							settings: "{\"isToken\":\"false\",\"isXml\":\"true\",\"xAction\":\"100\",\"ActionGroup\":\"" + this.History.AppID + "\"}",
							paramList: [pName, true]
						});
					}
					
					if (cb) 
						cb.call(this, status);
				},
				icon: Ext.MessageBox.QUESTION
			});
		}
		else 
			if (cb) 
				cb.call(scope);
	},
	IsSupport: function () {
		
		/* !!! remove after adding IE9 support to the ExtJS */
		var ieVer = /msie (\d+)/i.exec(navigator.userAgent);
		ieVer = ieVer ? parseInt(ieVer[1], 10) : 0;

		if(Ext.isIE && ieVer < 7) {
			var pName = 'SupportedBrowser';
			var msg = 'Your Web browser (Internet Explorer 6) is no longer supported by myNeopost. While most features will still work, we cannot guarantee that all will. Please upgrade to a modern browser to insure the best possible myNeopost experience.';
			var title = 'Browser not supported';
			var cb = undefined, animEl = undefined;
			var checkboxCB = function(obj, status) {

			}
			var scope = new NP.Object({
				Url: '/broker.asmx/PermanentCookie',
				History : new NP.History({
					AppID : 3
				}),
				GetSupported : function() {
					var cookie = this.History.Cookie;
					return cookie.GetCookie(pName);
				},
				Init : function() {

					this.Items = this.Items || {};
					this.Items.UserOptions = {};
					this.Items.UserOptions[pName] = this.GetSupported();
				}
			});
			NP.Notify.call(scope, msg, pName, title, cb, scope, animEl, checkboxCB);
		}
	}
};

/* base objects */
/**
 * @constructor NP.Indexer
 * creates an instance of NP.Indexer
 * @classDescription
 * this class is typically used with NP.Exists; if the object exists within the array
 * that is passsed to NP.Exists, then the location of the object is stored 
 * within this object.  
 * 
 * The indexer class is used in conjunction with NP.Exists to store the location of an
 * object within a given array... that information can be used later on to
 * merge or create an array that is order base on the index of each given object
 */
NP.Indexer = function(){
	/**
	 * list of components to add to a container
	 */
	this.Items = [];
	
	/**
	 * @deprecated
	 * @property index
	 * stores the index of the object within a specific array
	 */
	this.index=-1;
	
	/**
	 * @deprecated
	 * @property cmp
	 * stores a reference of the object
	 */
	this.cmp=null;
	/**
	 * @property smallestIndex
	 * @deprecated
	 * this value is set after the add method is called
	 *  and will be used to help merge two arrays : see MergeArray
	 *  NOTE: the smallest index is determine by comparing the two NP.Indexer
	 */
	this.smallestIndex=-1;
	/**
	 * @deprecated
	 * adds this.cmp along with the other object to the array base on their respective indeces
	 * @param items
	 * @param objIndexer
	 */
	this.Add = function(items, objIndexer){
		var tmpItems = [];
		if(objIndexer.index>this.index)
		{
			items = this.AddCmp(items,tmpItems);
			items = objIndexer.AddCmp(items,tmpItems);
			this.smallestIndex=this.index;
			
		}
		else
		{
			items = objIndexer.AddCmp(items,tmpItems);
			items = this.AddCmp(items,tmpItems);
			this.smallestIndex=objIndexer.index;
		}
		return tmpItems;
	}
	
	/**
	 * @deprecated
	 * adds the component to the array if the componenet is not null or its property index is not -1
	 * @param items an array of components
	 * @param tmpItems an array that will store a copy of the component
	 */
	this.AddCmp = function(items,tmpItems){
		if (this.cmp && this.index != -1) {
			items.push(this.cmp);
			
			if(tmpItems)
				tmpItems.push(this.cmp);
		}
		else 
			delete this.cmp;
		return items;
	}
	
	/**
	 * @deprecated
	 * Merge two arrays of components base on their smallest index
	 * @param items array of components
	 * @param items2 array of components
	 * @param sIndex1 smallest index within items
	 * @param sIndex2 smallest index within items2
	 * 
	 */
	this.MergeArray= function(items, items2, sIndex1,sIndex2){
		var tmpItems= [];
		if(sIndex1 > sIndex2){
			tmpItems= items2.concat(items);
		}
		else
			tmpItems= items.concat(items2);
			
		return tmpItems;
	}

	/**
	 * 
	 * @param {Object} app
	 */
	this.MergeSort = function(app){
		app.Tab.Index= app.index;
		var added=false;
			
		for(var i=0; i< this.Items.length; i++)
		{
			if(this.Items[i].Index < app.index)
				continue;
			else
			{
				//greater than or equal to...add the component to before this control
			  	this.Items.splice(i,0,app.Tab);
				added= true;
				break;
			}
		}
		
		if (!added) {
			this.Items.push(app.Tab);
			return;
		}
	}

};

/**
 * This class allows a user to get or create a cookie
 * @param {Object} cookie_name
 */
NP.Cookie = function() {
    /**
    * get a cookie by its cookie name. if the cookie was not found then a null value is return.
    * @param {Object} cookie_name
    */
    this.GetCookie = function(cookie_name) {
		var result =Ext.util.Cookies.get(cookie_name);
		
		return result;
    };

    /**
    * creates a new cookie and add it to the cookie container.
    * NOTE: a cookie needs a cookie name to create a new cookie
    * @param {Object} name
    * @param {Object} value
    */
    this.SetCookie = function(name, value) {
       Ext.util.Cookies.set(name, value);
    };
    /**
    * @method GetLocation: construct a href string
    * @param {Object} navPage
    */
    this.GetLocation = function(navPage) {
        var location = document.location.href.toLowerCase().replace("login", "index");

        if (location.indexOf("index") == -1)
            location += "cindex.htm";
        return location;
    }
	
	this.DeleteCookie = function(cookie_name){
		Ext.util.Cookies.clear(cookie_name);
	}
}

/**
 * @constructor MainMenu
 * @classDescription creates the main menu bar
 * 
 */
NP.MainMenu= function(WebControl, param){
	/**
	 * @property Toolbar
	 * @projectDescription tool bar 
	 */
    this.Toolbar = null;
	/**
	 * @property PrintMenu 
	 * @projectDescription print menu item: prints the grid control
	 */
    this.PrintMenu = null;
	/**
	 * @property ExportItem
	 * @projectDescription exports the grid control
	 */
	this.ExportItem =null;
	/**
	 * @property Parent
	 * @projectDescription parent control
	 */
    this.Parent = null;
	this.xGroup =57;
	
	this.ClassName='NP.MainMenu';
	
	this.getParentApp= function(){
		
		var appId = (WebControl.History && WebControl.History.AppID)? WebControl.History.AppID: '';
		var parent = WebControl;
		
		if (!appId) {
			for (; parent = parent.Parent;) {
			
				if (parent.History && parent.History.AppID) {
					appId = parent.History.AppID;
					break;
				}
			}
		}
		
		return appId;
	},
	this.getAppID = function(){
		var appId = WebControl.History.AppID || this.getParentApp();
		
		return appId;
	}
	
    this.Init = function(webcontrol, param){
		
		var printTpl = function(resultTpl, store){
			var items=[];
			
			for(var i=0; i<store.data.items.length; i++)
				items.push(store.data.items[i].data);
			
			return resultTpl.apply(items);
		};
		
        this.PrintMenu = {
            text: 'Printer Friendly',
            iconCls: 'blist',
            WebControl: webcontrol,
            listeners:{
				scope: this,
				render: function(pMenu){
					var obj = new NP.Object();
					var bar  =this.Toolbar;
					var appId = this.getAppID();
					
					if (appId) {
						var menuParam ={
							AppOptions: {
								isToken: "false",
								isXml: "false",
								xAction: "210",
								ActionGroup: appId
							}, 
							token: NP.Token
						}
						
						var params = {
							token: NP.Token,
							settings: Ext.util.JSON.encode({
								isToken: "false",
								isXml: "false",
								xAction: "210",
								ActionGroup: this.xGroup
							}),
							paramList: [Ext.util.JSON.encode(menuParam)]
						};
						
						obj.SendTextRequest(params, function(response){
							var json = this.ParseResponseJson(response);
							var data = Ext.util.JSON.decode(json);
		
							
							if(data.rows.canAccess =='False' || !data.rows.canAccess){
								bar.remove(pMenu);
							}
						});
					}
					else
					{
						bar.remove(pMenu);
					}
				}
			},
            handler: function(sender, event){
				var grid = this.WebControl.Grid
				if(!grid)
					return;
					
				NP.PrintGrid(webcontrol.PrintTpl? printTpl(webcontrol.PrintTpl,webcontrol.Store): Ext.ux.GridPrinter.print(grid,webcontrol));
			}
        };
		
		this.ExportItem = new NP.SplitButton({
            text:'Export to Excel',
			href:"http://"+ document.location.host+"/customers/Export.aspx?t="+NP.Token+param+"&d=a", // "http://www.neopostinc.com/customers/Export.aspx?t="+NP.Token+param+"&d=a",
			linkStyle:'text-decoration:none; color:black',
			applyParamToChild: true,
			target:'_new',
			scope: webcontrol,
			listeners:{
				scope: this,
				render: function(pMenu){
					var obj = new NP.Object();
					var bar  =this.Toolbar;
					var appId = this.getAppID();
					
					if (appId) {
						var menuParam ={
							AppOptions: {
								isToken: "false",
								isXml: "false",
								xAction: "208",
								ActionGroup: appId
							}, 
							token: NP.Token
						}
						
						var params = {
							token: NP.Token,
							settings: Ext.util.JSON.encode({
								isToken: "false",
								isXml: "false",
								xAction: "208",
								ActionGroup: this.xGroup
							}),
							paramList: [Ext.util.JSON.encode(menuParam)]
						};
						
						obj.SendTextRequest(params, function(response){
							var json = this.ParseResponseJson(response);
							var data = Ext.util.JSON.decode(json);
		
							
							if(data.rows.canAccess =='False' || !data.rows.canAccess){
								bar.remove(pMenu);
							}
						});
					}
					else
					{
						bar.remove(pMenu);
					}
				}
			},
			menu: new Ext.menu.Menu({
		        items: [
			        {text: 'Export All', href: "http://"+ document.location.host+"/customers/Export.aspx?t="+NP.Token+param+"&d=a"}, //"http://www.neopostinc.com/customers/Export.aspx?t="+NP.Token+param+"&d=a"},
			        {text: 'Filtered Data', href: "http://"+ document.location.host+"/customers/Export.aspx?t="+NP.Token+param+"&d=f"}//"http://www.neopostinc.com/customers/Export.aspx?t="+NP.Token+param+"&d=f"}
		        ]
		   	})
        });
        
        this.Toolbar = new Ext.Toolbar();
    };
	
	/**
	 * add the print menu item to the menu bar
	 */
    this.AddPrint = function(){
        this.Toolbar.add('->',this.PrintMenu);
    };
	/**
	 * add the export menu item to the menu bar
	 */
    this.AddExport = function(){
        this.Toolbar.add('->',this.ExportItem);
    };
	
	/**
	 * returns the menu bar
	 */
    this.getToolBar = function(){
        return this.Toolbar;
    };
	
	this.Init(WebControl,param);
}

NP.History = function(config){
	config = config || {};
	if(!config.cid)
		config.cid='NP.History';
	/**
	 * @property ClassName
	 * @projectDescription the name of the class. this property can be used to get an instance of this object
	 */
	this.ClassName='NP.History';
	
	Ext.applyIf(this, config);
	
	this.Cookie = new NP.Cookie();
}

NP.History.prototype = {
	CookieNameLA:'NP_lastApp',
	AppID:'',
	SetLastApp: function(){
		if(!this.AppID) return;
		
		var d = new Date();
		d.setDate(d.getDate()+1);
		
		this.Cookie.SetCookie(this.CookieNameLA, this.AppID, d.getYear(), d.getMonth(), d.getDate());
	},
	GetLastRunningApp: function(){
		var cookie = new NP.Cookie();
		var appId = cookie.GetCookie(NP.History.prototype.CookieNameLA);
		delete cookie;
		
		if (!appId) 
			return;
		
		return NP.AllApplications[appId];
	}
};


NP.History.StartLastApp = function(){
	//var app = NP.History.GetLastRunningApp();
	
	//if(!app) return;
	if(!NP.RunningApps['NP.LeftNav']){
		var leftNav = NP.RunningApps['NP.LeftNav'];
		
		//leftNav.StartApp(app);
	}
};



/**
 * The base class for components  
 */
NP.Object = function(config){
	config = config || {};
	var baseUrl = '';
	
	/**
	 * override defaults from decendants
	 */
	Ext.apply(this, config);
	
	Ext.applyIf(this, {
		/**
		 * @property ID
		 * @projectDescription a unique identifier that can be used as a prefix for a control's id
		 */
		ID: Ext.id(),
		/**
		 * @property ClassName
		 * @projectDescription the name of the class. this property can be used to get an instance of this object
		 */
		ClassName: 'NP.Object',
		/**
		 * @property Url
		 * @projectDescription the url that is used to preform ajax request
		 */
		BaseUrl: baseUrl,
		/**
		 * @property Url
		 * @projectDescription the url that is used to preform ajax request
		 */
		Url: baseUrl + '/broker.asmx/PerformOperationJson',
		
		xAction: null,
		xGroup: null,
		/***
		 * @method EmptyFunction returns an empty function
		 */
		EmptyFunction: function(){
		},
		/**
		 * @method UnMask is used to remove the mask that was applied to a specific controls
		 */
		UnMask: function(){
		},
		/**
		 * @method Mask applies a mask to a specific control
		 */
		Mask: function(){
		}
	});
	
	this.InitComponent();
};

Ext.extend(NP.Object,Ext.util.Observable,{
	/**
	 * @method InitComponent
	 * Initializes all the control
	 */
	InitComponent: function(){
		if(this.isInit)
			return;
		/*
		 * Backwards Compatible
		 */	
		if( this.cid && this.cid!=this.ClassName)
			return;
		
		this.InitEvents();
		this.isInit = true;
		
		NP.RunningApps[this.cid || this.ClassName]=this;
		
		if(!this.cid)
			this.cid = this.ClassName;
			
		this.Init();
		
		if(this.ID)
			this.ID =Ext.id();
			
		NP.RunningObjects[this.ID] = this;
	},
	/**
	 * @private
	 * @method Init Initializes all the controls: 
	 * note this function must be implemented by all of its direct descendants 
	 */
	Init: function(){},
	/**
	 * @method InitEvent adds and initializes all the default events
	 */
	InitEvents: function(){
		this.addEvents(
            "sendRequest",
			'jsonRequest',
			"afterRequest",
			'beforeRequest',
			'maskEl',
			'unmaskEl'
        );
		
	},
	
	/**
	 * @property Delay calls the specified function after a certain time as past
	 * @param {Object} funName
	 * @param {Object} delaytime
	 */
	Delay: function(funName,delaytime){
		var t= setTimeout("NP.RunningApps['"+this.ClassName+"']."+funName+";", delaytime ); 
	},
	AbortRequest: function(tranId){
		try {
			Ext.Ajax.abort(tranId);
		}
		catch(e){}
		NP.Remove(tranId, NP.PendingRequests);
	},
    /**
    * @method SendTextRequest sends an ajax request to the server with a few parameters
    * @param {Object} params
    * @param {Object} cbSuccess represents the method that is called if the request is successful (raw data)
    * @param {Object} cbFailure represents the method that is called if the request was unsuccessful
    */
    SendTextRequest: function(params, cbSuccess, cbFailure) {
		this.fireEvent('beforeRequest', params);
		
       var requestId = this.CurrentRequestId = NP.PendingRequests[NP.PendingRequests.length] = id = Ext.Ajax.request({
            url: this.Url,
            timeout: 120000,
            method: 'POST',
            params: params,
            scope: this,
            //scriptTag: true,
            success: function(response, store, param) {
                //removes this transaction from the pending list of tranactions...
                //this list is used to kill all pending requests 
                NP.PendingRequests = NP.Remove(id, NP.PendingRequests);
				
				try {
					this.fireEvent('sendRequest', this, response);
				}
				catch(ee){}
                if (cbSuccess)
                    cbSuccess.call(this, response);
					
				try {
					this.fireEvent('afterRequest', this, response);
				}
				catch(ee){}	
            },
            failure: function(response, proxy) {
                NP.PendingRequests = NP.Remove(id, NP.PendingRequests);
				
                try {
					this.fireEvent('afterRequest', this, response);
				}
				catch(ee){}	
				
                if (cbFailure)
                    cbFailure.call(this, response, proxy);
                else
                    NP.FailureCB.call(this, proxy, 'read', 'response', [], response);
            }
        });
		
		return requestId;
    },

    /**
    * @method SendJsonRequest sends an ajax request to the server with a few parameters
    * @param {Object} params
    * @param {Object} cbSuccess represents the method that is called if the request is successful (json data)
    * @param {Object} cbFailure cbFailure represents the method that is called if the request was unsuccessful
    */
    SendJsonRequest: function(params, cbSuccess, cbFailure){
		return this.SendTextRequest(params, function(response){
			var json = this.ParseResponseJson(response);
			var data = null;
			try {
				data = this.ParseJson(json);
				
				this.fireEvent('jsonRequest', this, data);
				
				if (cbSuccess) 
					cbSuccess.call(this, response, data);
			} 
			catch (e) {
				if (this.suppressErrorMsg === true) 
					return;
				NP.MessageBox('Neopost Inc.', e.message, true);
			}
			this.UnMask();
		}, function(response, proxy){
			this.UnMask();
			if (cbFailure) 
				cbFailure.call(this, response, proxy);
			
			NP.FailureCB.call(this, proxy, 'read', 'response', [], response);
		});
	},
	SendErrorReport: function(msg, xAction, actionGroup,flag){
		var tmp = this.Url;
		this.Url = this.Url = this.BaseUrl + '/broker.asmx/ReportError';
		
		this.SendTextRequest({
			token: NP.Token,
			settings: Ext.util.JSON.encode({
				isToken: "false",
				isXml: "false",
				xAction: xAction,
				ActionGroup: actionGroup
			}),
			opco: 2,
			paramList: [msg,flag]
		});
		this.Url = tmp;
	},
    /**
    * @method ParseResponseText extract the neccessary data from the response object
    * @param {Object} response
    */
    ParseResponseText: function(response) {
        return response.responseText.substring(response.responseText.indexOf('/">', 0) + 3, response.responseText.indexOf('</string>', 0));
    },
    /**
    * @method ParseResponseJson extract the json string from the response object
    * @param {Object} response
    */
    ParseResponseJson: function(response) {
        return response.responseText.substring(response.responseText.indexOf('/">', 0) + 3, response.responseText.indexOf('</anyType>', 0));
    },
    /**
    * @method ParseJson converts a json string into a json object
    * @param {Object} json
    */
    ParseJson: function(json) {
		var data;
		try {
			var data = Ext.util.JSON.decode(json);
		} 
		catch (ee) {
			throw {
				message: json
			};
		}
        if (!data) {
            throw {
                message: "JsonReader.read: Json object not found"
            };
        }

        if (typeof data.rows == 'string' && data.rows.indexOf(" ") != -1) {
            //check to see if the string can be converted to json
            try {
                json = data.rows;
                data = Ext.util.JSON.decode(json);
            }
            catch (e) {
                throw {
                    message: data.rows
                };
            }
        }
        return data;
    },
    CleanUp: function(el) {
        if (!el)
            return;
			
        el.update("");
        el.dom.innerHTML = "";
    }
})

//NP.Object.InstanceID = 1;

/* end of object */
/* a list of extension object */

/** 
 * @constructor NP.Panel()
 * @classDescription 
 * this class represents a container that can host other structures. this class can
 * be used as the base class for all of your controls...
 *  
 *  Events:
 *  	OnAfterLoad  
 *  	OnInit
 */

NP.Panel = function(config){
	/**
	 * @property Tab
	 * The main component that host all the other components
	 *
	 */
	/**
	 * @property Items
	 * a collection of object which typically contains a list of controls
	 */
	/**
	 * @property TopBar
	 * top menu bar
	 */
	Ext.applyIf(this, {
		ClassName: 'NP.Panel',
		/**
		 * a collection of parameters to pass to the webmethod.
		 * Note: the collection is used as the last set of inputs to the webmethod
		 */
		Params: ["null"],
		/**
		 * indicates if the main component as being rendered. in other words:
		 * maintain the loaded state of the Tab control
		 */
		IsDataLoaded: false,
		/**
		 * a list of configurations to apply to the application
		 */
		Settings: '',
		/**
		 * @property Name
		 * the title/name of the application
		 */
		History: new NP.History(),
		/**
		 * the base parameter list that is sent to the server
		 */
		BaseParams: {},
		TabConfig: {}
	});
	
	NP.Panel.superclass.constructor.call(this, config);
};
Ext.extend(NP.Panel, NP.Object, {
	InitEvents: function(){
		NP.Panel.superclass.InitEvents.call(this);
		
		this.addEvents(
            "afterRenderControl",
			'afterInit',
			'afterInitSettings',
			'afterPreferences'
        );
		
		this.on('afterRenderControl',this.onRenderControl);
		this.on('afterInit',this.OnInit);
	},
	onRenderControl: function(){
		this.History.SetLastApp();
		
		if (!this.IsDataLoaded) {
			this.IsDataLoaded = true;
			this.InitializeSettings();
		}
	},
		/**
	 * @method IsEmpty
	 * returns true if the Items array contains any object; otherwise false.
	 */
    IsEmpty: function(){
        if(!this.Items)
            return false;
            
        return (this.Items.length <= 0);
    },
	
	/**
	 * @method StripComma
	 * removes the last character if that character is a comma
	 * @param {Object} param
	 * @deprecated use Ext.util.JSON.encode
	 */
    StripComma: function(param){
        if(param.charAt(param.length-1)==',')
            return param.substring(0,param.length-1);
		else if(param.charAt(param.length-1)==' ')
			return this.StripComma(param.substring(0,param.length-1));
        else
            return param;
    },
	
	/**
	 * @method UnMaskChildControls
	 * makes a call to all it's children Unmask function
	 */
    UnMaskChildControls: function(){
        for (var i in this.Items) {
			try {
				this.Items[i].UnMask();
			} 
			catch (e) {
			}
		}
    },
	
	/**
	 * @method TriggerEnterClick
	 * a callback method; when assigned to an element will 
	 * triggers the click event for its click-control after the enter key is pressed 
	 * @param {Object} sender
	 * @param {Object} e
	 */
    TriggerEnterClick: function(sender, e,a){
        try
        {
			var tmp = e.getKey? sender : this;
			var ev = (e.getKey? e: sender);
			
            if(ev.getKey() == 13){ //if generated character code is equal to ascii 13 (if enter key)
				ev.stopPropagation();
	    		ev.stopEvent();
				
				if (tmp.onTriggerClick) 
					tmp.onTriggerClick(ev, tmp);
				else 
					if (typeof tmp.ControlToClick == 'string') {
					
						var tb = document.getElementById(tmp.ControlToClick) || document.getElementsByName(tmp.ControlToClick)[0];
						try {
							if (tb) 
								((tb.tagName.toLowerCase() == "button" || tb.tagName.toLowerCase() == "input") ? tb : tb.getElementsByTagName("BUTTON")[0]).click();
						} 
						catch (ee) {
						}
					}
					else {
						if (tmp.ControlToClick.dom) 
							tmp.ControlToClick.dom.click();
						else 
							tmp.ControlToClick.click();
					}
            }
        }
        catch(e){}
    },
	
	/**
	 * @method TriggerEnterTab
	 * a callback method; when assigned to an element will 
	 * triggers the focus event for its click-control after the enter key is pressed 
	 * @param {Object} sender
	 * @param {Object} e
	 */
	TriggerEnterTab: function(sender, e){
		try
        {
            if(e.getKey() == 13){ //if generated character code is equal to ascii 13 (if enter key)
				e.stopPropagation();
				e.stopEvent();
				
				if (typeof sender.ControlToClick == 'string') {
					var tb = document.getElementById(sender.ControlToClick);
					try {
						if (tb) 
							tb.getElementsByTagName("INPUT")[0].focus();
					} 
					catch (ee) {
					}
				}
				else
				{
					sender.ControlToClick.focus();
				}
            }
        }
        catch(e){}
	},
	
	/**
	 * @method RemoveAll
	 *  removes all element from the Tab control
	 */
    RemoveAll: function(){
        try
        {
			this.CleanUp();
			
            NP.View.doLayout();
			this.Tab.doLayout();
        }
        catch(e){}
    },
	/**
	 * @method Dispose
	 * removes all element from the tab control and release all its resources
	 */
    Dispose: function(){
        try
        {    
            this.CleanUp();
            try{NP.TabContainer.remove(this.Tab);}
			catch(e){};
			
			try{this.Tab.destroy();}
            catch(e){}
			
            this.Tab=null;
        }
        catch(e) { }
		if(NP.View)
        	NP.View.doLayout();
    },
	
	/**
	 * @method Init
	 * Initialize all the controls within the object as well as 
	 * trigger a method called GetData to retrieve the controls data 
	 * after the control is rendered to the screen. (Note: GetData is only called once)
	 * note this function must be implemented by all of its direct descendants 
	 */
	Init: function(){
		NP.Panel.superclass.Init.call(this);
		
        this.CreateTab();
        
        if (this.Tab) {
			this.Tab.WebControl = this;
			
			this.Tab.on('afterrender', function(container){
				this.WebControl.fireEvent('afterRenderControl',this);
			});
		}
		this.CreateMisc();
		this.fireEvent('afterInit', this);
    },
	/**
	 * @method InitializeSettings
	 * loads all of the application settings
	 */
	InitializeSettings: function(){
		if (this.IsInitialize === true) 
			return;
		this.IsInitialize = true;
		
		if (!this.History.AppID || this.IgnoreSettings === true) {
			this.GetData();
			this.OnAfterLoad(this);
			
			return;
		}
		
		var params = {
			token: NP.Token,
			settings: "{\"isToken\":\"false\",\"isXml\":\"true\",\"xAction\":\"106\",\"ActionGroup\":\"" + this.History.AppID + "\"}",
			paramList: ['null']
		};
		
		this.SendTextRequest(params, function(response, data){
			try {
				this.Items.InitConfig = {
					Text: this.ParseResponseJson(response)
				};
			} 
			catch (ee) {
			}
			
			this.GetData();
			
			this.OnAfterLoad(this);
		});
	},
	
	/**
	 * @method GetData
	 * is called after the initialize settings 
	 * if a call is made to the Tab control's render method and you would like 
	 * the GetData method to be triggered, then simple set IsDataLoaded to false 
	 * before invoking the call
	 */
    GetData: function(){
		this.fireEvent('afterInitSettings', this);
	},
	
	/**
	 * @method CreateTab creates the main control
	 */
	CreateTab: function(){
		this.Items=[];
		return this.OnCreateTabItems();
	},
	/**
	 * @method CreateMisc: can be used to create other controls such as a popout window
	 */
	CreateMisc: function(){},
	
	/**
	 * @method OnInit
	 * This function can be used to execute code when the Init method is called 
	 */
	OnInit: function(){},
	
	/**
	 * @method OnAfterLoad
	 * Triggered after the Tab control is loaded 
	 * @param {Object} WebControl
	 */
	OnAfterLoad: function(WebControl){},
	
	/**
	 * @method Creates a basic top menu bar that contains a export and print functionality
	 */
	CreateTopMenu: function(){},
	
	/**
	 * @method Creates a basic context menu and apply it to the specificed control
	 */
	CreateContextMenu: function(menu, control){
		menu.Parent = this;
		control.ContextMenu = menu
				
		control.on('contextmenu', function(eventObj, elRef){
			var ev = eventObj.stopEvent? eventObj: elRef;
			
			ev.stopEvent();

			var xy = ev.getXY();
			this.ContextMenu.showAt(xy);
		});
	},
	/**
	 * @method Creates the controls that will be added to the tab control
	 */
	OnCreateTabItems: function(items, buttons){},
	/**
	 * set the height of the tab control
	 * @param {Object} height
	 */
	SetHeight: function(height){
		try {
			this.Tab.setHeight(height);
		}
		catch(e){}		
	},
	/**
	 * set the width of the tab control
	 * @param {Object} width
	 */
	SetWidth: function(width){
		try {
			this.Tab.setWidth(width);
		}
		catch(e){}
	},
	/**
	 * @method Hide: hides the popout window
	 */
	Hide: function(){
		if(this.Tab)
			this.Tab.hide();
	},
	Show: function(){
		if(!this.Tab)
			return;
		
		this.Tab.show();
		if (this.Tab.el) {
			this.Tab.el.fadeIn({
				endOpacity: .99,
				duration: 2
			});
		}
	},
	/**
	 * @property Mask
	 * @projectDescription adds a mask to the control
	 */
	Mask: function(msg){
		if (this.Tab && this.Tab.el) {
			if (msg) 
				this.Tab.el.mask(msg, 'x-mask-loading')
			else 
				this.Tab.el.mask();
		}
	},
	/**
	 * @property UnMask
	 * @projectDescription remove the mask that was applied to the control
	 */
	UnMask: function(){
		if(this.Tab && this.Tab.el)
			this.Tab.el.unmask();
	},
	/**
	 * Addes the users preferences to the the list of Items
	 * @param {Object} data
	 */
	ParseUserPreferences: function(data){
		this.Items.UserOptions = this.Items.UserOptions || {};
		
		if (data.results > 0) {
			for (var item in data) {
				if (typeof(data[item]) == 'string' || typeof(data[item]) == 'function') 
					continue;
				
				for (var i in data[item]) {
					if (typeof(data[item][i]) == 'string' || typeof(data[item][i]) == 'function') 
						continue;
					
					this.Items.UserOptions[data[item][i].PropertyName] = data[item][i].PropertyValue;
				}
			}
		}
	},
	LoadPreferences: function(){
		this.Mask();
		var settings = {
			isToken: "false",
			isXml: "false",
			xAction: "99",
			ActionGroup: this.History.AppID
		};
		
		this.SendJsonRequest({
	        token:NP.Token,
	        settings: Ext.util.JSON.encode(settings), 
	        paramList: ["null"]
	    },
		function(response,data){
			this.ParseUserPreferences(data);
			this.fireEvent('afterPreferences',this.Items.UserOptions);
				
			delete data;
			delete response;
		});
	}
});

/**
 * @constructor PopoutWindow
 * @classDescription a pop out window control
 * @param {Object} config
 */
NP.PopoutWindow = function(config){
	Ext.applyIf(this, {
		ClassName: 'NP.PopoutWindow',
		ModalWindow: false,
		
		/**
		 * @property AnimateTarget
		 * @projectDescription target control to animate from
		 */
		AnimateTarget: Ext.getBody().id,
		/**
		 * represents the width of the pop out window
		 */
		Width: 400,
		/**
		 * represents the height of the pop out window
		 */
		Height: 500,
		
		/**
		 * indicate if the control should automatically determine its height
		 */
		AutoHeight: true,
		/**
		 * represent the text that will be shown when the mask is active
		 */
		MaskText: "Loading..."
	});
	
	NP.PopoutWindow.superclass.constructor.call(this, config);
}

Ext.extend(NP.PopoutWindow, NP.Panel,{
	/**
	 * @method CreateWindow: create a pop out window container
	 */
	CreateWindow: function(){
		if (this.Tab) {
			this.win = new Ext.Window({
				layout: 'form',
				width: this.Width,
				autoHeight: this.AutoHeight,
				height: this.Height,
				modal: this.ModalWindow,
				animateTarget: this.AnimateTarget,
				disabled: false,
				closeAction: 'hide',
				items: this.Tab
			});
		}
	},
	
	/**
	 * @method CreateMisc
	 * @see NP.Panel/CreateMisc
	 */
	CreateMisc: function(){
		NP.PopoutWindow.superclass.CreateMisc.call(this);
		this.CreateWindow();
	},
	/**
	 * @method Hide: hides the popout window
	 */
	Hide: function(){
		NP.PopoutWindow.superclass.Hide.call(this);
		
		if(this.win)
			this.win.hide();
	},
	
	/**
	 * @method Show: shows the popout window
	 */
	Show: function(){
		NP.PopoutWindow.superclass.Show.call(this);
		
		if(this.win)
			this.win.show();
	},
	
	/**
	 * @method SetWindow
	 * @param {Object} w
	 */
	SetWindow: function(w){
		this.win=w;
	},
	
	/**
	 * @method SetDisabled: enable or disable the popout window
	 * @param {Object} status
	 */
	SetDisabled: function(status){
		if(this.win)
			this.win.setDisabled(status);
	},
	
	/**
	 * @method SetTitle
	 * @param {Object} title
	 */
	SetTitle: function (title){
		if(this.win)
			this.win.setTitle(title);
	},
	/**
	 * @method SetModal
	 * @param {Object} status
	 */
	SetModal: function(status){
		if(this.win)
			this.win.modal=status;
	},
	
	Close: function(){
		this.Hide();
		this.win.close();
		this.Dispose();
	}
});

/**
 * @constructor Tree
 * @classDescription creates a tree control
 * @param {Object} args
 */
NP.Tree = function(args){
	/**
	 * @property Root
	 * @projectDescription represents the root node within the tree
	 */
	/**
	 * @property Loader
	 * @projectDescription the control that retrieve the nodes from the server
	 */
	Ext.applyIf(this, {
		RootCategory: 'docs',
		/**
		 * @see NP.Panel/ClassName
		 */
		ClassName: 'NP.Tree',
		/**
		 * @property RootName
		 * @projectDescription the name of the root node
		 */
		RootName: 'Documents',
		/**
		 * @property Region
		 * @projectDescription represent the position of the control relative to its siblings
		 */
		Region: 'west',
		/**
		 * @property Width
		 * @param {Object} config
		 */
		Width: 200
	});
	
	NP.Tree.superclass.constructor.call(this, args);
};

Ext.extend(NP.Tree, NP.Panel, {
	/**
	 * @method Creates the controls that will be added to the tab control
	 */
	OnCreateTabItems: function(items, buttons){
		this.CreateLoader();
		this.Root = new Ext.tree.AsyncTreeNode({
			nodeType: 'async',
            text: this.RootName,
            draggable: false,
            id: this.RootCategory,
			category: this.RootCategory,
			expanded: false
		});
	},
	
	/**
	 * @see NP.Panel/CreateTab
	 */
	CreateTab: function(){
		NP.Tree.superclass.CreateTab.call(this);
		this.TabConfig = this.TabConfig || {};
		
		this.Tab = new Ext.tree.TreePanel(Ext.applyIf({
			useArrows: true,
			region: this.Region,
			autoScroll: true,
			animate: true,
			enableDD: false,
			width: this.Width,
			containerScroll: true,
			border: true,
			loader: this.Loader,
			WebControl: this,
			root: this.Root
		}, this.TabConfig));
		
		this.Tab.on('click', function(node, e){
			if (this.WebControl.HandleNodeClick) 
				this.WebControl.HandleNodeClick.call(this.WebControl, node, e);
		});
	},
	/**
	 * @method CreateLoader create an assign the appropriate events to the Loader control
	 */
	CreateLoader: function(){
		//triggers an ajax request that retrieves a list of nodes base on the specified params
		this.Loader = new NP.TreeLoader({
			dataUrl: '/broker.asmx/PerformOperationJson',
			WebControl: this,
			baseParams: this.BaseParams
		});

		var cbBeforeload = this.HandleBeforeLoad;
		var cbAfterload = this.HandleAfterLoad;
		
		this.Loader.on('beforeload', function(treeLoader, node){
			this.baseParams.paramList = [node.attributes.category.replace("&amp;","&")]//.concat(this.WebControl.Params);
			if (cbBeforeload) 
				cbBeforeload.call(this.WebControl, this, node);
		});
		this.Loader.on('load', function(loader, node, response, parseData){
			if (cbAfterload) 
				cbAfterload.call(this.WebControl, loader, node, response, parseData);
		});
		
		if(this.ProcessDataSet)
			this.Loader.ProcessDataSet= this.ProcessDataSet;
	},
	/**
	 * @method HandleBeforeLoad is called before the load event is triggered on Loader
	 */
	HandleBeforeLoad: function(){},
	/**
	 * @method HandleAfterLoad is called after the Loader retrieves a collection of nodes 
	 * @param {Object} loader
	 * @param {Object} node
	 * @param {Object} response
	 */
	HandleAfterLoad: function(loader, node, response){},
	/**
	 * @method HandleNodeClick node click event
	 * @param {Object} node
	 * @param {Object} e
	 */
	HandleNodeClick: function(node, e){},
	GetData: function(items, buttons){
		this.Root.expand();
	}
});

NP.GreetingPanel = Ext.extend(NP.Panel, {
	ClassName: 'NP.GreetingPanel',
	/**
	 * @see NP.Panel/CreateTab
	 */
	CreateTab: function(){
		NP.GreetingPanel.superclass.CreateTab.call(this);
		var hdn = Ext.query("*[id$=hdnMsgApp]")[0];
		var value = hdn.value;
		
		NP.Data.Gval=value;
		
		value = value.length >0? value.toLowerCase() : 'welcome';
		
		var url = (NP_Home? NP_Home.home: '/customers/' + value + '.aspx');
		
		this.Tab = new Ext.Panel({
			bodyBorder: false,
			border: false,
			header:false,
			anchor:'98%',
			autoHeight: true,
			//height: 720,
			title:'Overview',
			autoLoad: {
				url: url,
				text: "Loading",
				scrits: false
			}
		});
	}
});

NP.WelcomePanel = Ext.extend(NP.Panel, {
	ClassName: 'NP.WelcomePanel',
	/**
	 * @property User
	 */
	User:'user',
	Init: function(){
		NP.GlobalRunningApps[this.ClassName] = this;
		NP.WelcomePanel.superclass.Init.call(this);
	},
	/**
    * @see NP.Panel/CreateTab
    */
    CreateTab: function(){
		NP.WelcomePanel.superclass.CreateTab.call(this);
		
		var div = Ext.query('.leftlogin');
		div = div.length ==0 ?  Ext.query('.homelogin'): div;
		
		if (div.length > 0) {
			div = div[0];
			
			this.Items.Message = Ext.get('wplbGreeting');
			
			if(!this.Items.Message)
				this.Items.Message = Ext.get(Ext.DomHelper.append(div, {tag: 'div', id:'wplbGreeting'}));
				
			this.el = Ext.DomHelper.append(div, {tag: 'div', style:'float:left;'});
			this.rendered = false;
			this.div = Ext.get(div);
			
			if (this.Items.Message.dom.innerHTML.indexOf('Welcome') != -1) {
				this.initialWelcome = this.Items.Message.dom.innerHTML;
				
				this.CreateButton();
				this.Resize();
			}
			else
			{
				Ext.get(this.el).remove();
				this.Items.Message.dom.style.display= 'none';
			}
		}
	},
	Resize: function(){
		try {
			var padding = 10;
			var h =Ext.get(this.el).getComputedHeight() + this.Items.Message.getComputedHeight();
			this.div.dom.style.height =h+'px';
		}
		catch(ee){}
	},
	CreateButton: function(){
		var counter = 0;
		var cbLogout = function(sender, e){
			try {
				sender.stopPropagation();
				sender.stopEvent();
			} 
			catch (ee) {
			}
			if (counter > 0) 
				return;
			
			counter = 1;
			
			var url = '';
			try {
				url = ssoLogout || '';
			} 
			catch (ee) {
				url = '';
			}
			
			var obj = new NP.Object({
				Url: '/broker.asmx/Logout'
			});
			obj.SendTextRequest({
				token: NP.Token
			}, function(response){
				var cookie = new NP.Cookie();
				var date = new Date();
				cookie.SetCookie("NPUserProfile1", "", date.getFullYear(), date.getMonth(), date.getDay() - 1);
				
				document.location.href = url;
			});
			NP.Token = "";
		};
		
		this.Items.Logout = Ext.get(Ext.DomHelper.append(this.el,{
			tag: 'button',
			value:'Logout',
			html:'Logout'
		}));
		
		this.Items.Logout.on('click', cbLogout);
		
		try {
			//this.Items.Logout.render(this.el);
			
			this.rendered = true;
		} 
		catch (ee) {
		};
	},
	/**
	 * @method UpdateGreeting displays a message on the welcome menu
	 * @param {Object} msg
	 */
	UpdateGreeting: function(msg){
		if(this.Items.Message)
			this.Items.Message.update(msg);
		if(!this.rendered)
			this.CreateButton();
	}
});

NP.WebControl = function(config){
	/**
	 * @property MenuBar
	 * @projectDescription menu bar that is typically attached to the grid object
	 */
	/**
	 * @property Store
	 * @projectDescription a collection of items -> DataSet
	 */
	/**
	 * @property Columns
	 * @projectDescription a list of columns that is applied to the Store
	 */
	/**
	 * @property ColumnHeader
	 * @projectDescription a list of columns and their respective fitlers to apply to
	 * Store before displaying the items within the grid
	 */
	/**
	 * @property ColumnModel
	 * @projectDescription stores the columns and general settings to apply to the data store and
	 * grid object
	 */
	/**
	 * @property IDProperty
	 */
	Ext.applyIf(this, {
		ClassName: 'NP.WebControl',
		/**
		 * @property Grid
		 * @projectDescription represents a grid control
		 */
		Grid: [],
		
		/**
		 * @property AutoExpandColumn
		 * @projectDescription indicate which column should be automatically expanded when the grid
		 * is populated
		 */
		AutoExpandColumn: '',
		
		/**
		 * @property EnableRemoteSorting
		 * Enable remote sorting of the data store
		 */
		EnableRemoteSorting: false,
		/**
		 * @property EnableRemoteGrouping
		 * Enable remote grouping of the data store
		 */
		EnableRemoteGrouping: false,
		/**
		 * @property EnableClientSort
		 * @projectDescription indicate whether the Store should be sorted
		 */
		EnableClientSort: true,
		/**
		 * @property EnableIDProperty
		 * @projectDescription indicate if the specified column (sorting column) or IDProperty should be used as the id field
		 * if false;  an auto- generated numeric value will be used
		 */
		EnableIDProperty: true,
		
		/**
		 * @property LoadStore
		 * @projectDescription if true loads the data store whenever the function LoadData is executed; otherwise false.
		 */
		LoadStore: true,
		GridConfig: {}
	});
	
	NP.WebControl.superclass.constructor.call(this, config);
};

Ext.extend(NP.WebControl, NP.Panel, {
	/**
	 * @method LoadData
	 * config and apply listeners to the data store
	 * @param {Object} param
	 * @param {Object} beforeLoad
	 * @param {Object} afterLoad
	 */
	LoadData: function(param, beforeLoad, afterLoad){
		this.Store.WebControl = this;
		this.LoadCustomStore.call(this.Store, param, beforeLoad, afterLoad);
	},
	LoadCustomStore: function(param, beforeLoad, afterLoad){
		this.NPBeforeLoad = beforeLoad;//a callback method 
		this.NPAfterLoad = afterLoad;//a callback method 
		this.baseParams = param;
		
		this.Settings = param.settings;
		if (this.Pager) {
			this.Pager.on('beforechange', function(control, params, a){
				this.Start = params.start;
			});
		}
		this.on('beforeload', function(store){
			if (store.NPBeforeLoad) 
				store.NPBeforeLoad(this.WebControl);
			
			if (store.Pager) {
				var start = (store.Pager.Start) ? store.Pager.Start : 0;
				
				var settings = store.Settings.substring(0, store.Settings.length - 1);
				settings += ",\"Start\":" + start + ",\"Limit\":" + store.Pager.pageSize + "}";
				store.baseParams.settings = settings;
				
				if (store.WebControl.MenuBar) {
					store.WebControl.MenuBar.ExportItem.baseParams.Start = start;
					store.WebControl.MenuBar.ExportItem.baseParams.Limit = store.Pager.pageSize;
					
					store.WebControl.MenuBar.ExportItem.setParams(store.WebControl.Params);
				}
			}
			store.baseParams.paramList = this.WebControl.Params;
		});
		
		this.on('exception', this.WebControl.CBException);
		
		this.on('load', function(dataStore, data, param){
			if (this.NPAfterLoad) 
				this.NPAfterLoad(this.WebControl, this, data);
			
			this.WebControl.UnMask();
			NP.SuccessCB(dataStore, data, param);
		});
		
		this.on('afterload', function(dataStore, data, param){
		});
		
		if (this.WebControl.LoadStore) 
			this.load();
		
		if (this.WebControl.OnLoadData) 
			this.WebControl.OnLoadData();
	},
	/**
	 * @method Creates the controls that will be added to the tab control
	 */
	OnCreateTabItems: function(items, buttons){
		this.CreateGrid();
	},
	/**
	 * @method CreateGrid
	 */
    CreateGrid: function(){},
	
	/**
	 * @method reconfigure the grid object by applying an existing 
	 * data store and columnheader collection 
	 */
	ReconfigureGrid: function(){
		try {
			this.Grid.reconfigure(this.Store, this.ColumnModel);
		}
		catch(e){};
	},
	/**
	 * @method GetToolbarFitlers returns an array of toolbar filters 
	 */
	GetToolbarFitlers: function(){},
	
	CreatePagingToolbarWStore: function(store, size){
		return this.CreatePagingToolbar.call({
			Store: store,
			GetToolbarFitlers: this.GetToolbarFitlers
		}, size);
	},
	 
	/**
	 * @method CreatePagingToolbar
	 * creates a base paging tool bar
	 * @param {Object} size
	 */
	CreatePagingToolbar: function(size){
		var bbar = new Ext.PagingToolbar({
            pageSize: size || 10,
            store: this.Store,
            displayInfo: true,
            displayMsg: 'Displaying {0} - {1} of {2}',
            emptyMsg: "No locations to display",
			plugins: this.GetToolbarFitlers(),
            items:[]
        });
		
		var lbmp = new Ext.form.DisplayField({
			value:'Page Size',
			style:'margin-left:5px; margin-right:5px;'
		});
		var txtmp = new Ext.form.TextField({
			value: size || 10,
			width:40,
			style:'margin-right:5px',
			Pager: bbar,
			enableKeyEvents: true,
			listeners: {
				change : function ( txt,newValue,oldValue ) {
					if (NP.IsWholeNumber(txt.getValue())) {
						this.Pager.pageSize = parseInt(newValue);
					}
				},
				keypress: function(txt , e){
					if (e.getKey() == 13) {
						e.stopPropagation();
	    				e.stopEvent();
					
						if (NP.IsWholeNumber(txt.getValue())) {
							this.Pager.pageSize = parseInt(txt.getValue());
							this.Pager.doLoad(this.Pager.cursor);
						}
					}
				}
			}
		 });
		bbar.MaxPageControl=txtmp;
		bbar.insert( 3, lbmp);
		bbar.insert( 4, txtmp);
		
		if(this.Store)
			this.Store.Pager=bbar;
			
		return bbar;
	},
	
	/**
	 * @method CreateColumns
	 * creates a collection of columns
	 */
    CreateColumns: function(){
        this.Columns = [];
    },
	
	/**
	 * @method CreateColumnHeader creates a column header collection
	 */
    CreateColumnHeader: function(){
        this.ColumnHeader = [];
    },
	
	/**
	 * @method CreateStore creates a data store 
	 * @param {Object} sortByfieldName
	 */
    CreateStore: function(sortByfieldName){
        this.CreateColumns();
        this.CreateColumnHeader();
        
        this.Proxy = new Ext.data.HttpProxy({
            timeout : 120000,
            url: '/broker.asmx/PerformOperationJson' 
        });
        
        this.Reader= new NP.NPReader({
            root: 'rows', 
            idProperty: this.EnableIDProperty? (this.IDProperty? this.IDProperty: sortByfieldName) : '',
            successProperty: 'success', 
            totalProperty: 'results',
            fields: this.Columns
        });
        
        this.Store= new Ext.data.Store({
            autoDestroy: true,
            proxy: this.Proxy,
            reader: this.Reader,
			remoteSort: this.EnableRemoteSorting,
			remoteGroup: this.EnableRemoteGrouping
        });
		
		if(this.EnableClientSort)
			this.Store.sortInfo={field:sortByfieldName, direction:'DESC'};
			
        this.ColumnModel = new Ext.grid.ColumnModel({
            // specify any defaults for each column
            defaults: {
                sortable: true, // columns are not sortable by default       
                width: 90  
            },
            columns: this.ColumnHeader
        });
    },
	
	/**
	 * Print the grid
	 * @param {Object} sender
	 * @param {Object} event
	 */
    PrintGrid: function(sender,event){
        var grid=this.WebControl.Grid;
        var height= grid.getHeight();

        grid.setHeight(grid.getEl().dom.clientHeight+ grid.view.scroller.dom.clientHeight);
        NP.Print(grid);

        grid.setHeight(height);
    },
	/**
	 * @method this function is called after LoadData
	 */
	OnLoadData: function(){},
	CBException: function(DataProxy, type, action, options, response, arg){
		
		this.WebControl.UnMask();
		NP.FailureCB(DataProxy, type, action, options, response, arg);
	}
});

NP.Iframe = Ext.extend(NP.Panel, {
	ClassName: 'NP.Iframe',
	/**
	 * @property Src
	 * @projectDescription src of the iframe
	 */
	Src: '',
	Height:450,
	InitEvents: function(){
		NP.Iframe.superclass.InitEvents.call(this);
		
		this.addEvents(
			"afterSrcLoaded"
        );
		
	},
	/**
	 * @see NP.Panel/CreateTab
	 */
	CreateTab: function(){
		NP.Iframe.superclass.CreateTab.call(this);
        
		this.Tab= new Ext.Panel({
            autoWidth: true,
			region:this.Region,
            height: this.Height,
            layout:'fit', 
            loadMask: true,
            bodyStyle:'padding:5px;',
            bodyCfg: {
                tag: 'iframe',
		        frameBorder: 0,
		        src: this.DefaultSrc+ this.Settings
            }
        });
    },
	/**
	 * @see NP.Panel/GetData
	 */
	GetData: function(){
		NP.Iframe.superclass.GetData.call(this);
        this.Tab.body.dom.style.width='99%';
		this.SetSrc(this.Src+ this.Settings|| "");
		var delay = this.DeferTime || 300;
		
		this.fireEvent('maskEl');
		this.Tab.body.on('load', function(sender ,e ){
			var scope= this;
			var load = function(msg){
				scope.fireEvent('afterSrcLoaded', scope.Tab.body.dom.src);
				scope.fireEvent('unmaskEl');
			}

			load.defer(delay,this,'afterSrcLoaded',delay);
		},this);
    },
	SetSrc:function(src){
		this.Tab.body.dom.src=src;
		this.Src=src;
	}
});

/** 
 * @constructor Window
 * @classDescription this class create and embed a source document inside an iframe.
 */
NP.Window = function(config){

	Ext.applyIf(this, {
		ClassName: 'NP.Window',
		/**
		 * @property AnimateTarget: represents the target control where this object will animate from
		 */
		AnimateTarget: '',
		/**
		 * @property Collapsible
		 */
		Collapsible: true,
		/**
		 * @property Height: represents the height of the tab control
		 */
		Height: 600,
		/**
		 * @property Width: represents the width of the tab control
		 */
		Width: 700,
		/**
		 * @property AutoHeight
		 */
		AutoHeight: false
	});
	
	NP.Window.superclass.constructor.call(this, config);
};

Ext.extend(NP.Window, NP.Iframe, {
	/**
	 * @see NP.Panel/CreateTab
	 */
	CreateTab: function(){
		NP.Window.superclass.CreateTab.call(this);
		
        this.Tab= new Ext.Window({
            width: this.Width,
            height: this.Height,
			autoHeight: this.AutoHeight,
            layout:'fit', 
            loadMask: true,
			animCollapse: true,
			collapsible: this.Collapsible,
            animateTarget:this.AnimateTarget,
            plain:true,
			y: 100,
			WebControl: this,
            closeAction: 'hide',
            bodyStyle:'padding:5px;',
            bodyCfg: {
                tag: 'iframe',
                frameBorder: 0,
				id: this.ID,
                src: this.Src+ this.Settings
            }
        });
    },
	
	/**
	 * @see NP.Panel/OnInit
	 */
	OnInit: function(){
		NP.Window.superclass.OnInit.call(this);
		
        this.Tab.show();
		this.Tab.on('close', function(container){
			try {
				delete NP.RunningApps[this.WebControl.ClassName]
				delete this.WebControl;
			}
			catch(e){};
		});
		this.Tab.on('expand', function(panel, animate){
			panel.body.dom.src=panel.WebControl.Src;
		});
    }
});

/********************************Ext User Extension***********************************/
/**
 * Custom Json reader used for parsing an asp.net webservice response
 * @param {Object} val
 */
NP.NPReader = Ext.extend(Ext.data.JsonReader,{
    read : function(response){
        var json = NP.Object.prototype.ParseResponseJson(response);
        var o=null;
        
        if(json=="{}")
            json='{"results":"0", "success":true, "rows":[]}';
		    
        try {
			o = NP.Object.prototype.ParseJson(json);
			
			if (o.success == false || (typeof o.success == 'string' && o.success.toLowerCase() == "false")) 
				throw {
					message: o.rows
				};
			else 
				if (typeof o.rows == 'string') 
					throw {
						message: o.rows
					};
		} 
		catch (e) {
			//Ext.Msg.alert('Neopost USA', json);
			try {
				var data = Ext.util.JSON.decode(json);
				if (!data) {
					throw {
						message: "JsonReader.read: Json object not found"
					};
					return;
				}
				throw {
					message: data.rows
				};
			} 
			catch (ee) {
			}
			return;
		}
        return this.readRecords(o);
    }
});

/**
 * Custom Json reader used for parsing an asp.net webservice response
 * @param {Object} val
 */
NP.TreeLoader = Ext.extend(Ext.tree.TreeLoader,{
	processResponse: function(response, node, callback, scope){
		var json = NP.Object.prototype.ParseResponseJson(response);
		var rawData;
		
		if (json == "{}") 
			json = '{"results":"0", "success":true, "rows":[]}';
		
		try {
			var obj = new NP.Object();
			o = obj.ParseJson(json);
			delete obj;
			
			if (o.success == false || (typeof o.success == 'string' && o.success.toLowerCase() == "false")) 
				throw {
					message: o.rows
				};
			else 
				if (typeof o.rows == 'string') 
					throw {
						message: o.rows
					};
			rawData = o;
			
			o = (this.ProcessDataSet) ? this.ProcessDataSet(o.rows) : o.rows;
			
			node.beginUpdate();
			for (var i = 0, len = o.length; i < len; i++) {
				var n = this.createNode(o[i]);
				if (n) {
					node.appendChild(n);
				}
			}
			node.endUpdate();
			
			this.runCallback(callback, scope || node, [node]);
		} 
		catch (e) {
			this.handleFailure(response);
		}
		return rawData;
	},
	handleResponse : function(response){
        this.transId = false;
        var a = response.argument;
		
        var rawData = this.processResponse(response, a.node, a.callback, a.scope);
		if(rawData)
			rawData.results= rawData.rows.length;
		
        this.fireEvent("load", this, a.node, response, rawData);
    }
});

NP.LinkButton = Ext.extend(Ext.Button, {
    template: new Ext.Template(
        '<table cellspacing="0" class="x-btn {3}"><tbody class="{4}">',
        '<tr><td class="x-btn-tl"><i>&amp;#160;</i></td><td class="x-btn-tc"></td><td class="x-btn-tr"><i>&amp;#160;</i></td></tr>',
        '<tr><td class="x-btn-ml"><i>&amp;#160;</i></td><td class="x-btn-mc"><em class="{5}" unselectable="on"><a href="{6}" target="{7}"><div class="x-btn-text {2}"><button>{0}</button></div></a></em></td><td class="x-btn-mr"><i>&amp;#160;</i></td></tr>',
        '<tr><td class="x-btn-bl"><i>&amp;#160;</i></td><td class="x-btn-bc"></td><td class="x-btn-br"><i>&amp;#160;</i></td></tr>',
        '</tbody></table>').compile(),

    buttonSelector : 'div:first',

    getTemplateArgs: function() {
        return Ext.Button.prototype.getTemplateArgs.apply(this).concat([this.href, this.target]);
    },

    onClick : function(e){
        if(e.button != 0){
            return;
        }
        if(!this.disabled){
            if(this.menu && !this.menu.isVisible() && !this.ignoreNextClick){
                this.showMenu();
            }
            this.fireEvent("click", this, e);
            if(this.handler){
                this.handler.call(this.scope || this, this, e);
            }
        }
    }
});

/**
 * @class Ext.LinkButton
 * @extends Ext.Button
 * A Button which encapsulates an &lt;a> element to enable navigation, or downloading of files.
 * @constructor
 * Creates a new LinkButton
 */ 
Ext.LinkButton = Ext.extend(Ext.Button, {
    template: new Ext.Template(
        '<table cellspacing="0" class="x-btn {3}"><tbody class="{1}">',
            '<tr>',
                '<td class="x-btn-tl"><i>&#160;</i></td>',
                '<td class="x-btn-tc"></td>',
                '<td class="x-btn-tr"><i>&#160;</i></td>',
            '</tr>',
            '<tr>',
                '<td class="x-btn-ml"><i>&#160;</i></td>',
                '<td class="x-btn-mc">',
                    '<em class="{2}" unselectable="on">',
                        '<a href="{6}" style="display:block;{7}" target="{5}" class="x-btn-text">{0}</a>',
                    '</em>',
                '</td>',
                '<td class="x-btn-mr"><i>&#160;</i></td>',
            '</tr>',
            '<tr>',
                '<td class="x-btn-bl"><i>&#160;</i></td>',
                '<td class="x-btn-bc"></td>',
                '<td class="x-btn-br"><i>&#160;</i></td>',
            '</tr>',
        '</tbody></table>'
    ).compile(),

    buttonSelector : 'a:first',

    /** 
     * @cfg String href
     * The URL to create a link for.
     */
    /** 
     * @cfg String target
     * The target for the &lt;a> element.
     */
    /** 
     * @cfg Object
     * A set of parameters which are always passed to the URL specified in the href
     */
    baseParams: {},

//  private
    params: {},
	linkStyle: 'text-decoration:none',
    getTemplateArgs: function() {
        return Ext.Button.prototype.getTemplateArgs.apply(this).concat([this.getHref(), this.linkStyle, this.target]);
    },

    onClick : function(e){
        if(e.button != 0){
            return;
        }
        if(this.disabled){
            this.stopEvent(e);
        } else {
            if (this.fireEvent("click", this, e) !== false) {
                if(this.handler){
                    this.handler.call(this.scope || this, this, e);
                }
            }
        }
    },

    // private
    getHref: function() {
        var result = this.href;
		var p="";
		
		if (this.params instanceof Array) {
			for (var i = 0; i < this.params.length; i++) 
				p += "paramList=" + this.params[i] + "&";
		}
					
        if (p.length) {
            result += ((this.href.indexOf('?') == -1) ? '?' : '&') + p;
        }
        return result;
    },

    /**
     * Sets the href of the link dynamically according to the params passed, and any {@link #baseParams} configured.
     * @param {Object} Parameters to use in the href URL.
     */
    setParams: function(p) {
        this.params = p;
		
		if(this.el)
        	this.el.child(this.buttonSelector, true).href = this.getHref();
    }
});
// Add xtype
Ext.ComponentMgr.registerType('linkbutton', Ext.LinkButton);

Ext.grid.CheckColumn = function(config){
    Ext.apply(this, config);
    if(!this.id){
        this.id = Ext.id();
    }

    this.renderer = this.renderer.createDelegate(this);
};

Ext.grid.CheckColumn.prototype ={
    init : function(grid){
        this.grid = grid;
        this.grid.on('render', function(){
            var view = this.grid.getView();
            view.mainBody.on('mousedown', this.onMouseDown, this);
        }, this);
    },

    onMouseDown : function(e, t){
        if(t.className && t.className.indexOf('x-grid3-cc-'+this.id) != -1){
            e.stopEvent();
            var index = this.grid.getView().findRowIndex(t);
            var record = this.grid.store.getAt(index);
            record.set(this.dataIndex, !record.data[this.dataIndex]);
			
			this.click(record);
			
        }
    },
	click: function(record){
		
	},
    renderer : function(v, p, record){
        p.css += ' x-grid3-check-col-td'; 
        return '<div class="x-grid3-check-col'+(v?'-on':'')+' x-grid3-cc-'+this.id+'"> </div>';
    }
};  
Ext.ComponentMgr.registerType('checkcolumn', Ext.grid.CheckColumn);

NP.Item = function(config) {
	NP.Item.superclass.constructor.call(this, config);
}
Ext.extend(NP.Item, Ext.menu.Item, {
	setHref: function(href, target)
	{
		this.href = (href == undefined) ? "#" : href;
		this.hrefTarget = (target == undefined) ? "_blank" : target;	         
	}
});

Ext.ComponentMgr.registerType('hrefitem', NP.Item);
		
NP.SplitButton = Ext.extend(Ext.SplitButton, {
	template: new Ext.Template(
		'<table cellspacing="0" class="x-btn {3}">',
			'<tbody class="{4}">',
			'<tr>',
				'<td class="x-btn-tl"><i>&#160;</i></td>',
				'<td class="x-btn-tc"></td>',
				'<td class="x-btn-tr"><i>&#160;</i></td>',
			'</tr>',
			'<tr>',
				'<td class="x-btn-ml"><i>&#160;</i></td>',
				'<td class="x-btn-mc">',
					'<em unselectable="on" class="{5}">',
						'<a href="{6}" style="display:block;{7}" target="{8}" class="x-btn-text">{0}</a>',
					'</em>',
				'</td>',
				'<td class="x-btn-mr"><i>&#160;</i></td>',
			'</tr>',
			'<tr>',
				'<td class="x-btn-bl"><i>&#160;</i></td>',
				'<td class="x-btn-bc"></td>',
				'<td class="x-btn-br"><i>&#160;</i></td>',
			'</tr>',
			'</tbody>',
		'</table>'
    ).compile(),

    buttonSelector : 'a:first',
    /** 
     * @cfg String href
     * The URL to create a link for.
     */
    /** 
     * @cfg String target
     * The target for the &lt;a> element.
     */
    /** 
     * @cfg Object
     * A set of parameters which are always passed to the URL specified in the href
     */
    baseParams: {},

//  private
    params: {},
	linkStyle: 'text-decoration:none',
	applyParamToChild: false,
    getTemplateArgs: function() {
		this.on('arrowclick', function(btn,e){
			this.setParams(this.scope.Params);
		})
        return Ext.SplitButton.prototype.getTemplateArgs.apply(this).concat([this.getHref(), this.linkStyle || "", this.target || ""]);
    },
    // private
    getHref: function() {
        var result = this.href || "";
		var p = this.toStringParams();
					
        if (p.length) {
            result += ((this.href.indexOf('?') == -1) ? '?' : '&') + p;
        }
        return result;
    },
	getHrefStr: function(paramStr, href){
		var result = href || "";
					
        if (paramStr.length) {
            result += ((href.indexOf('?') == -1) ? '?' : '&') + paramStr;
        }
        return result;
	},
	toStringParams: function(){
		var p="";
		
		if (this.params instanceof Array) {
			for (var i = 0; i < this.params.length; i++) 
				p += "paramList=" + this.params[i] + "&";
		}
		
		if(p.length==0)
			p='paramList=null&';
			
		if (this.baseParams) {
			for (var item in this.baseParams) {
				p+=item+"="+ this.baseParams[item] + "&";
			}
		}
		return p;
	},

    /**
     * Sets the href of the link dynamically according to the params passed, and any {@link #baseParams} configured.
     * @param {Object} Parameters to use in the href URL.
     */
    setParams: function(p) {
        this.params = p;
		var pstr = this.toStringParams();
		
		if(this.el && this.el.child(this.buttonSelector, true))
        	this.el.child(this.buttonSelector, true).href = this.getHrefStr(pstr,this.href);
		
		if (this.applyParamToChild) {
			if (this.menu && this.menu.items.length > 0) {
				
				for(var i=0; i<this.menu.items.items.length; i++){
					var href = this.menu.items.items[i].initialConfig.href; //this.menu.items.items[i].hrefCopy; 
					
					if (this.menu.items.items[i].rendered) {
						this.menu.items.items[i].el.dom.target = this.target;
						this.menu.items.items[i].el.dom.href = this.getHrefStr(pstr, href);
					}
					else {
						this.menu.items.items[i].target = this.target;
						this.menu.items.items[i].href = this.getHrefStr(pstr, href);
					}
				}
			}
		}
    },
	
	appendParams: function(){
		
	}
});
// Add xtype
Ext.ComponentMgr.registerType('linkbutton', NP.SplitButton);

NP.ImageButton = Ext.extend(Ext.BoxComponent, {
    onRender : function(ct, position){
        this.autoEl = {
            tag: 'button',
            cn: this.text || '&nbsp;',
            cls: 'ux-image-button'
        };
        if(this.icon){
            this.autoEl.style = 'background-image: url(' + this.icon + ')';
        }
        NP.ImageButton.superclass.onRender.call(this, ct, position);
		
        this.el.on('click', this.handler, this, {stopEvent: true});
		
		if(this.el.dom)
			this.el.dom.setAttribute('tabIndex', -1);
			
		if(!this.IgnoreToolTip)
			this.CreateTooltip();
    },
    handler: Ext.emptyFn,
	SetIcon: function(img){
		this.icon=img;
		this.el.dom.style.backgroundImage='url(' + img + ')';
	},
	CreateTooltip: function(){
		this.tip = new Ext.ToolTip({
			anchorToTarget: true,
	        target: this.el,    // The overall target element.
	        trackMouse: true,         // Moving within the row should not hide the tip.
	        renderTo: document.body  // Render immediately so that tip.body can be
	                                  //  referenced prior to the first show.
	    });
		
		this.UpdateTip(this.tooltip);
	},
	UpdateTip: function updateTipBody(tooltip){
		this.tip.body.dom.innerHTML = tooltip;
	},
	GetTip: function(){
		return this.tip.body.dom.innerHTML;
	}
});
// Add xtype
Ext.ComponentMgr.registerType('imagebutton', NP.LinkButton);

//Ext.form.VTypes["passwordRegEx"] = /^(?=\w*\d)\w{6,12}$/;

Ext.apply(Ext.form.VTypes, {
    passwordRegEx: function(val, field){
		var passRegEx1 = /^\w{7,16}$/;
		var passRegEx2 = /\d+/;
		
		if (passRegEx1.test(val)) {
			return passRegEx2.test(val);
		}
		else {
			return false;
		}
		
	},
    passwordRegExText: 'Min 7 alphanumeric chars. (a-z A-Z 0-9) Must contain at least 1 digit, and no special characters.'
});

Ext.apply(Ext.form.VTypes, {
  password: function(val, field) {
    if (field.initialPassField) {
		var pwd=field.initialPassField;
		if(typeof field.initialPassField =='string')
      		var pwd = Ext.getCmp(field.initialPassField);
      return (val == pwd.getValue());
    }
    return true;
  },
  passwordText: 'The passwords entered does not match!'
});

Ext.apply(Ext.form.VTypes, {
    usPhone: function(v) {
        return /\([2-9]\d\d\)\s[2-9]\d\d-\d{4}$/.test(v);
    },
    usPhoneText: 'Please enter a US Phone number in the format (999) 999-9999',
    usPhoneMask: /[\d\s\(\)\-]/i
});

Ext.apply(Ext.form.VTypes, {
     phone: function(val, field){
         var re = /(1?(-?\d{3})-?)?(\d{3})(-?\d{4})/;
	field.invalidText = 'Invalid phone number';
	return re.test(val);
     },
     phoneText : 'Invalid phone number format.  Please enter in xxx-xxx-xxxx format'
});

Ext.apply(Ext.form.VTypes, {
	creditCard: function(val, field){
		if (val.length > 16) {
			return false;
		} else {
			var cardType = Ext.getCmp(field.cardTypeField).getValue();
			var cardNumber = val;
			
			var cardExpireMonth = Ext.getCmp(field.expireMonthField).getValue();
			var cardExpireYear = Ext.getCmp(field.expireYearField).getValue();
			field.invalidText = 'Please enter a valid credit card number';
			return Mod10(cardType, cardNumber, cardExpireMonth, cardExpireYear);
		}
	},
	creditCardText: ''
});

Ext.apply(Ext.form.VTypes, {
	userName: function(v){
		var reg = /^([a-zA-Z0-9_-]+)$/;
		var regEmail = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,10}$/;
		
		if (v.indexOf(' ') != -1) {
			Ext.apply(Ext.form.VTypes, {
				userNameText: 'username should not contain space(s)'
			});
			return false;
		}
		
		Ext.apply(Ext.form.VTypes, {
			userNameText: 'Min. 6 alphanumeric chars. (a-z A-Z 0-9) No special characters or spaces except dash and underscore. (- _)' // and most contain at least 1 numeric value'
		});
		if (v.length > 5) {
			if (v.indexOf('@') != -1) 
				return regEmail.test(v);
			else 
				return reg.test(v);
		}
		return false;
	},
	userNameText: 'Min. 6 alphanumeric chars. (a-z A-Z 0-9) No special characters or spaces except dash and underscore. (- _)' // and most contain at least 1 numeric value'
});

Ext.apply(Ext.form.VTypes, {
    emailExt: function(v) {
		return /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,10}$/.test(v);
    },
    emailExtText: 'This field should be an e-mail address in the format<b/>"user@example.com"'
});

Ext.apply(Ext.form.VTypes, {
    zipCode: function(v) {
		return /^\d{5}$/.test(v);
    },
    zipCodeText: 'Not a valid zipcode. Zip code must be 5 digits long',
	zipCodeMask: /[\d-]/
});

Date.patterns = {
    ISO8601Long:"Y-m-d H:i:s",
    ISO8601Short:"Y-m-d",
    ShortDate: "n/j/Y",
    LongDate: "l, F d, Y",
    FullDateTime: "l, F d, Y g:i:s A",
    MonthDay: "F d",
    ShortTime: "g:i A",
    LongTime: "g:i:s A",
    SortableDateTime: "Y-m-d\\TH:i:s",
    UniversalSortableDateTime: "Y-m-d H:i:sO",
    YearMonth: "F, Y"
};

String.prototype.RTrim = function() {
	return this.replace(/((\s*\S+)*)\s*/, "$1");
}
String.prototype.EscapeJson = function() {
	return String.escape(this).replace(/: \\/g,":").replace(/\\',/g,"',").replace(/\\'}/g,"'}");
}
String.prototype.ObjectFormat = function(data){
	var formatted = this;
	for (arg in data) {
		formatted = formatted.replace("{" + arg + "}", data[arg]);
	}
	return formatted;
};


Ext.grid.WordWrapColumnModel = Ext.extend(Ext.grid.ColumnModel, {

    initComponent: function() {
        Ext.grid.WordWrapColumnModel.superclass.initComponent.apply(this, arguments);
    },

    getRenderer: function(col) {
		
        if (!this.config[col].renderer) {
            if (typeof (this.config[col].wordWrap) == 'undefined' || this.config[col].wordWrap == true) {
                return Ext.grid.ColumnModel.wordWrapRenderer;
            } else {
                return Ext.grid.ColumnModel.defaultRenderer;
            }
        }
        return this.config[col].renderer;
    },

    onRender: function() {
        Ext.grid.WordWrapColumnModel.superclass.onRender.apply(this, arguments);
    }
});

Ext.grid.ColumnModel.wordWrapRenderer = function(value) {
	
    return '<div style="white-space:normal !important;">' + value + '</div>';
};

Ext.ns('Ext.ux.grid');
(function () {
    var cursorRe = /^(?:col|e|w)-resize$/;
    Ext.ux.grid.AutoSizeColumns = Ext.extend(Object, {
        cellPadding: 8,
        constructor: function (config) {
            Ext.apply(this, config);
        },
        init: function (grid) {
            var view = grid.getView();
            view.onHeaderClick = view.onHeaderClick.createInterceptor(this.onHeaderClick);
            grid.on('headerdblclick', this.onHeaderDblClick.createDelegate(view, [this.cellPadding], 3));
        },
        onHeaderClick: function (grid, colIndex) {
            var el = this.getHeaderCell(colIndex);
            if (cursorRe.test(el.style.cursor)) {
                return false;
            }
        },
        onHeaderDblClick: function (grid, colIndex, e, cellPadding) {
            var el = this.getHeaderCell(colIndex), width, rowIndex, count;
            if (!cursorRe.test(el.style.cursor)) {
                return;
            }
            if (e.getXY()[0] - Ext.lib.Dom.getXY(el)[0] <= 5) {
                colIndex--;
                el = this.getHeaderCell(colIndex);
            }
            if (this.cm.isFixed(colIndex) || this.cm.isHidden(colIndex)) {
                return;
            }
            el = el.firstChild;
            el.style.width = '0px';
            width = el.scrollWidth;
            el.style.width = 'auto';
            for (rowIndex = 0, count = this.ds.getCount(); rowIndex < count; rowIndex++) {
                el = this.getCell(rowIndex, colIndex).firstChild;
                el.style.width = '0px';
                width = Math.max(width, el.scrollWidth);
                el.style.width = 'auto';
            }
            this.onColumnSplitterMoved(colIndex, width + cellPadding);
        }
    });
})();
Ext.preg('autosizecolumns', Ext.ux.grid.AutoSizeColumns);

Ext.override(Ext.grid.ColumnModel,{	
	removeColumn: function(colIndex){
		var config = this.config;
		this.config = [config[colIndex]];
		config.splice(colIndex, 1);
		this.setConfig(config);
	}
});


/*****************************End of Extensions*************************************/
Ext.onReady(function(){
	var wp = new NP.WelcomePanel();
});
