/**
* @namespace
* @meta-type namespace
* namespace - The root namespace for Kusog
*/
var ksg = {
	
	/**
	*	@namespace
	* A common collection of usefull helper functions used by Kusog internals.
	*/
    util: {
        svcCall: function (url, success, error, cbId, data, usePOST) {
            var callbackName = cbId;
			var ajaxOptions = { dataType: url.indexOf(':') != -1 ? 'jsonp' : 'json', url: url, data: data, success: success, error: error, jsonpCallback: callbackName };
			if(usePOST == true)
				ajaxOptions["type"] = "POST";
            $.ajax(ajaxOptions);
        },
        isNull: function (i) {
            return (i == null || typeof (i) == 'undefined');
        },
		
        urlParamsId: function () {
            if (urlParams.id != null)
                return urlParams.id;
            return 'NotFound';
        },
		/**
		* The big problem with just checking for window.DOMParser is that IE9 supports that now, but the xml document
		* it returns lacks many things expected in an xml document like selectSingleNode.  However, if we keep using the
		* active x object type, then it works fine.  So now we just check for ie and default to the better xml document
		* type for now.
		* Lots of bug reports for this on web "ie9 missing selectSingleNode"
		*/
        createXmlDoc: function (xml) {
            var xmlDoc = null;
            //if (window.DOMParser) {
			 if(!$.browser.msie) {
                parser = new DOMParser();
                xmlDoc = parser.parseFromString(xml, "text/xml");
            }
            else // Internet Explorer
            {
                xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
                xmlDoc.async = "false";
                xmlDoc.loadXML(xml);
            }
            return xmlDoc;
        },
        createXmlString: function (elem) {
            var serialized;
            try {
                // XMLSerializer exists in current Mozilla browsers
                serializer = new XMLSerializer();
                serialized = serializer.serializeToString(elem);
            }
            catch (e) {
                // Internet Explorer has a different approach to serializing XML
                serialized = elem.xml;
            }

            return serialized;
        }
    },
	
	/**
	*	@namespace
	* namespace - Contains all code items related to the gui portion of the app framework.
	* @meta-type namespace
	*/
	ui: {
	/**
	* @namespace
	* Factory Map of registered bizprocs.
	* @meta-type factory
	*/
		bizprocs:{}
	},
	/**
	* @namespace
	* Map of registered web services that can be called by name.
	*/
	services: {}
};

if(!$.browser.msie && XMLDocument.prototype.selectNodes == null) {
    XMLDocument.prototype.selectNodes = function(xpath, contextNode) {
		try {
			if (this.nsResolver == null)
				this.nsResolver = this.createNSResolver(this.documentElement);
	
			var oResult = this.evaluate(xpath, (contextNode?contextNode:this), null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
			var nodeList = new Array(oResult.snapshotLength);
			nodeList.expr = xpath;
			var j = 0;
			for (i=0;i<oResult.snapshotLength;i++)
			{
				var item = oResult.snapshotItem(i);
				//	Ignore whitespace nodes.
				if (item.nodeType != 3)
				{
					nodeList[j++] = item;
				}
			}
			return nodeList;
		}catch(e){
		}
    }

    XMLDocument.prototype.selectSingleNode = function(xpath, contextNode) {
        var ar = this.selectNodes(xpath,contextNode);
        if(ar.length > 0)
            return ar[0];
        return null;
    }
}

/**
* @namespace
* The main access point for interacting with the app framework at runtime.
* @meta-type static class
* @Depends ksg.base.js
*/
ksg.App = {
	/**
	* A place to store data in the browser that will survive between page loads.
	*/
	SessionData: function() {
		return ksg.App._sessionData;
	},
	_sessionData: {
	}
	
};
/**
* @class The base exception to all exceptions thrown by code in Kusog.
* @Depends ksg.base.js

* @param {String} id The unique identifier for the given type of exception.  
* This should be usable as an id for articles written about the given type of error.
* @param {String} location A source code location that helps to identifer where the given error
* happened.
* @param {Map} vals A map of values that will be used as information about the error
* and can be embedded into an article about the error when displayed to the user.
*/
ksg.BaseException = function(id, location, vals) {
	this.id = id;
	this.location = location;
	this.vals = vals;
}
ksg.BaseException.prototype = {
	/**
	* A rudamentary method to generate a single line of text that could be displayed
	* to a user about the exception.  This isnt a very classy way to display an error, but is useful
	* in the begining of development.
	* @returns {String} A string with the various information about the error embedded in.
	*/
	displayText: function() {
		var txt = this.location + " - " + this.id + ": ";
		for(var i in this.vals)
			txt += this.vals[i] + ", ";
		return txt;
	}
};
/**
* @namespace
*/
$.extend(ksg.services, /** @lends ksg.services# */{
	/**
	* baseUrl is used as the default location for web services to be called from if it is not
	* overriden on a given call.  Typically this property is set with options bassed to the 
	* ksgSetupUI jQuery plugin.
	*/
	baseUrl: "",

	/**
	* General Scs services
	*/
	getTemplate: function (tmplName, success, error) {
		ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/getTemplate/" + tmplName, success, error, "x" + tmplName.replace(/-/g,""));
	}
});
$.extend(ksg.ui, /** @lends ksg.ui */{

	/**
	* @namespace
	* Action availability enum used by bizproc actions to indicate their current state for user interaction.
	* @meta-type enum
	*/
	Availability: {
		/**The given value is not set. */
		NotSet: -1, 
		/** The user has no access */
		None: 0,
		/** The user has access, but not at this moment due to other reasons like the current UI state. */
		Disabled: 1, 
		/** The user has access and can use the action right now */
		Enabled: 2
	},
	
	/**
	* @namespace
	* The base.bizproc expects the views it is interacting with to specify what type of view they are
	* for this bizproc.
	* @meta-type enum
	*/
	BizProcWidgetType: {
		/** A bizobj list display, meant to show the primary list of bizobjs from a bizproc  */
		List: 0,
		/** A bizobj detail display, meant to show the details on one bizobj, typically the current bizobj from the bizproc  */
		Disp: 1,
		/** A filter/sort criteria display, meant to help build the filter/sort options for getting the list of bizobjs */
		Criteria: 2,
		/** A paging display that will allow the user to page through the main list of bizobjs when they can only see a small number of them at one time */
		Pager: 3,
		/** An action trigger widget that will typically respond to user interaction (such as mouse click) and then trigger an action on the bizproc */
		ActionTrigger: 4,
		/** To be documented */
		AltList: 5,
		/** To be documented */
		AltDisp: 6, 
		/** To be documented */
		AltDisp2: 7,
		/** Some other custom widget that the particular bizproc would know how to deal with */
		Other: 8
	},

	/**
	* @namespace
	* The ksg.ui.BizProc class can use a blend of two bizobj lists, one being a master list
	* and the other being the main list, using this enum to indicate how it is getting its
	* master bizobj list.
	* @meta-type enum
	*/
	MasterDataOption: {
		/** Not specified */
		Unknown: -1,
		/** There is no master bizobj list */
		None: 0, 
		/** There is a master bizobj list, which comes from a parent bizproc's data */
		ListFromParentBizProc: 1, 
		/** There is a master bizobj list, which is retrieved by calling the bizrule named in the bizproc's bizrules.getMasterBizObjListBizRule */
		ListFromRule: 2
	},
	
	//Will get reset to true after the page load event has fired.  Can be used to determine if the page has loaded yet.
	pageLoaded: false,
	
	/**
	* A collection of objects that can get/set values out of a dom element.  This is an important class
	* for moving data between a dom element tree and a bizobj.
	*
	* @type Map<string,object> 
	*/
	fields: {
		"label": {
			//getVal on label returns null because it is a read only control.
			getVal: function ($el) { return null; },
			setVal: function ($el, val) { $el.html(val); }
		},
		"textbox": {
			getVal: function ($el) { return $el.val(); },
			setVal: function ($el, val) { $el.val(val); }
		},
		"textarea": {
			getVal: function ($el) { return $el.val(); },
			setVal: function ($el, val) { $el.val(val); }
		},
		"hiddenfield": {
			getVal: function ($el) { return $el.val(); },
			setVal: function ($el, val) { $el.val(val); }
		},
		"checkbox": {
			getVal: function ($el) { return $el.attr('checked') ? 'True' : 'False'; },
			setVal: function ($el, val) { $el.attr('checked', val.toLowerCase() == 'true' ? true : false); }
		},
		"dropdowncalendar": {
			getVal: function ($el) { return $('#' + $el.attr('id') + 'Fld').val(); },
			setVal: function ($el, val) { $('#' + $el.attr('id') + 'Fld').val(val); }
		},
		"combo": {
			getVal: function ($el) { 
				var v = $('#' + $el.attr('id') + 'SelectedValue0').val(); 
				return v;
			},
			setVal: function ($el, val) { 
				var cb = nitobi.getComponent($el.attr('id'));
				setComboSelectedRowByKey(cb, val); 
			}
		},
		"combosearch": {
			getVal: function($el) {
				var v = $ntb($el.attr('id') + 'SelectedValue0').value;//var v2 = $ntb('EBAComboBoxTextValue' + $el.attr('id')).value;if(v2=='' || v=='') v = v2;
				if(v=="")
					v = $el.data("bizObjId");
				return v==""?null:v;
			},
			setVal: function ($el, val, bizobj, fieldName) { 
				$el.data("bizObjId", val);
				var cb = nitobi.getComponent($el.attr('id'));
				var val2 = bizobj.getAttribute(fieldName + "_dispName");
				setComboSelectedRowByKey(cb, val2); 
			}
		},
		"dropdownlist": {
			getVal: function ($el) { var el = $el.get(0); return el.options(el.selectedIndex).value; },
			setVal: function ($el, val) { var dd = $el.get(0); for (var p = 0; p < dd.options.length; p++) if (dd.options[p].value == val) { { dd.options[p].selected = true; break; } }; }
		},
		"radiobutton": {
			getVal: function ($el) { return $el.checked ? 'True' : 'False'; },
			setVal: function ($el, val) { $el.attr('checked', val.toLowerCase() == 'true' ? true : false); }
		},
		"editableimage": {
			getVal: function ($el) {
				return getScsImageSrc($el,false);
			},
			setVal: function ($el, val) { $el.attr('src', val); }
		},
		"image": {
			getVal: function ($el) { return $el.attr('src'); },
			setVal: function ($el, val) { $el.attr('src', val); }
		},
		"hyperlink": {
			getVal: function ($el) { return $el.attr('href'); },
			setVal: function ($el, val) { $el.attr('href', val); }
		},
		"ckeditor": {
			getVal: function ($el) { try{
				var v = CKEDITOR.instances[$el.attr('id')].getData();
				return v;
			}catch(e){} },
			setVal: function ($el, val) { try{var f = CKEDITOR.instances[$el.attr('id')];if(f!=null)f.setData(val);}catch(e){} }
		},
		"readonlytext": {
			//Even though the control is named readonlytext, it is actually not read only and can be edited.
			getVal: function ($el) { return getROCTextValue($el); },
			setVal: function ($el, val) {
				$el.html(val);

				//TODO: Move the following out of here and into another control called 'scriptablereadonlytext'
				var re = /<script\b[\s\S]*?>([\s\S]*?)<\//ig;
				var match;
				while (match = re.exec(val)) {
					eval(match[1]);
				}
			}
		}
	},

	/**
	* @namespace
	* Objects that represent widget prototypes are defined in here.  This helps with "widget inheritance".
	* @meta-type namespace
	*/
	widgets: {},
	/**
	* @namespace
	* The widget map is a collection of functions that know how to create a specific type of widget.
	* The keys in this colleciton map to the css class names attached to dom elements.  This
	* is the key class factory used by the scsSetupUI jQuery plugin.
	* @meta-type factory
	*/
	widgetMap: {
		addWidget: function(widgetId, factoryMethod) {this[widgetId] = factoryMethod;}
	},

	/**
	* This will look for all elements marked as an edit field and get its value if it is marked as
	* being edited.  The resulting obj will be populated with the values from the dirty elements
	* only.
	*/
	populateFromDirtyFields: function ($el, obj) {
		$el.find(".ksg-edit-field").each(function () {
		});
	},

	_tmplCache: {},
	
	getTemplate: function (templateName, ext, success, error) {
		var $tmpl = null;
		var rtId = templateName+ext;
		var $tmpl = ksg.ui._tmplCache[rtId];
		if ((!($tmpl) || $tmpl.length == 0) && templateName) {
			ksg.services.getTemplate(rtId, function(tmpl) {
				var $tmpl = $(tmpl.response);
				ksg.ui._tmplCache[rtId] = $tmpl;
				success({tmpl: $tmpl});
			}, error);
		}
		else if ($tmpl.length !=0)
			success({ tmpl: $tmpl });
		//TODO:ERROR OTHERWISE
	},

	/**
	* Will break aparet the window.location value and grab at the query string parameters.
	* Returns an object with the results.
	* Note: This implementation does not deal with multiple names with the same name, which is valid.
	*/
	queryString: function () {
		if (this._urlParams == null) {
			this._urlParams = {};
			var e,
			a = /\+/g,  // Regex for replacing addition symbol with a space
			r = /([^&=]+)=?([^&]*)/g,
			d = function (s) { return decodeURIComponent(s.replace(a, " ")); },
			q = window.location.search.substring(1);

			while (e = r.exec(q))
				this._urlParams[d(e[1])] = d(e[2]);
		}
		return this._urlParams;
	},
	_urlParams: null,

	loadCssUrl: function (url) {
		if (document.createStyleSheet) 
			document.createStyleSheet(url);
		else
			$("head").append($("<link>").attr({ type: 'text/css', rel: 'stylesheet', href: url }));
	},
	loadScriptUrl: function (url, success) {
		$.getScript(url, success);
	},
	
	getElementDataObject: function($el, name) {
		var op = $el.data(name);
		var opt = typeof(op);
		if(opt == "string")
			op = $.parseJSON(opt);
		return op;
	}
});
/**
* @namespace
* namespace - Contains all items related to bizobjs
* @meta-type namespace

*/
ksg.bizobj = {
	/**
	* @namespace
	* @meta-type Map
	* Map of all known bizObj types.
	*/
	bizObjTypes: { },

	/**
	* This should be the base prototype for all real bizobj types created
	* so that the standard functionality of a bizobj is available.
	* @class
	* @importance high
	*/
	BizObj: {
		/**
		* Will retrieve a value from the bizobj, and if not found or null is returned, the optional
		* defVal will be used if supplied.
		* <p>This method has deep name address support, which standard javascript obj["name.name"] 
		* does not.  Also, this method serves as a general point of entry for getting values out of a bizobj
		* and thus will support decorated bizobj values.</p>
		* @param {Object} obj The object to get the value from.  This does not actually need to be a BizObj based class - any javascript object will work.
		* @param {String} deepName The field name to get the value for, which can be a deep name address.
		* @param {Object} defVal optional - The default value to use if the resulting value is not found or null.
		* @returns {object} The value requested
		*/
		getValue: function(obj, deepName, defVal) {
			var child = defVal==null?null:defVal;
			if(obj && deepName) {
				var names = deepName.split('.');
				child = obj;
				for(var i = 0; i < names.length; i++)
					if(names[i] in child) {
						if((child = child[names[i]]) == null)
							break;
					}
					else
						return defVal;

			}
			return child;
		},
		
		/**
		* Will check to see if the given name is contained within the given object.
		* <p>This method has deep name address support, which standard javascript obj["name.name"] 
		* does not.</p>
		* @param {Object} obj the object to check if the given name exists in
		* @param {String} deepName the deep name address to check for
		* @returns {Boolean} 
		*/
		hasValue: function(obj, deepName) {
			var hasIt = true;
			if(obj && deepName) {
				var names = deepName.split('.');
				var child = obj;
				for(var i = 0; i < names.length; i++)
					if(names[i] in child)
						child = child[names[i]];
					else
						return false;
			}
			return hasIt;
		}
	},

	/**
	* While arrays of bizobjs can be used instead of BizObjList, this class provides 
	* methods that make using bizobjs easier.
	* so that the standard functionality of a bizobj is available.
	* @class
	* @importance high
	*/
	BizObjList: {
	}
};

$.extend(ksg.bizobj.bizObjTypes, {
	Article: {
		depthWidth: function (art) {
			return art.depth * 25;
		},
		calculatedShortTitle: function () {
			var d = this.data;
			return (d.shortTitle) ? d.shortTitle : d.title;
		}
	}
});

/**
* @class
* Provides a way to interate through a collection of bizobjs without having to
* maintain an index.  The cursor is an index into a list of bizobjs.
* @importance high
*/
ksg.bizobj.BizObjCursor = function(bizObjs) {
	this.bizObjs = bizObjs;
	this.pos = 0;
};

ksg.bizobj.BizObjCursor.prototype = {
	hasMoreThanOne: function() {
		return this.bizObjs.length > 1;
	},
	
	moveFirst:function() {
		this.pos = 0;
		return this.currentElement();
	},
	movePrev:function() {
		if(--this.pos < 0)
			this.pos = 0;
		return this.currentElement();
	},
	moveNext:function() {
		if(++this.pos >= this.bizObjs.length)
			if((this.pos = this.bizObjs.length-1) < 0)
				this.pos=0;
		return this.currentElement();
	},
	moveLast:function() {
		this.pos = this.bizObjs.length -1;
		if((this.pos = this.bizObjs.length-1) < 0)
			this.pos=0;
		return this.currentElement();
	},
	moveTo:function(pos) {
		if(pos >= 0 && pos < this.bizObjs.length)
			this.pos = pos;
		return this.currentElement();
	},
	isBOF:function() {
		return this.pos == 0;
	},
	isEOF:function(){
		var s = this.bizObjs.length-1;
		if(s<0)
			s==0;
		return this.pos == s;
	},
	currentElement:function() {
		if(this.pos >=0 && this.pos < this.bizObjs.length)
			return this.bizObjs[this.pos];
		return null;
	},
	pushForward: function(num) {
		num = new Number(num);
		var length = this.bizObjs.length;
		var start = this.pos, end = (num&&num>0)?this.pos+(num):length;
		if(end > length)
			end = length;
		this.pos = end;
		return this.bizObjs.slice(start,end);
	}
};

/**
* @namespace
* Maintains a collection of BizObj types (JavaScript classes) that it uses to service requests to
* create BizObj and BizObj List objects.
* @Depends feature.bizobj.js
* @meta-type static class
*/
ksg.App.bizObjMgr = {
	/**
	* Given a bizobj type name and plain javascript object containing values for the new bizobj,
	* this will create the given type.  If the plain javascript object contains a key named
	* _type it will override the typeName provided and try to use the value of _type for the 
	* new bizobj type.
	*
	* <p>Typically, if json wont contain _type on every object, which would bloat the total size transmitted.
	* However there are special cases such as a field of a bizobj is a hetrogenous map of objects and
	* as such each object in that particular map is providing a _type to specify what it is.</p>
	*
	* <p>When the actual bizobj structure is generated from a SCS feature xml, then there should be a good
	* understanding of what objects are contained within the structure.</p>
	* @param {String} typeName The bizobj type name to create a new bizobj from.
	* @param {Object} bizObj A plain object that contains values that should be used to initialize the bizobj with.
	* This is particularly useful when getting data back as plain JSON and then using that to create bizobjs.
	*/
	create: function(typeName, bizObj) {
		if(bizObj == null)
			bizObj = {};
		
		var bizObjType = null;
		if(typeName)
			bizObjType = ksg.bizobj.bizObjTypes[typeName];
		
		var obj = bizObj;
		if("_type" in obj) {
			var _type = ksg.bizobj.bizObjTypes[obj["_type"]];
			if(_type)
				bizObjType = _type;
		}
		
		if(bizObjType)
			obj = new bizObjType(bizObj);

		return obj;
	},
	
	/**
	* Given a bizobj type name and a regular javascript array of objects such as that created from JSON,
	* this will create a bizobj list of the given type.
	* @param {String} typeName The bizobj type name to create a new bizobj list from.
	* @param {Object} bizObjs A plain javascript array of objects that contains values that should be used to 
	* initialize each bizobj in the list with.
	* This is particularly useful when getting data back as plain JSON and then using that to create bizobjs.
	*/
	createList: function(typeName, bizObjs) {
		var list = {
			bizObjs: bizObjs,
			typeName: typeName
		};
		list.prototype = ksg.bizobj.BizObjList;
		if(bizObjs)
			for(var i in bizObjs)
				bizObjs[i] = this.create(typeName, bizObjs[i]);
		
		return list;
	}
};/**
* @namespace
* namespace - Contains all items related to bizrules.
* @meta-type namespace
*/
ksg.bizrule = {
	//compoundBizRuleName: "compoundBizRule",
	/**
	* If your main service handlers support a compound web service call,
	* it can be named here and used for compound bizrule calls.  When null,
	* compound rule requests are just executed as normal within the context of
	* the overall compound rule start/complete calls.
	* <p>It is currently not possible to have different compound bizrule names
	* for different servers.</p>
	*/
	compoundBizRuleName: null,
	
	/**
	* @class
	* Contains the ruleName, arguments and handlers from a call to ksg.App.ruleMgr.execute.
	* Particularly used for compound bizrule call scenario.
	*/
	RuleCallInfo: function(ruleName, ruleArgs, onSuccess, onError) {
		this.ruleName = ruleName;
		this.ruleArgs = ruleArgs;
		this.onSuccess = onSuccess;
		this.onError = onError;
	},
	/**
	* @namespace
	* Map - Contains all the registerd bizrule functions that can be executed via ksg.App.ruleMgr.
	*/
	bizRules: {
	}
};

/**
* @namespace The main access point for executing bizrules.
* <p>The ruleMgr implements a façade design pattern where by business rules are abstracted behind string names
* in order to allow specific implementations to be switched out dynamically.  This also allows for advanced bizrule
* call changing scenarios such as registering preExtends and postExtends handlers for a given bizrule.</p>
* @fieldOf ksg.App
* @importance high
* @meta-type static class
*/
ksg.App.ruleMgr = {
	_compoundRuleSet: null,
	
	
	/**
	* Main method to execute bizrules.  If the rule name cannot be found as a local bizrule in ksg.bizrule.bizRules
	* then this method will look for a web service in ksg.services with the same name.
	* <p>This method may or may not return before the rule has completed executing.  There should be no dependency that 
	* about when the rule will execute based on the return of this function.  The use on onSuccess/onError should
	* drive the next step in processing the results of the rule.</p>
	* @param {String} ruleName name of rule being executed.
	* @param {Object} ruleArgsObj object contained name/value pairs for the parameters needed in the bizrule call. 
	* @param {function} onSuccess callback function that will be called when the rule has completed successfully.
	* @param {function} onError callback function that will be called if the rule fails to execute properly.
	*/
	execute: function(ruleName, ruleArgsObj, onSuccess, onError) {
		if(ruleArgsObj==null)
			ruleArgsObj={};
		if(this._compoundRuleSet) {
			this._compoundRuleSet.push(new ksg.bizrule.RuleCallInfo(ruleName, ruleArgsObj, onSuccess, onError));
		}
		else {
			var rule = ksg.bizrule.bizRules[ruleName];
			try {
				if(rule) {
					rule(ruleArgsObj, onSuccess, onError);
				}
				else {
					//If no local rule is provided, try to find ruleName as web service.
					var service = ksg.services[ruleName];
					if(service) {
						var ruleArgs = [ruleArgsObj, onSuccess, onError];
						service.apply(ksg.services,ruleArgs);
					}
					else if(onError)
						onError(new ksg.BaseException("ksg-unknown-bizrule", "ksg.App.ruleMgr.execute", {ruleName: ruleName}));
				}
			}
			catch(e) {
			}
		}
	},
	
	/**
	* Causes bizrule calls made through the execute methods to be queued up rather than be executed at that moment.
	* <p>This is an important process for managing many different web services requests to the same web server.
	* When a page has several different bizprocs on it, each making requests plus widgets making requests for templates,
	* there can be many requests going to the web server, which will be queued by the browser, causing a ping-pong effect.
	* When this method is called,all calls to execute bizrules are actually queued in the ruleMgr and not executed immediately.
	* When the completeCompoundRuleSet is
	* called, the rules can be called in one compound rule call that contains all the service names and parameters, which
	* is handled on the server and the results are all sent back on one response.</p>
	*/
	startCompoundRuleSet: function() {
		this._compoundRuleSet = [];
	},
	
	/**
	* Causes the bizrule calls queued up since the last call to startCompoundRuleSet to be executed in one common
	* compound bizrule call per unique server url.  If only one server url is used for all rules executed, then only
	* one service call to that server will be made with all the bizrule calls made in the ruleSet passed as parameters.
	* <p>Note that, if the server doesnt support a compound service call, this method will fall back on calling each
	* bizrule one at a time like they would have been without compound rules.  However, there is still value because
	* the onAllComplete callback can be used to know when all the various async bizrules have completed.</p>
	* @param {function} onAllComplete Will be called once all the bizrules within the compound ruleset have completed.
	*/
	completeCompoundRuleSet: function(onAllComplete) {
		var ruleMgr = this;
		if(ksg.bizrule.compoundBizRuleName) {
			var ruleArgs = ruleMgr._buildCompoundParams();
			ruleMgr._compoundRuleSet = null;	
			ruleMgr.execute(ksg.bizrule.compoundBizRuleName, ruleArgs, onSuccess, onError);
		}
		else {
			var rules = ruleMgr._compoundRuleSet;
			var remainingCalls = rules.length;
			var callRule=function(rule) {
				ruleMgr.execute(rule.ruleName, rule.ruleArgs, 
				function(results) {
					try {
						rule.onSuccess(results);
					}catch(e) {
					}
					if(--remainingCalls == 0 && onAllComplete)
						onAllComplete();
				},
				function() {
					try {
						rule.onError.apply(rule, Array.prototype.slice.call(arguments, 0));
					}catch(e) {
					}
					if(--remainingCalls == 0 && onAllComplete)
						onAllComplete();
				});
			};
			ruleMgr._compoundRuleSet = null;			
			if(rules.length == 0)
				onAllComplete();
			else
				for(var i in rules) 
					callRule(rules[i]);
		}
	},
	
	/**
	* Will setup the parameters needed for the compound bizrule call.  This code will go thorugh
	* the bizrules in the call queue and create one single set of parameters from it for the single 
	* compound bizrule call.
	* <p>Warning: This method is not properly implemented and should be evaluated again during deep
	* testing with a compound bizrule call.</p>
	*/
	_buildCompoundParams: function() {
		return this._compoundRuleSet;
	}
};/**	
* @namespace
* Coordinates the general app framework config options with config partners that use them to properly
* startup when the page is first loaded.
* @Depends ksg.App.js
* @meta-type static class
*/
ksg.App.configMgr = {
	/**
	* The array of registered config parters, which is populated by calling the
	* registerConfigParner method.
	*/
	_configPartners: [],
	
	/**
	* If a feature needs to have options passed to it in order to properly startup when a page is first loaded,
	* it should register as a config patner.
	* <p>When the startup process calls the ksg.App.configMgr.init method, the config partners are called
	* and given the options from the page.</p>
	* @param {ksg.config.IConfigPartner} partner An object that implements the IConfigPartner interface.
	*/
	registerConfigPartner: function(partner) {
		this._configPartners.push(partner);
	},
	
	/**
	* Call during page startup to properly handle startup of various items, such as config partners.
	* <p>This is typically called by the ksgSetupUI jQuery plugin that initializes everything on the page.
	* @param {Object} options The options passed in from the page startup code.
	*/
	init: function(options) {
		for(var i in this._configPartners) {
			try {
				var results = this._configPartners[i](options);
				//TODO check for partner failure.
			}
			catch(e) {
				//TODO do something about exception during partner config init.
			}
		}
	}
};
/**
* @class
* An observer for an action trigger event can have a handler for before the action is triggered
* and after the action has completed being triggered.
* <p>This is passed to the ksg.ui.bizProcMgr.addActionTriggerObserver method and can just be create as
* an anonymous object that has the started or completed functions in it.  Neither handler is required.</p>
* @Depends ksg.base.ui.js
*/
ksg.ui.ActionTriggerObserver = {
	/**
	* Called just before the bizproc(s) action is called.
	* @param {String} actionStr the action bizprocId.actionName comma delimited list of actions being triggered.
	*/
	started: function(actionStr) {},
	/**
	* Called just after the bizproc(s) action has been called.
	* @param {String} actionStr the action bizprocId.actionName comma delimited list of actions being triggered.
	*/
	completed: function(actionStr) {}
};/**
* @class Provides the core bizproc behavior, intended to be overriden by child bizproc classes.
*
* The details for child bizproc inheritence in javascript is a bit different than other patterns
* for inheritence.  A bizproc facatory method will create an instance of this class, passing in the
* child class as a parameter.  The BizProc constructor will set itself up and then blend in the child
* methods and data elements using $.extend.
<pre>
&lt;div class="ksg-bizproc ksg-bizproc-articleManagement" id="art1" 
	data-options='{"editModeSessionKey":"GlobalEdit"}'
	data-art-options='{"id":"", "details": "basicDetails", "includeCounts": true, "entireTree": true}'&gt;
&lt;/div&gt;		
</pre>
*
* @Depends ksg.base.ui.js
* @meta-type abstract base class
* @importance high

* @param {String} id The unique identifier relative to the overall page hosting this bizproc.
* @param {Object} dataParams the various parameters supplied to create the bizproc.
* <p>When this is provided by the ksg-bizproc class being attached to a DOM element, this
* is created from all the data-[name] elements defined on the DOM element.</p>
* @param {Object} childBizProc A plain object that contains methods and properties to be blended into
* the new bizproc object being created.
*/
ksg.ui.BizProc = function(id, dataParams, childBizProc) {
	this.id = id;
	this.options = dataParams.options;
	this.parentBizProcs = dataParams["parent-bizprocs"];
	
	/**
	* Keeps track of how far this bizproc has gotten in getting its initial data shown from since it was first created.
	* Values: 0=no init. 1=startedGettingData. 2=Done getting initial data.
	* @type integer
	* @private
	*/
	this.initState = 0;
	
	//#Paging support ---
	/**
	* Keeps track of the current page when the bizobj list is being paged by the list displayers.
	* @type integer
	* @private
	*/
	this.currentPage = 0;
	//#
	
	/**
	* Flag to track if we have attempted to retrieve the bizobj list from the source.
	* @type boolean
	* @private
	*/
	this.retrievedBizObjList = false;
	/**
	* Flag to track if we have attempted to retrieve the current bizobj details from the source.
	* @type boolean
	* @private
	*/
	this.retrievedCurrentBizObj	= false;
	
	/**
	* When the add bizobj action is triggered, a new instances of the bizobj type is created and
	* put here while it is being edited.  This helps to indicate to other logic that we are in add mode.
	* @type ksg.bizobj.IBizObj
	* @private
	*/
	this.inProgressAddBizObj = null;
	
	/**
	* The id of the current bizobj.
	* @type Object
	* @private
	*/
	this.currentBizObjId = null;
	
	/**
	* The fully populated selected bizobj.  This is typically set by calling the getBizObjBizRule, but
	* could also come from the bizobj list directly if getBizObjBizRule is not set.
	* @type ksg.bizobj.IBizObj
	* @private
	*/
	this.currentBizObj = null;
	
	/**
	* Used to keep track of the main list of bizobjs as well as current index for the selected bizobj.
	* When the move next/prev first/last actions are used, this is the data member that keeps track of that state.
	* @type ksg.bizobj.BizObjCursor
	* @private
	*/
	this.bizObjCur = null;
	
	/**
	* The collection of bizrule names used by the bizproc to interact with the middle tier.
	* The rules defined at this level are those know to the base BizProc class, but
	* child classes can add other bizrule names to call in here.
	* <ul>
	*	<li>getBizObjListBizRule - the bizrule to get the list of bizobjs being used</li>
	*	<li>getBizObjBizRule - the bizrule to get the details of one bizobj</li>
	*	<li>getMasterBizObjListBizRule - the bizrule to get the master list of all bizobjs related to this bizproc.</li>
	* 	<li>updateBizRule - the bizrule to update a single bizobj</li>
	*	<li>deleteBizRule - the bizrule to delete a single bizobj</li>
	* </ul>
	*
	* @type Map<String, String>
	* @private
	*/
	this.bizRules = {
		/**
		* A bizrule that takes an options Map and returns an IBizObjList
		*/
		getBizObjListBizRule: null,
		getBizObjBizRule: null,
		getMasterBizObjListBizRule: null,
		
		updateBizRule: null,
		deleteBizRule: null,		
		bulkUpdateBizRule: null		
	};
	
	var self = this;
	this.actions = {};
	
	this._addAction(new ksg.ui.Action("SwitchEdit", function() {self._switchEditMode();}));
	
	this._addAction(new ksg.ui.Action("AddBizObj", function() {self._addBizObj();}));
	this._addAction(new ksg.ui.Action("UpdateBizObj", function() {self._updateBizObj();}));
	this._addAction(new ksg.ui.Action("DeleteBizObj", function() {self._deleteCurrentBizObj();}));
	this._addAction(new ksg.ui.Action("CancelEdits", function() {self._cancelEdits();}));
	
	//#Indexing Support ---
	this._addAction(new ksg.ui.Action("MoveFirst", function() {self._moveFirst();}));
	this._addAction(new ksg.ui.Action("MovePrev", function() {self._movePrev();}));
	this._addAction(new ksg.ui.Action("MoveNext", function() {self._moveNext();}));
	this._addAction(new ksg.ui.Action("MoveLast", function() {self._moveLast();}));
	//#
	
	//Blend in the child bizproc methods and values into this.
	$.extend(true, this, childBizProc); 
	
	this._setupActions();
	
	ksg.App.bizProcMgr.registerBizProc(this);
}

//The base bizproc prototype methods.
ksg.ui.BizProc.prototype = {	
	/**
	* If the main bizobj's keyvalue field name is not the default value set here, the
	* child bizproc should override this with the proper field name to be used.
	* @type String
	*/
	_keyName: "id" ,
	/**
	* Returns the key name of the bizobj used for its unique id.
	* @returns {String}
	*/
	getKeyName: function() {return this._keyName;},

	/**
	* The main entrypoint for getting the bizproc to retrieve its data (if needed) and show it in its list and 
	* detail displays.  This method is typically called by the bizproc manager.
	*/
	showData: function() {
		var self = this;
		var listDisplays = this._getListDisplays();
		var bizObjs = null;
		
		//This is only relevant during initialization.  Once initState reaches two and further calls to show data happen, nothing changes for this variable.
		//Helps the bizproc manager know if a given bizproc has been initialized yet.
		if(self.initState==0)
			self.initState = 1;
		
		//Get the list displays and have them show the bizobj list retrieved from getSourceBizObjs.
		if(listDisplays.length > 0) {
			self.getSourceBizObjs(function(bizObjs) {
				var cur = self._setupCursor(bizObjs, listDisplays);
				
				var editPriv = self.CanEdit() ? self.CurrentEditPrivilege() :
								self.CurrentEditPrivilege() == ksg.security.Privileges.None ? 
								ksg.security.Privileges.None : ksg.security.Privileges.ReadOnly;
				for(var i in listDisplays) {
					var listDisp = listDisplays[i];
					listDisp.setEditPrivilege(editPriv);	
					self._showBizObjListInDisplay(listDisp, cur);	
				}
				self._showBizObjDetails();
			});
		}
		else
			this._showBizObjDetails();
	},

	/**
	* Given a relationship id, will search all of its parent bizprocs looking for a relationship
	* that matches the provided id and if found returns the value from the relationship.
	* @param {String} relationshipId the unique identifier used to define the relationship between this bizproc
	* and a parent bizproc.
	* @returns {Object} the value from the parent bizproc or null if the parent could not be found or 
	* hasnt had it data setup yet.
	*/
	_getParentBizProcValue: function(relationshipId) {
		var parents = this.parentBizProcs;
		if(parents)
			for(var i in parents) {
				if(parents[i].id == relationshipId) {
					var bizProc = ksg.App.bizProcMgr.getBizProc(parents[i].bizProcId);
					if(bizProc) {
						var parentBizObj = bizProc.getCurrentBizObj();
						if(parentBizObj != null)
							return parentBizObj[parents[i].fieldName];
					}
				}
			}
	},
	
	/**
	* A bizproc is not ready to get its own data if it has parent bizprocs that have not gotten their
	* data yet.  This method will check to see if it has not yet been initialized and also if all its parents
	* have gotten their data yet.
	*
	* The only way this method will return true is if this object has not been initialized, and all parent
	* bizprocs have already been initialized.
	*/
	isReadyToGetInitialData: function() {
		//starts at 2 to assume all parent bizprocs have their data already.
		//IF a parent has less than a 2 for their initState, the readyState is adjusted down.
		var readyState = 2;
		var parents = this.parentBizProcs;
		if(parents)
			for(var i in parents) {
				var parent = ksg.App.bizProcMgr.getBizProc(parents[i].bizProcId);
				if(parent.initState < readyState) {
					readyState = parent.initState;
					break;
				}
			}
				
		return this.initState == 0 && readyState == 2;
	},
	
	/**
	* Primarily called by showData, Sets up a bizobjlist cursor based on the bizObjs provided.
	* Positions cursor to first bizobj that should be displayed in first list.
	*
	* Expects bizObjs to represent the full list of bizobjs, not just a single page of bizObjs.
	* Also sets up the pager controls if there are any, which indicates paging is being used.
	* @param {ksg.bizobj.IBizObjList} bizObjs the bizobjs to use for the cursor
	* @param {ksg.ui.IBizObjListDisplay[]} listDisplays The array of bizobj list displays that will be used to
	* calculate the page size with.
	*/
	_setupCursor: function(bizObjs, listDisplays) {
		var self = this;
		var cur = new ksg.bizobj.BizObjCursor(bizObjs);
		
		//#Paging support ---
		var pagers = self._getPagerDisplays();
		if(pagers) {
			var pagesize = self._calculateMaxBizObjsShown(listDisplays);
			for(var pager in pagers)
				pager.setupPagination(bizObjs.length, pagesize, self.currentPage);

			cur.moveTo(self.currentPage * pagesize);
		}
		//#
		
		return cur;
	},
	
	/**
	* Called during the showData process, this first starts the async process of getting the current
	* bizobj details and then showing the bizobj in the bizproc detail displays.
	*/
	_showBizObjDetails: function() {
		var self = this;

		var detailDisplays = self._getDetailDisplays();
		self.getCurrentBizObj(function(bizObj) {
			if(bizObj == null)
				bizObj = self.createNewBizObj();
				
			//This if statement is designed to prevent the display of a bizobj from being different from that
			//set as the currentBizObjId.  This can happen when the user is rapidly moving through the list of
			//bizobjs.  Getting the details for a bizobj is async, and multiple requests for setting the current
			//bizobj can cause many requests to be made and come in async.
			if(bizObj[self._keyName] == self.currentBizObjId)
				for(var i in detailDisplays)
					self._showBizObjInDisplay(detailDisplays[i], bizObj);
		});
		
		self._updateActionState();
	},
	
	/**
	* Returns the current state of if the user is able to edit at this moment.  This is not the same as asking
	* if the user is authorized to edit.  If the bizproc is a part of the global edit mode and that edit mode is off, 
	* then the user cannot edit until edit mode is on again.
	*
	* @returns {boolean}
	*/
	CanEdit: function() {
		var e = this.CurrentEditPrivilege() >= ksg.security.Privileges.EditOnly;
		if (e && this.UsingEditModeForEdits())
			e = ksg.App.SessionData()[this.options.editModeSessionKey]==true;
		return e;		
	},
	
	/**
	* The edit privilege of the user at the time. 
	* Child bizproc should override this method to calculate the privilege based on currentUser
	* and what security app function the bizproc wants to use for its security access.
	* @returns {ksg.security.Privileges} The security privilege the bizproc is using to determin its behavior.
	*/
	CurrentEditPrivilege: function() {
		return ksg.security.Privileges.None;
	},
	
	/**
	* Checks to see if the editModeSessionKey option is set.
	* @returns {boolean} True if the bizproc is configured with a editModeSessionKey
	*/
	UsingEditModeForEdits: function() {
		return this.options.editModeSessionKey && this.options.editModeSessionKey.length > 0;
	},
	
	/**
	* Not implemented yet, but should be.
	* @returns {ksg.ui.MasterDataOption}
	*/
	MasterDataOption: function() {
	},
		
	/**
	* When something happens that invalidates the data held by the bizproc, this will 
	* clear out the cached data so that when calls to ksg.ui.BizProc.getCurrentBizObj and
	* ksg.ui.BizProc.getSourceBizObjs happen again, they will see there is no cached data
	* and retrieve the bizobj list or detailed bizobj again when its needed.
	* @param {Boolean} clearBizObj set to true if the current bizobj should be cleared out.
	* @param {Boolean} clearBizObjList set to true if the source bizobj list should be cleared out.
	* @param {Boolean} includeCurrentBizObjId set to true if the currently selected bizobj id should
	* also be cleared out, causing the bizproc to have to calculate what the selected bizobj should
	* be the next time it's showData method is called.
	*/
	clearData: function(clearBizObj, clearBizObjList, includeCurrentBizObjId) {
		if(clearBizObj == true) {
			if(includeCurrentBizObjId != false)
				this.currentBizObjId = null;
			this.currentBizObj = null;
			this.retrievedCurrentBizObj = false;
		}
		if(clearBizObjList == true) {
			this.bizObjCur = null;
			this.retrievedBizObjList = false;
		}
	},
	
	/**
	* Typically called by the bizproc's bizObjList displays when a user
	* selects a bizobj in its display, but can also be used by any javascript that has a valid
	* id to set as the current selected bizobj.
	* @param {Object} bizObjId The unique identifier to use for the current bizobj
	* @param {Boolean} dontSetIndex optional - if false will not try to set the index from the given id.
	* This is provided when the cursor is being moved and is already set.
	*/
	selectBizObj: function(bizObjId, dontSetIndex) {
		var self = this;
		ksg.App.bizProcMgr.bizObjSelected(self, bizObjId, function() {
			self.clearData(true,false);
			self._setSelectedBizObjId(bizObjId);
			
			//#Indexing Support ---
			if(dontSetIndex != true) 
				self._setIndexFromBizObjId(bizObjId);
			//#
			
			self._showBizObjDetails();		
		});
	},
	
	/**
	* Iterates through each of associated bizobj list displays and asks it to try and select the given
	* id.  This is an internal helper method intended to make sure the list displays are showing the selected
	* bizobj, it is not intended to be the primary method for selecting a bizobj based on its id.
	* @param {Object} bizObjId the unique identifier of the bizobj that is to be setup as selected for.
	*/
	_setSelectedBizObjId: function(bizObjId) {
		this.currentBizObjId = bizObjId;
		var listDisplays = this._getListDisplays();
		if(listDisplays)
			for(var i in listDisplays)
				listDisplays[i].setSelectedBizObjKeyValue(bizObjId);
	},
	
	//#Indexing Support ---
	/**
	* Maintains the current selected index when the current bizobj is changed to some 
	* random location.  This helps to ensure that the move next/prev actions have their state
	* managed properly.  If someone clicks on the last item in the bizobj list, then the move next
	* action should be disabled.  This method does not manage the action state, it only moves
	* the internal ksg.bizobj.BizObjCursor object position.
	* @param {Object} bizObjId the unique identifier for the bizobj that the index should be set with.
	*/
	_setIndexFromBizObjId: function(bizObjId) {
		if(this.bizObjCur) {
			var bizObjs = this.bizObjCur.bizObjs;
			for(var i = 0; i < bizObjs.length; i++)
				if(bizObjs[i][this._keyName] == bizObjId) {
					this.bizObjCur.moveTo(i);
					return;
				}
		}
	},
	//#
	
	/**
	* Called internally when showing the bizobj list in its views, this method will simply
	* tell the display to show the data.
	* This is a good method to override in a child bizproc if you need to change the way in which
	* data is driven into a list display.
	* @param {ksg.ui.IBizObjListDisplay} listDisp The bizobj list display to show the list in.
	* @param {ksg.bizobj.BizObjCursor} cur The bizobj list cursor to use.
	*/
	_showBizObjListInDisplay: function(listDisp, cur) {
		if (listDisp.DrivenByBizProc())
		{
			listDisp.setSelectedBizObjKeyValue(this.getCurrentBizObjKeyValue());
			listDisp.showBizObjs(this, cur);
		}
	},
		
	/**
	* Calculates what the current bizobj key value is, which can be somewhat involved to come up with, 
	* especially if the user has yet to actually select a current bizobj or if there are no bizobjs in the list.
	* @returns {Object} The current bizobj id value or null if there is no current bizobj.
	*/
	getCurrentBizObjKeyValue: function() {
		var bizObjId = this.currentBizObjId;
		var bizObj = this.currentBizObj;
		if(bizObj)
			bizObjId = bizObj[this._keyName];
			
		if(!(bizObjId)) {
			var bizObjs = this.getSourceBizObjs();
			if (this.getCanDefaultToFirstInList() && bizObjs && bizObjs.length) {
				bizObjId = bizObjs[0][this._keyName];
				//#Indexing Support ---
				this.bizObjCur.moveTo(0);
				//#
			}
		}
		
		if(!(bizObjId)) {
			//TODO: check list display to see if they have current id from having content
			//embedded in them.  There is a chance that there was no bizobj list retrieved
			//because the bizobj list displays are prepopulated with content when the page was
			//rendered in the server.  If we need to know the "current bizobj id" and yet we dont
			//have it set from one being selected, we would need to ask the first bizobj list display
			//what their first bizobj's id value is.
		}
		
		if(bizObjId)
			this._setSelectedBizObjId(bizObjId);
		
		return bizObjId;
	},
	
	/**
	* Will get the current list of bizobjs if cached, or if passed a function for onSuccess,
	* this will call _getBizObjs to kick of the bizrule call to get the bizobj list.
	* @param {function} onSuccess optional - The handler to use if the bizrule has to be called
	* to get the bizobj list.  This will always be called if provided, even if the bizobj list
	* is already in memory.
	* @returns {ksg.bizobj.IBizObjList} If the bizobj list isnt cached, this will return null.
	*/
	getSourceBizObjs: function(onSuccess) {
		var self = this;
		var bizObjs = self.bizObjCur?self.bizObjCur.bizObjs:null;
		if(!(bizObjs) && onSuccess)
			self._getBizObjs(onSuccess);
		else if(onSuccess)
			onSuccess(bizObjs);		
		return bizObjs;
	},
	
	/**
	* This is an important method for child bizprocs to override in order to create any custom Action objects
	* it may need when first being created.
	* This method has no implementation in ksg.ui.BizProc, but is called for the child bizproc to setup
	* custom actions.  If you have no custom Actions for the child BizProc, you dont need to override this method.
	*/
	_setupActions: function() {
	//Intentionally left blank for child bizproc to override.
	},
	
	/**
	* Adds the given action into the collection of actions used by the bizproc.
	* @param {ksg.ui.Action} action The action to add.
	*/
	_addAction: function(action) {
		this.actions[action.id.toLowerCase()] = action;
	},
	
	/**
	* Access to a given action based on its id.
	* @param {String} actionId the id of the action to get
	* @returns {ksg.ui.Action} The Action that matches the id or null if no match found.
	*/
	getAction: function(actionId) {
		return this.actions[actionId.toLowerCase()];
	},
		
	/**
	* Updates the state and availability of the bizproc's actions.  This method is called at various points
	* during in the bizproc processing, which drive action trigger widgets (such as if a given action is available for 
	* the user at the moment).
	* It is typical for a child bizproc to override this method if they have custom Actions to manage, or if the 
	* standard way in which the standard Actions are managed needs to be changed.
	*/
	_updateActionState: function() {
		var curPriv = this.CurrentEditPrivilege();
		var action = null;
		var isNew = this.inProgressAddBizObj != null;
		
		if(action = this.getAction("ClearFilterSort"))
			action.availability = FilterSortCriteria == null ? ksg.ui.Availability.None : ksg.ui.Availability.Enabled;

		if(action = this.getAction("SwitchEdit"))
			action.availability =
				curPriv >= ksg.security.Privileges.EditOnly ? ksg.ui.Availability.Enabled:ksg.ui.Availability.None;
				
		if(action = this.getAction("MasterDataOption"))
			action.availability = (this.MasterDataOption() > ksg.ui.MasterDataOption.None) ? ksg.ui.Availability.Enabled : ksg.ui.Availability.None;
			
		if (this.CanEdit()) {

			if(action = this.getAction("DeleteBizObj"))
				action.availability =
				(isNew || curPriv == ksg.security.Privileges.None) ? ksg.ui.Availability.None :
				(curPriv == ksg.security.Privileges.Delete) ? ksg.ui.Availability.Enabled : ksg.ui.Availability.Disabled;
				
			if(action = this.getAction("AddBizObj"))
				action.availability =
				(isNew || curPriv == ksg.security.Privileges.None) ? ksg.ui.Availability.None :
				(curPriv == ksg.security.Privileges.AddOnly || curPriv >= ksg.security.Privileges.Add) ? ksg.ui.Availability.Enabled : ksg.ui.Availability.Disabled;
				
			if(action = this.getAction("CancelEdits"))
				action.availability = isNew ? ksg.ui.Availability.Enabled : ksg.ui.Availability.None;

			if(action = this.getAction("UpdateBizObj"))
				action.availability =
				(curPriv == ksg.security.Privileges.None) ? ksg.ui.Availability.None :
				(curPriv >= ksg.security.Privileges.AddOnly) ? ksg.ui.Availability.Enabled : ActionAvailability.Disabled;
		}
		else {
			if(action = this.getAction("DeleteBizObj"))
				action.availability = ksg.ui.Availability.None;
			if(action =this.getAction("AddBizObj"))
				action.availability = ksg.ui.Availability.None;
			if(action = this.getAction("UpdateBizObj"))
				action.availability = ksg.ui.Availability.None;
			if(action = this.getAction("CancelEdits"))
				action.availability = ksg.ui.Availability.None;
		}
		
		//#Indexing Support ---
		if (this.retrievedBizObjList) {
			var cur = this.bizObjCur;
			var couldBeEnabled = cur.hasMoreThanOne() && !isNew;
			if(action = this.getAction("MoveToFirst")) 
				action.availability = couldBeEnabled ? (cur.isBOF() ? ksg.ui.Availability.Disabled : ksg.ui.Availability.Enabled) : ksg.ui.Availability.None;
			if(action = this.getAction("MoveToLast"))
				action.availability = couldBeEnabled ? (cur.isEOF() ? ksg.ui.Availability.Disabled : ksg.ui.Availability.Enabled) : ksg.ui.Availability.None;
			if(action = this.getAction("MoveNext"))
				action.availability = couldBeEnabled ? (cur.isEOF() ? ksg.ui.Availability.Disabled : ksg.ui.Availability.Enabled) : ksg.ui.Availability.None;
			if(action = this.getAction("MovePrev"))
				action.availability = couldBeEnabled ? (cur.isBOF() ? ksg.ui.Availability.Disabled : ksg.ui.Availability.Enabled) : ksg.ui.Availability.None;
		}
		//#
		
		//Give child bizprocs a chance to manage any additional action states.
		this._updateAdditionalActionStates();
		
		//After setting up the state of our actions, we need to tell the action triggers to refresh their state.
		var actionTriggers = ksg.App.bizProcMgr.getBizProcWidgets(this.id, ksg.ui.BizProcWidgetType.ActionTrigger);
		for(var i in actionTriggers) {
			actionTriggers[i].setupStateFromActions();
		}
	},
	
	/**
	* A child bizproc should override this method if it just wants to manage the state of additional actions they manage,
	* or even want to change the state of the standard actions after they have had their state updated by the base bizproc.
	*/
	_updateAdditionalActionStates: function() {
		//Intentionally left blank.  This method is specifically for child bizprocs to override if needed.
	},
	
	/**
	* Given a bizobj and a detailDisplay, this method will setup the detailDisplay to be in the proper edit mode
	* and then tell it to display the given bizObj.
	* This is a good method for a child bizproc to override to add more behavior for when a bizobj is shown in a given display
	* or to change the way the bizobj is shown.
	* @param {ksg.ui.IBizObjDisplay} detailDisplay the display to show the bizobj in
	* @param {ksg.bizobj.IBizObj} bizObj the bizobj that will be used.
	*/
	_showBizObjInDisplay: function(detailDisplay, bizObj) {
		var currentEditPrivilege = this.CurrentEditPrivilege();
		detailDisplay.setEditPrivilege(this.CanEdit() ? currentEditPrivilege :
			currentEditPrivilege == ksg.security.Privileges.None ? ksg.security.Privileges.None : ksg.security.Privileges.ReadOnly);
			
		detailDisplay.displayBizObj(bizObj);
	},

	/**
	* Given the list of bizobj list displays, this method calculates the max number of bizobjs that are
	* going to be shown.
	* This is done by checking the max number of items each bizobj list display is setup to use and adding up 
	* that total.  If there are pager displays, this number is used to control how many pages of data there are as
	* this becomes the "page size" for the pager displays.
	* @param {ksg.ui.IBizObjListDisplay[]} listDisplays array of bizobj list displays being used by this bizproc. 
	* @returns {integer} -1 if all bizobjs will be shown, or the number of bizobjs shown.
	*/
	_calculateMaxBizObjsShown: function(listDisplays) {
		var numPerPage = 0;
		for (var i in listDisplays)	{
			try {
				var num = new Number(listDisplays[i].MaxElements());
				numPerPage += num;
			}
			catch(e) {
			}
		}
		return numPerPage;
	},
	
	/**
	* Calls ksg.App.bizProcMgr to find the child bizobj list displays for this bizproc.
	* The child bizobj list displays for a bizproc are never cached in the object.  Everytime
	* this method is called, the bizProcMgr is asked to create this list.
	*/
	_getListDisplays: function() {
		return ksg.App.bizProcMgr.getBizProcWidgets(this.id, ksg.ui.BizProcWidgetType.List);
	},

	/**
	* Calls ksg.App.bizProcMgr to find the child bizobj detaild displays for this bizproc.
	* The child bizobj detail displays for a bizproc are never cached in the object.  Everytime
	* this method is called, the bizProcMgr is asked to create this list.
	*/
	_getDetailDisplays: function() {
		return ksg.App.bizProcMgr.getBizProcWidgets(this.id, ksg.ui.BizProcWidgetType.Disp);
	},
	
	/**
	* If this bizproc has a complete dependency on another bizproc for its data, it wont use bizrules
	* to get its bizobj list
	*/
	_getCompletlyDependentParent: function() {
		return null;
	},
	
	//#Paging support ---
	/**
	* Calls ksg.App.bizProcMgr to find the child paging displays for this bizproc.
	* The pager displays for a bizproc are never cached in this object.  Everytime
	* this method is called, the bizProcMgr is asked to create the list.
	*/
	_getPagerDisplays: function() {
		return ksg.App.bizProcMgr.getBizProcWidgets(this.id, ksg.ui.BizProcWidgetType.Pager);
	},
	//#

	/**
	* Given a error object from calling a bizrule,t this method will create a message to be
	* given to the ksg.ui.messenger to deal with.
	* Child bizprocs should override this message when they know the bizrules they are calling can return
	* complex error information that needs to be packaged up for presentation to the user.
	* @param {ksg.ErrorInfo} errInfo details about an error that happened, which a message is needed for to display to the user.
	* @returns {String} The message to give to ksg.ui.messenger to display.
	*/
	_getErrorMsg: function(errInfo) {
		var msg = "unknown reason";
		if(errInfo && errInfo.displayText)
			msg = errInfo.displayText();
		else if(errInfo && errInfo.status)
			msg = "Web service failure(" + errInfo.status + "): " + errInfo.statusText + ":<br/>"+ errInfo.responseText;
		return msg;
	},
	
	/**
	* Protected method that does the work to get the bizobj list from where it is supposed to come from.
	* This method is not supposed to decide if its necessary to get the data, it just does the work.
	* @param {function} onSuccess handler that is called after the bizobj list is retrieved successfully.
	*/
	_getBizObjs: function(onSuccess) {
		var self = this;
		
		//If bizobj list is supposed to come from a parent bizproc 
		//(typically a bizobjlist field from the parent's selected bizobj),
		//Get the value from that rather than trying to use a bizrule.
		var depParent = this._getCompletlyDependentParent();
		if(depParent != null) {
			var bizObjs = depParent.getBizObjs();
			if(bizObjs) {
				onSuccess(this._setupBizObjList(bizObjs));
			}
			else {
				//TODO error, cannot get list from dependent parent.
			}
		}
		
		//If we are supposed to get the bizobj list from calling a bizrule, setup the call.
		else if(this.bizRules.getBizObjListBizRule) {
			var onError = function(errInfo) {
				ksg.ui.messenger.displayMessage(ksg.ui.messenger.levels.error,"Unable to successfully get bizobj list:<br/>" + self._getErrorMsg(errInfo));
				//todo: process rule call error here.
			};
			var newOnSuccess = function(results) {
				var bizObjs = results.response.bizObjs;
				if(!(bizObjs))
					bizObjs = [];
				onSuccess(self._setupBizObjList(bizObjs));				
			};
			ksg.App.ruleMgr.execute(this.bizRules.getBizObjListBizRule,
									this._getBizObjListRuleParameters(),
									newOnSuccess, onError);
		}
	},
	
	/**
	* Intended to be called only by the _getBizObjs method, this sets up the cursor and flag that we got the data.
	* This could have been an inner method to _getBizObjs but that would make it hard for a child bizproc to override 
	* the behavior here.
	* @param {ksg.bizobj.IBizObjList} bizObjs the bizobjs to use for the source bizobjs in this bizproc.
	*/
	_setupBizObjList: function(bizObjs) {
		if(!(bizObjs))
			bizObjs = [];
		this.bizObjCur = new ksg.bizobj.BizObjCursor(bizObjs);
		if(this.currentBizObjId)
			this._setIndexFromBizObjId(this.currentBizObjId);
		
		this.retrievedBizObjList = true;
		return bizObjs;
	},
	
	/**
	* Internal method that does the work of getting the bizobj details for the bizObjId provided.
	* This method doesnt attempt to decide if its the right time to doe the work, it will always try to:
	* <ol><li>See if it is a completely dependent child of another bizproc and get the bizobj from that</li>
	* <li>If a get detailed bizobj bizrule is provided, call the bizrule to get the details</li>
	* <li>Use the bizobj from the main source bizobj list if it can be found.</li>
	* </ol>
	* @param {Object} bizObjId the id of the bizobj to get the details for
	* @param {function} onSuccess The handler that gets called when the bizrule completes successfully.
	* @param {function} onError The handler that gets called whent he bizrule has an error being called properly.
	* @param {Boolean} isCurrentBizObj if true, this can also setup the currentBizObj for the bizproc
	* when the bizobj is retrieved successfully.
	*/
	_getBizObjDetails: function(bizObjId, onSuccess, onError, isCurrentBizObj) {
		var self = this;
		//If bizobj is supposed to come from a parent bizproc 
		//(typically a bizobj field from the parent's selected bizobj),
		//Get the value from that rather than trying to use a bizrule.
		var depParent = self._getCompletlyDependentParent();
		if(depParent != null) {
			var bizObj = depParent.getBizObj();
			if(bizObj) {
				onSuccess(self._setupCurrentBizObj(bizObj,isCurrentBizObj));
			}
			else {
				//TODO error, cannot get list from dependent parent.
			}
		}
		
		//If we are supposed to get the bizobj list from calling a bizrule, setup the call.
		else if(self.bizRules.getBizObjBizRule) {
			var ruleParams = self._getBizObjDetailRuleParameters(bizObjId);
			if(self._shouldCallGetBizObjDetailsRule.call(self, ruleParams)) {
				var newOnError = function(errInfo) {
					ksg.ui.messenger.displayMessage(ksg.ui.messenger.levels.error,"Unable to successfully get bizobj detail:<br/>" + self._getErrorMsg(errInfo));
					//todo: process rule call error here.
					if(onError)
						onError();
				};
				var newOnSuccess = function(results) {
					var bizObj = self._setupCurrentBizObj(results.response,isCurrentBizObj);
					if(onSuccess)
						onSuccess(bizObj);
				};		
				ksg.App.ruleMgr.execute(self.bizRules.getBizObjBizRule, ruleParams,
					newOnSuccess, newOnError);
			}
		}
		else {
			var bizObj = self._getBizObjWithIdFromList(bizObjId);
			if(bizObj != null) {
				bizObj = self._setupCurrentBizObj(bizObj, isCurrentBizObj);
				onSuccess(bizObj);
			}				
		}
		
	},
	
	/**
	* Iterates through the current bizobj list, looking for the first bizobj that has the matching key value.
	* @param {Object} bizObjId a non-null unique identifier for the bizobj desired from the list.
	* @returns {ksg.bizobj.IBizObj} Will return null if there is no matching value
	*/
	_getBizObjWithIdFromList: function(bizObjId) {
		var self = this;
		var bizObj = null;
		if(self.bizObjCur != null)
			for(var i in self.bizObjCur.bizObjs) {
				var child = self.bizObjCur.bizObjs[i];
				if(child[self._keyName] == bizObjId) {
					bizObj = child;
					break;
				}
			}
		return bizObj;
	},
	
	/**
	* Intended to be called only by the _getBizObjDetails method, this sets up the currentBizOBj and flag that we got the data.
	* This could have been an inner method to _getBizObjDetails but that would make it hard for a child bizproc to override 
	* the behavior here.
	* The isCurrentBizObj param is an optional pass boolean that if true will actually just return the bizObj.  This is a helper
	* to reduce the amount of logic needed by _getBizObjDetails when it is used to get details of a bizobj that is not actually
	* being used to set the current bizobj.  That can happenen when outside logic wants to get the details of a bizobj for external use.
	* @param {ksg.bizobj.IBizObj} bizObj The bizobj to be used as the current bizobj.
	* @param {Boolean} isCurrentBizObj this is really a helper parameter for other methods calling this that just want to pass through
	* this method without having to use an if statement to have more complex logic.
	*/
	_setupCurrentBizObj: function(bizObj,isCurrentBizObj) {		
		if(isCurrentBizObj == true) {
			this.currentBizObj = bizObj;
			this.retrievedCurrentBizObj = true;
			if(this.initState == 1)
				this.initState = 2;
			ksg.App.bizProcMgr.bizProcDataAvailable(this, true);
		}
		return bizObj;
	},
	
	/**
	* <p>Will retrieve the current bizobj at the moment. If the bizproc has a getDetailedBizObj bizrule
	* the current bizobj is not already in this.currentBizObj, and onSuccess is passed a function,
	* this method will call the bizrule to get the details, calling onSuccess when the bizrule has
	* completed.</p>
	* <p>If onSuccess is null, this method will not attempt to call the bizrule if the detailed bizobj
	* is unavailable and will return null.
	* If the getDetailedBizObj bizrule is not defined, then the current bizobj will be pulled out of
	* the main list of bizobjs if there is one available.</p>
	* @param {function} onSuccess optional - The handler to call if the bizrule had to be called to get the
	* current bizobj.  However, if provided, this will always be called even if the bizobj is already in memory.
	* @param {function} onError optional - The handler to call if the bizrule had to be called to get
	* the current bizobj but there was an error doing so.
	* @returns the bizobj if available, or null if not currently available.
	*/
	getCurrentBizObj: function(onSuccess, onError) {
	
		var self = this;
		var bizObj = self.inProgressAddBizObj;
		if(!(bizObj)) {
			bizObj = self.currentBizObj;
			if(!self.retrievedCurrentBizObj && onSuccess) {
				self._getBizObjDetails(self.getCurrentBizObjKeyValue(), onSuccess, onError, true);
				return null;
			}
		}
		if(onSuccess)
			onSuccess(bizObj);			

		if(this.initState == 1)
			this.initState = 2;
			
		return bizObj;
	},
	
	/**
	* Will create a new instance of the type of bizobj being used by this bizproc.
	* This is typically used by the addNewBizObj Action.
	* Child bizproc can override this method to control how a new object is created.
	*/
	createNewBizObj: function() {
		return {};
	},
	
	/**
	* Returns an object of parameters to be passed to the bizrule to get the list of bizobjs
	* This is a common method for a child bizproc to override in order to properly gather
	* the parameters needed for the bizrule it is using.
	*/
	_getBizObjListRuleParameters: function() {
	},
	
	/**
	* Returns an object of parameters to be passed to the bizrule to get the details of a given bizobj id.
	* This is a common method for a child bizproc to override in order to properly gather
	* the parameters needed for the bizrule it is using.
	* The default behavior is to return an object with one key/value pair "id" with the id provided.
	* @param {Object} bizObjId The id of the bizobj to get the details for.
	* @returns {Object} A plain object as a Map of parameters to be passed.  This needs to match up
	* to the parameters the get bizobj detail bizrule expects to get.
	*/
	_getBizObjDetailRuleParameters: function(bizObjId) {
		return {id:bizObjId};
	},

	/**
	* Returns an object of parameters to be passed to the bizrule to update a given bizobj.
	* This is a common method for a child bizproc to override in order to properly gather
	* the parameters needed for the bizrule it is using.
	* The default behavior is to return the BizObj that is being updated.
	* @param {ksg.bizobj.IBizObj} bizObj The bizobj being updated
	* @returns {Object} The object of values needed by the given bizrule being used by the bizproc to update the bizobj.
	*/
	_getUpdateBizObjRuleParams: function(bizObj) {
		return bizObj;
	},
	
	/**
	* Returns an object of parameters to be passed to the bizrule to delete a bizobj based on the given id.
	* This is a common method for a child bizproc to override in order to properly gather
	* the parameters needed for the bizrule it is using.
	* The default behavior is to return an object with one key/value pair "id" with the id provided.
	* @param {Object} bizObjId the id of the bizobj to be deleted.
	* @returns {Object} The plain object as a Map of parameters to be passed.
	*/
	_getDeleteBizObjRuleParams: function(bizObjId) {
		return {id:bizObjId};
	},
	
	/**
	* Indicates if the bizproc can decide to use the first bizobj in the list of bizobjs as the selected bizobj
	* when the bizproc is first created and there is no passed id to use.
	* This is intended for a child bizproc to override and control.  Sometimes it is better to not have a selected
	* bizobj until the user specifically picks one and then this should be override to return false.
	* @returns {boolean} 
	*/
	getCanDefaultToFirstInList: function() {
		return true;
	},
	
	/**
	* The parent pizproc relationship id used to get a parent id if needed.
	* This is the standard value of "pid", but under rare situations, it may need to be a different name to 
	* avoid conflicts of some kind.
	* @type String
	*/
	_parentIdKeyName: "pid",
	
	/**
	* Called just before trying to call the bizrule to get the list of bizobjs when they are needed.
	* This method is a good choice for child bizproc to override and control the behavior.
	* If this method returns false, the bizrule will not be called, and the bizproc will behave
	* as if there were no items in the list.
	*/
	_shouldCallGetBizObjListRule: function() {
		var parents = this.parentBizProcs;
		if(parents)
			for(var i in parents)
				if(parents[i].id == this._parentIdKeyName)
					return (parentBizObjId)?true:false;
		return true;		
	},
	
	/**
	* Called just before trying to call the bizrule to get the details of a given bizobj.
	* This method is a good choice for child bizproc to override and control the behavior.
	* If this method returns false, the bizrule will not be called, and the bizproc will behave
	* as if there were no detailed bizobj.
	* @param {Object[]} ruleParams the array of parameters to be passed to the bizrule.
	*/
	_shouldCallGetBizObjDetailsRule: function(ruleParams) {
		var detailDisplays = this._getDetailDisplays();
		return (ruleParams && detailDisplays.length > 0);
	},
	
	/**
	* Called just before trying to call the bizrule to update a given bizobj.
	* This method is a good choice for child bizproc to override and control the behavior.
	* If this method returns false, the bizrule will not be called, and the bizobj will not
	* get updated.
	* @param {Object[]} ruleParams the array of parameters to be passed to the bizrule.
	*/
	_shouldCallUpdateBizObjRule: function(ruleParams) {
		return (ruleParams)?true:false;
	},
	
	/**
	* Called just before trying to call the bizrule to delete a bizobj with the given Id.
	* This method is a good choice for child bizproc to override and control the behavior.
	* If this method returns false, the bizrule will not be called, and the bizobj will not get deleted.
	* @param {Object[]} ruleParams the array of parameters that will be passed to the bizrule 
	*/
	_shouldCallDeleteBizObjRule: function(ruleParams) {
		return (ruleParams)?true:false;		
	},
	
	/**
	* BizProc Action - Will create a new bizobj and put the bizproc into an "add new mode".
	*/
	_addBizObj: function() {
		var newBizObj = this.createNewBizObj();
		var pinfo = this._getCompletlyDependentParent();
		if (pinfo != null) {
			//TODO Properly add new bizobj into parent's bizobj list.
			//SourceBizObjs.Add(newBizObj);
		}		
		
		this.inProgressAddBizObj = newBizObj;
		this._showBizObjDetails();
	},
	
	/**
	* Gets the bizobj that will be modified by the displays to gather the user's updates.
	* This could be the new bizobj if the user is in the add new mode or it could be
	* the current bizobj from calling the get bizobj details bizrule.  If there is not bizrule to
	* get the details, the bizobj from the main list of bizobjs is used.
	* @returns {ksg.bizobj.IBizObj} the bizobj to be updated, should never return null.
	*/
	_getBizObjToUpdate: function() {
		var self = this;
		if(self.options.updateIntoNewBizObj == true)
			return self.createNewBizObj();
		else
			return $.extend({},self.getCurrentBizObj());
	},
	
	/**
	* BizProc Action - Will update the current bizobj via the provided update bizrule.
	*/
	_updateBizObj: function() {
		var self = this;
		var bizObj = self._getBizObjToUpdate();
		var curBizObj = self.getCurrentBizObj();
		var detailDisplays = self._getDetailDisplays();
		if(detailDisplays) {
			for(var i in detailDisplays)
				detailDisplays[i].updateBizObj(bizObj);
			var b = self._getBizObjWithIdFromList(bizObj[self._keyName]);
			if(b != null)
			for(var i in detailDisplays)
				detailDisplays[i].updateBizObj(b);			
		}
		
		var clearShow = function() {
			if(self.options.refreshListOnUpdate)
				self.clearData(true, true, false);
			else if(self.options.updateIntoNewBizObj != true)
				self.clearData(true,false, false);				
			self.showData();
		};
		
		var ruleParams = self._getUpdateBizObjRuleParams(bizObj);
		if(self._shouldCallUpdateBizObjRule(ruleParams)) {
			var onError = function(errInfo) {
				clearShow();
				//TODO process rule call error here.
				ksg.ui.messenger.displayMessage(ksg.ui.messenger.levels.error,"Unable to successfully update:<br/>" + self._getErrorMsg(errInfo));
			};
			var onSuccess = function(results) {
				results = self._afterSuccessfulUpdate(results);
				$.extend(curBizObj, bizObj);
				ksg.ui.messenger.displayMessage(ksg.ui.messenger.levels.normal,"update successful");
				clearShow();
				//TODO trigger successfull update completed
			};
			ksg.App.ruleMgr.execute(self.bizRules.updateBizRule, ruleParams, onSuccess, onError);
		}
	},
	
	/**
	* Called during the _updateBizObj process, ksg.ui.BizProc calls this to give the child bizproc the chance
	* to modify the results from the bizrule before it is used.
	* @param {Object} results The bizrule return value from updating the bizobj.  The specific details of the
	* results are dependent on the bizrule being called.  This can be null if the bizrule didnt return a value.
	* @returns {Object} The results modified or not.
	*/
	_afterSuccessfulUpdate: function(results) {
		return results;
	},
	
	/**
	* BizProc Action - Will delete the currently selected bizobj.
	*/
	_deleteCurrentBizObj: function() {
		var self = this;
		var bizObjId = self.getCurrentBizObjKeyValue();
		if(self.bizRules.deleteBizRule) {
			var ruleParams = self._getDeleteBizObjRuleParams(bizObjId, self.getCurrentBizObj());
			if(self._shouldCallDeleteBizObjRule(ruleParams)) {
				var onError = function(errInfo) {
					ksg.ui.messenger.displayMessage(ksg.ui.messenger.levels.error,"Error while trying to delete bizobj:<br/>" + self._getErrorMsg(errInfo));
				};
				var onSuccess = function(results) {
					ksg.ui.messenger.displayMessage(ksg.ui.messenger.levels.normal,"delete successful");
					var bizObjs = self.getSourceBizObjs();
					for(var i = 0; i < bizObjs.length; i++)
						if(bizObjs[i][self._keyName] == bizObjId) {
							bizObjs.splice(i,1);
							self.bizObjCur = new ksg.bizobj.BizObjCursor(bizObjs);
							if(i >=bizObjs.length)
								i = bizObjs.length -1;
							if(i >= 0) {
								self.selectBizObj(bizObjs[i][self._keyName]);								
								self.showData();
							}
								
							break;
						}
				};
				ksg.App.ruleMgr.execute(self.bizRules.deleteBizRule, ruleParams, onSuccess, onError);			
			}
		}
	},
	
	/**
	* BizProc Action - Will cancel any edits made by the user and revert back. 
	* This is typically only shown when in "add mode" and will cancel the new bizobj and go back to showing the 
	* currently selected bizobj.
	*/
	_cancelEdits: function() {
		this._internalCancelEdits();
		this.inProgressAddBizObj = null;
		this.showData();
	},
	
	/**
	* Called by _cancelEdits, this is an easy method for child bizprocs to override in order
	* to do something as a part of _cancelEdits without having to override that method
	* and deal with ensureing the base functionality was called.  
	* <p>This method has no behavior in this class and if overriden by a child, the child doesnt need to 
	* call this method back.</p>
	*/
	_internalCancelEdits: function() {
		//Intentionally left blank.  This is specifically for child bizprocs to override
	},
	
	/**
	* BizProc Action - Will toggle the bizproc's edit mode, if it is using one.
	*/
	_switchEditMode: function() {
		var editModeKey = this.options.editModeSessionKey;
		var txt = editModeKey?ksg.App.SessionData()[editModeKey]:"always on editing";
		this._internalSwitchEditMode();
		if(this.options.refreshListOnEditToggle)
			this.clearData(true,true,false);
		this.showData();
	},
	
	/**
	* Called by _switchEditMode, this is an easy method for child bizprocs to override in order
	* to do something as a part of _swtichEditMode without having to override that method
	* and deal with ensureing the base functionality was called.  
	* <p>This method has no behavior in this class and if overriden by a child, the child doesnt need to 
	* call this method back.</p>
	*/
	_internalSwitchEditMode: function() {
		//Intentionally left blank.  This is specifically for child bizprocs to override
	},

	//#Indexing Support ---
	/**
	* BizProc Action - Will change the current bizobj to the first bizobj in the list.
	*/
	_moveFirst: function() {
		this._selCur(this.bizObjCur.moveFirst());
	},
	/**
	* BizProc Action - Will change the current bizobj to the previous bizobj in the list based on the current bizobj position.
	*/
	_movePrev: function() {
		this._selCur(this.bizObjCur.movePrev());
		ksg.ui.messenger.displayMessage(ksg.ui.messenger.levels.normal,"moved to previous item.");
	},
	/**
	* BizProc Action - Will change the current bizobj to the next bizobj in the list based on the current bizobj position.
	*/
	_moveNext: function() {
		this._selCur(this.bizObjCur.moveNext());
		ksg.ui.messenger.displayMessage(ksg.ui.messenger.levels.normal,"moved to next item.");
	},
	/**
	* BizProc Action - Will change the current bizobj to the last bizobj in the list.
	*/
	_moveLast: function() {
		this._selCur(this.bizObjCur.moveLast());
	},

	/**
	* Drives the internal ksg.bizobj.BizObjCursor to the specific index location of the bizObj
	* that was selected.
	* @param {ksg.bizobj.IBizObj} bizObj the bizobj to select based on the index cursor
	* being moved.
	*/
	_selCur: function(bizObj) {
		this.selectBizObj(bizObj[this._keyName], true);
	}
	//#
	
}
/**
* @class
* Contains the state for a bizproc's action and used by action trigger widgets to coordinate interation
* between the user and a bizproc.
*/
ksg.ui.Action = function(id, action) {
	this.id = id;
	this.availability = ksg.ui.Availability.NotSet;
	this.action = action;
	
	this.allowOpenParams = false;
	this.states = null;
	this.validParams = null;
	this.currentState = null;
}

ksg.ui.Action.prototype = {
	/**
	* Typically called by an action trigger ui widget like an action button, this method will call
	* the method on the bizproc if the action is available to trigger.
	* @param {Object} param An optional value to pass as the parameter for the action trigger event.
	* @returns {Boolean} true if any other Actions being trigger should also be triggered,
	* false if there is some reason to stop processing the other triggers.
	*/
	trigger: function(param) {
		if(this.action)
			return this.action(param);
		return true;
	},
	
	/**
	* A bizproc will set the action state with this method, which can be used by the action trigger ui widgets
	* to change their behavior.  Not all Actions need to have state, but a classic example is the play/pause
	* action.  When the bizproc is "playing" the state is play and the buttons could show an icon 
	* with a "pause" graphic.  When the user triggers the action, the bizproc would "pause" and the state would
	* change.  The buttons would then show a "play" graphic.
	* @param {String} state an id for the state.
	* @returns this
	*/
	setState: function(state) {
		this.currentState = state;
		return this;
	},
	
	/**
	* A bizproc will set the availability on its actions with this method which will drive the visual cues for
	* the action trigger ui elements, such as being disabled or display:none if needed.
	* @param {ksg.ui.Availability} availability The new availability level.
	* @returns this
	*/
	setAvailability: function(availability) {
		this.availability = availability;
		return this;
	},
	
	/**
	* If a bizproc has an action that has states, it will call this method with the currentState and the list of
	* possible states, which an action trigger ui element can use to drive its visual cues.  
	* @see ksg.ui.Action.setState for more info.
	* @param {String} currentState the id of the current state
	* @param {String[]} states array of possible state choices.
	* @returns this
	*/
	setupStates: function(currentState, states) {
		this.currentState = currentState;
		this.states = states;
		return this;
	},
	
	/**
	* An action may want to be trigger with a parameter, and if so, it will setup the parameter options with this method.
	* An example could be an action that took a true/false value, or even a drop down selector of values such as the months of the year,
	* such that when the user picked a month, it would trigger the action with that month as the parameter.
	* @param {Boolean} allowOpenParams If there are no hard set of valid parameters or if there are, but the user can still pass any value
	* then this should be true.  When true, triggering an action will allow any parameter to be passed and triggered.
	* @param {ksg.ui.ActionParameter[]} validParams The array of valid parameters if needed.
	* @returns this
	*/
	setupTriggerParams: function(allowOpenParams, validParams) {
		this.allowOpenParams = allowOpenParams;
		this.validParams = validParams;
		return this;
	}
};
/**
* @class
* Used in a bizproc action that has defined possible parameters the user can pick from to trigger the parameter.
* One typically usage scenario for this class is to show a dropdown action trigger widget for an action that
* has a defined set of parameters that can be passed.
*/
ksg.ui.ActionParameter = function(displayName, value) {
	this.displayName = displayName;
	this.value = value;
}
/**
* @namespace
* Coordinates the data dependency relationships between bizprocs on a page as well as to optimize the
* overall requests for data from multiple bizprocs and widgets to the same server at the same time.
* This include:
<ul>
 <li>Gathering a list of all the templates referenced by widgets defined at startup as well as initial
	  bizproc data requests from showData() calls and bundle them into one compound service call to help
     reduce the number of requests made to the server at startup, which can slow the overall time it takes
     for an initial page to render.</li>

 <li>When a bizproc action trigger happens, more than one bizproc may want to get data at the same time.
     These will be called together in one compound service call.</li>
</ul>
<p>Note that the ability to use compound bizrules is completely dependent on the server software
implementing the web services.  If the server doesnt support compound bizrules, the web service calls
will happen independently.</p>
* @Depends ksg.base.ui.js
* @meta-type static class
*/
ksg.App.bizProcMgr = {
	/**
	* Helps this class to decide if it should initialize a bizproc when it is registered with it rather than wait until
	* the page is being initialized.
	*/
	pageInitialized: false,
	
	/**
	* Controls if compound rule calls will be used or not.
	*/
	useCompoundCalls: true,
	
	widgets: [],
	bizProcs:[],
	triggerObservers: [],
	rulesetCallObservers: [],
	bizObjSelectedObservers: [],
	
	/**
	* Intended to be called once, at the startup of the page, which will properly coordinate
	* the initialization of the bizprocs and widgets. 
	* Will also coordinate the calls for webservices that can happen at the same time, such as:
	* <ul>
	*	<li>Get all first needed templates from common template server</li>
	*	<li>Inital data requests for data that are independent (no parent id relationship)</li>
	* </ul>
	* @param {Boolean} isPageInit only true once when the page is first being setup.
	*/
	findAndInitDomBizProcs: function(isPageInit) {
		var self = this;
		//Init BizProcs
		$(".ksg-bizproc").each(function() { 
			var $this = $(this);
			var classList =$this.attr('class').split(/\s+/);
			$.each(classList, function(){
				var cName = this.toString().substr(12); //class name we want starts with ksg-bizproc-, but factory doesnt use that part.
				if(ksg.ui.bizprocs[cName]) {
					if($this.data("_bpInit") != true) {
						$this.data("_bpInit", true);
				
						//This block of code is specifically to gather the data- elements and pass them in as plain objects
						var dataParams = {}, attrs = $this.get(0).attributes, attrName, d="data-";
						for (var i = 0; i < attrs.length; i++) {
							var attrib = attrs[i];
							if (attrib.specified == true && (attrName = attrib.name).substr(0,d.length)==d) {
								var partName = attrName.substr(d.length);
								dataParams[partName] = ksg.ui.getElementDataObject($this,partName);
							}
						}
						var dd = $this.data();
						//TODO is dd holds the same things as dataParams, skip the whole for loop above.
					
						ksg.ui.bizprocs[cName]($this.attr('id'), dataParams);
						return false;
					}
				}
			});
		});
		
		if(this.useCompoundCalls) {
			self._startCompoundRuleSet();
			
			if(isPageInit == true) {
				//TODO loop through the widgets and get their template info.  Setup a getTemplate rule call for all those templates
			}
		}
		
		//After looking for all ksg-bizproc elements, they should have self registered and now we can tell them
		//to show their data.
		var bizProcs = this.bizProcs;
		for(var i in bizProcs)
			if(bizProcs[i].isReadyToGetInitialData())
				bizProcs[i].showData();
		//---
		
		if(this.useCompoundCalls)
			ksg.App.ruleMgr.completeCompoundRuleSet(function() {
				self._rulesetCallCompleted();
			});
		
		pageInitialized = true;		
	},//pageInit
	
	
	/**
	* Called when a compound ruleset has completed, which then notifies the ruleset call observers
	* of that fact.
	*/
	_rulesetCallCompleted: function() {
		var observers = this.rulesetCallObservers;
		for(var i in observers)
			if(observers[i].completed)
				observers[i].completed();
	},
	
	/**
	* When the bizProcMgr is setup to use compound rule calls, it will use this to set the
	* ruleMgr to be in a compound rule call and to notify the ruleset call observers that
	* a compound ruleset has started.
	*/
	_startCompoundRuleSet: function() {
		ksg.App.ruleMgr.startCompoundRuleSet();
		var observers = this.rulesetCallObservers;
		for(var i in observers)
			if(observers[i].started)
				observers[i].started();
	},
	
	/**
	* All jQuery widgets that are also used as bizproc views should register themselves with
	* the bizProcMgr using this method.
	* <p>The best time to call this when writing a bizproc view using a jQuery UI Widget is in the _create 
	* method.</p>
	* @param {ksg.ui.IWidget} widget The jQuery widget that implements the IWidget interface.
	*/
	registerWidget: function(widget) {
		var widgets = this.widgets;
		for(var p = 0; p < widgets.length; p++)
			if(widget == widgets[p])
				return;
		widgets.push(widget);
	},
	
	/**
	* When a bizproc view is getting destroyed, it should call this to remove itself from
	* the bizProcMgr.
	* <p>The best time to call this when writing a bizproc view using a jQuery UI Widget is in the destroy
	* method.</p>
	* @param {ksg.ui.IWidget} widget The bizproc view that should be removed.
	*/
	unregisterWidget: function(widget) {
		var newWidgets = [];
		var widgets = this.widgets;
		for(var p = 0; p < widgets.length; p++)
			if(widget != widgets[p])
				newWidgets.push(widgets[p]);
		this.widgets = newWidgets;
	},
	
	/**
	* All bizproc objects on a page should register themselves with the bizproc coordinator.
	* @param {ksg.ui.BizProc} bizProc The bizproc being registered.
	*/
	registerBizProc: function(bizProc) {
		var bizProcs = this.bizProcs;
		for(var p = 0; p < bizProcs.length; p++)
			if(bizProc == bizProcs[p])
				return;
		bizProcs.push(bizProc);
		
		if(this.pageInitialized == true)
			bizProc.showData();
	},
	
	/**
	* Will add the given observer to its internal list, and will be notified
	* when actions are trigger on the page.
	* @param {ksg.ui.ActionTriggerObserver} observer The observer to add.
	*/
	addActionTriggerObserver: function(observer) {
		this.triggerObservers.push(observer);
		return this;
	},
	
	/**
	* Will add the given observer to its internal list, and will be notified
	* when the bizrules are being called by bizprocs from various scenarios occuring.
	* @param {ksg.ui.BizProcRuleCallObserver} observer The observer to add.
	*/
	addRulCallSetObserver: function(observer) {
		this.rulesetCallObservers.push(observer);
		return this;
	},
	
	/**
	* This is a way to register as a global observers of all bizproc having their bizobj being selected.
	* @param {function(bizProc, bizProcId)} observer the handler to get called when a select occurs.
	*/
	addBizObjSelectedObserver: function(observer) {
		this.bizObjSelectedObservers.push(observer);
		return this;
	},
	
	/**
	* It is important for a biproc to call this when it is getting destroyed so that there is not a build
	* up of dead bizprocs still being driven by the bizproc coordinator.
	* This is mostly an issue when a page is using templates which have bizproc elements defined in them
	* and as the user changes something (such as the selected bizobj) and the template changes, the bizprocs can 
	* be cleaned up as they are not getting used any more.
	* <p>This is one of the good reasons why a bizproc is defined like a widget on a dom element.  jQuery ui
	* already takes cares of calling its widget _create and destroy methods when their dom element is going away.
	* The bizproc should be using a mechanism like that to control life time.</p>
	* @param {ksg.ui.BizProc} bizProc the bizproc being unregistered.
	*/
	unregisterBizProc: function(bizProc) {
		var newBizProcs = [];
		var bizProcs = this.bizProcs;
		for(var p = 0; p < bizProcs.length; p++)
			if(bizProc != bizProcs[p])
				newBizProcs.push(bizProcs[p]);
		this.bizProcs = newBizProcs;
	},
	
	/**
	* Called by a bizproc when one of its bizobj was selected from one of its bizobj lists.
	* <p>This method helps to coordinate observers of this process being called as well 
	* as to allow compound bizrules to be used when this important type of event happens.</p>
	* @param {ksg.ui.BizProc} bizProc The bizproc calling this method.
	* @param {Object} bizObjId The id of the bizobj that was selected.
	* @param {function} handler The handler from the bizproc to actually do the work of selecting
	* the bizobj and showing it.
	*/
	bizObjSelected: function(bizProc, bizObjId, handler) {
		var self = this;
		for(var i in self.bizObjSelectedObservers)
			self.bizObjSelectedObservers[i](bizProc, bizObjId);
			
		if(self.useCompoundCalls)
			self._startCompoundRuleSet();
		
		handler();
	
		if(self.useCompoundCalls)
			ksg.App.ruleMgr.completeCompoundRuleSet(function() { 
				self._rulesetCallCompleted();
			});	
	},
	
	/**
	* When an "action trigger" ui widget is triggered (such as clicking a button or choosing an option in a select drop down).
	* and wants to have the bizproc actions get triggered, it should cal this method, which will help to coordinate
	* observers of an action event like this with the action itself.
	* <p>This method really just deals with managing the observers of an action trigger event, not the actual
	* calling of the bizproc action methods.  This is because the type of action widget may do that processing differently
	* so it is no something that can be done in here.</p>
	* @param {String} actionStr The comma delimited list of bizproc id.actionName to be trigger.
	* @param {function} handler The function that will do the work of actually triggering the bizproc actions.
	*/
	actionTriggered: function(actionStr, handler) {
		var self = this;
		for(var i in self.triggerObservers)
			if(self.triggerObservers[i].started)
				self.triggerObservers[i].started(actionStr);

		if(this.useCompoundCalls)
			self._startCompoundRuleSet();
		
		handler();
		
		if(this.useCompoundCalls)
			ksg.App.ruleMgr.completeCompoundRuleSet(function() { 
				self._rulesetCallCompleted();
				for(var i in self.triggerObservers)
					if(self.triggerObservers[i].completed)
						self.triggerObservers[i].completed(actionStr);
			});	
	},

	/**
	* Will build an array of bizproc widgets that match a given type.
	* @param {ksg.ui.BizProcWidgetType} widgetType the type of bizproc to filter with.
	* @param {String} bizProcId the id of the bizproc to get the widgets for.
	*/
	_getWidgets: function(widgetType, bizProcId) {
		var widgets = [];
		
		for(var i in this.widgets) {
			var widget = this.widgets[i];
			if(widget.getWidgetType() == widgetType && (!(bizProcId) || widget.getParentBizProcId() == bizProcId) )
				widgets.push(widget);
		}

		return widgets;
	},
	
	/**
	* A bizproc will use this method to get the list of bizproc widgets of a given type.
	* <p>The bizproc should never cache the list of widgets in a long term variable, but instead 
	* should use this method to get the active list at the moment.</p>
	* @param {String} bizProc Id The id of the bizProc to get the widgets for.
	* @param {ksg.ui.BizProcWidgetType} widgetType The type of widget that should be returned in the list.
	* @returns {array of ksg.ui.IWidget} An array of widgets that match, or an emptry array if none match.
	*/
	getBizProcWidgets: function(bizProcId, widgetType) {
		return this._getWidgets(widgetType,bizProcId);
	},
	
	/**
	* Will return the ksg.ui.BizProc object that has an id that matches
	* the provided id.
	* <p>No code should cache a bizproc object in a long term variable.  Rather,
	* they should cache the id, and use this method to find it.</p>
	* @param {String} bizProcId The id of the bizproc to find.
	* @returns {ksg.ui.BizProc} The bizproc with matching id, or null no bizobj has the given id.
	*/
	getBizProc: function(bizProcId) {
		var bizProcs = this.bizProcs;
		for(var i in bizProcs)
			if(bizProcs[i].id == bizProcId)
				return bizProcs[i];
		return null;
	},
	
	/**
	* When a bizproc's data changes in some way, it should call this method in order to allow
	* child bizprocs to be refresh as a result.  This is one of the core responsibilities of
	* the bizProcMgr.
	* @param {ksg.ui.BizProc} bizProc The bizproc that is calling this method.
	*/
	bizProcDataAvailable: function(bizProc) {
		var bizProcs = this.bizProcs;
		var isParentOf = 
			function(sourceBP) {
				var parents = sourceBP.parentBizProcs;
				if(parents)
					for(var i in parents)
						if(parents[i].bizProcId == bizProc.id)
							return true;
				return false;
			};
		
		for(var i in bizProcs) {
			if(isParentOf(bizProcs[i]) && (bizProcs[i].initState == 2 || bizProcs[i].isReadyToGetInitialData())) {
				bizProcs[i].clearData(true,true);
				bizProcs[i].showData();
			}
		}
	}
	
};

/**
* @class
* An observer for when a bizrules are being called during a bizproc event.
* <p>This is passed to the ksg.ui.bizProcMgr.addRulCallSetObserver method and can just be create as
* an anonymous object that has the started or completed functions in it.  Neither handler is required.</p>
* @Depends ksg.base.ui.js
*/
ksg.ui.BizProcRuleCallObserver = {
	/**
	* Called just before the various number of bizprocs start calling bizrules.
	*/
	started: function() {},
	/**
	* Called just after the bizrules called have actually completed and returned either successfully or not.
	*/
	completed: function() {}
};/**
* @namespace
* A common manager of messages meant to be displayed to the user.  This is a middleman class between
* code that generate messages for users to see and the ui widgets and other classes that deal with 
* the messages and possibly show them to the user in some way.
* @Depends ksg.base.ui.js
*/
ksg.ui.messenger = {
	/**
	* @namespace 
	* Each message to be displayed should be associated with a level to help determine how it
	* will be displayed to the user.
	* @meta-type enum
	*/
	levels: {
		/** */
		normal: 0,
		/** */
		warning: 1,
		/** */
		error: 2
	},
	_observers: [],
	
	/**
	* Observers are notified when a client calls a method to display a message or article.
	* Objservers are typically UI widgets that will decide if they should display the message to the 
	* user based on the level of the message.
	*/
	addObserver: function(observer) {
		this._observers.push(observer);
	},
	
	/**
	* Will trigger an event that a message was received.
	* @param {ksg.ui.messenger.levels} level The criticalness of the message being displayed.	
	*/
	displayMessage: function(level, text) {
		var msg = new ksg.ui.Message(level, text);
		for(var i in this._observers)
			this._observers[i](msg);
	},
	/**
	* @param {ksg.ui.messenger.levels} level The criticalness of the article being displayed.
	* @param {Map} replacements A map of values to use as macros to replace within the context of the message.
	*/
	displayArticle: function(level, text, replacements) {
	}	
};

/**
* @class
* Holds a message created by the user, and is sent to observers of the ksg.ui.messenger
* object when requested to display a message.
* @param {ksg.ui.messenger.levels} level The criticalness of the message.	
*/
ksg.ui.Message = function(level, text) {
	this.level = level;
	this.text = text;
}
ksg.ui.widgets.BaseWidget = {
	//--- IWidget
	_IWidget_construct: function() {
		this.editPrivilege = ksg.security.Privileges.None;
		ksg.App.bizProcMgr.registerWidget(this);
	},
	
	_IWidget_destruct: function() {
		ksg.App.bizProcMgr.unregisterWidget(this);
	},
	
	setEditPrivilege: function(privilege) {
		this.editPrivilege = privilege;
	},

	_getTemplateName: function() {
		var templateName = null;		
		//var templateSet = this.options.template;
		var templateSet = this.element.data("template");
		if(templateSet) {
			var editPrivilege = this.editPrivilege;
			var tsType = typeof(templateSet);
			if(tsType == "string")
				templateName = templateSet;
			else if(tsType == "object") {
				if(editPrivilege > ksg.security.Privileges.ReadOnly)
					templateName = templateSet["edit"];
				if(!(templateName) && editPrivilege >= ksg.security.Privileges.ReadOnly)
					templateName = templateSet["readOnly"];
			}
				
		}
		return templateName;
	},
	
	_findClassBeginingWith: function($el, className) {
		var remainingName = null;
		var classAttr = $el.attr('class');
		if(classAttr) {
			var classList = classAttr.split(/\s+/);
			$.each( classList, function(){
				if(this.length >= className.length && this.substr(0,className.length) == className) {
					remainingName = this.substr(className.length);
					return false;
				}				
			});
		}
		
		return remainingName;		
	},
	
	getParentBizProcId: function() {return this.options.bizProcId;}
	
}
/**
*
* @Depends ksg.baseWidget.js
*/
$.widget("ksg.actionTriggerSet", {
	_create: function() {
		var $this = this.element;
		
		$this.find(".ksg-actionButton").ksgSetupUI();
	}
});
ksg.ui.widgetMap["ksg-actionTriggerSet"] = function ($el, options) {
	$el.actionTriggerSet(options); 
};
/**
* @class
* Displays message inline to the DOM element it is atteched to when notified by ksg.ui.messenger that there is a message to display
* if the level provided is one of the levels listed in options.displayLevels.
* @meta-type jQuery widget
* @Depends ksg.baseWidget.js
*/
ksg.ui.widgets.InlineMessenger = {
	/**
	* The options used by this widget to control its behavior.
	* @field
	*/
	options: {
		/** Which message levels should this display show, all others are ignored. */
		displayLevels: [ksg.ui.messenger.levels.normal]
	},
	
	_create: function() { var self = this; var $this = this.element;
		
		ksg.ui.messenger.addObserver(function(msg) {
			if(self.options.displayLevels.indexOf(msg.level) != -1) {
				$this.html(msg.text);
				$this.effect("pulsate", {times:4}, "fast");
			}
		});
		ksg.App.bizProcMgr.addActionTriggerObserver({started: function() {
			$this.html("");
		}}).addBizObjSelectedObserver(function() {
			$this.html("");
		});		
	}
};
$.widget("ksg.inlineMessenger", ksg.ui.widgets.InlineMessenger);

ksg.ui.widgetMap["ksg-inlineMessenger"] = function ($el, options) {
	$el.inlineMessenger(options); 
};
/**
* @class
* A bizproc action trigger driven by a click event bound to the given dom element.
* This has the flexibility to be an anchor or a div that is turned into a jQuery UI button widget.
* This class maintains the css class state of the attached DOM element based on the state
* of the bizproc action.  This allows css to be applied to hide the button when the action is totally unavailable
* to the user or just disable it if the action is just currently not available.
<p>The main DOM element this is attached to will have the following css classes added/removed from it
based on the action state:</p>
<ul>
	<li>ksg-enabled</li>
	<li>cs-disabled - would typically cause the element to be grayed out in some way</li>
	<li>ksg-notAllowed - would typically cause the element to be hidden</li>
</ul>
<p>It is recommended that the DOM element be hidden by default so that the element isnt visible
until the jQuery widget has attached to it and been able to setup the class name.  Use ksg-enabled
to make the element visible.  This will keep buttons that should be hidden from being visisble as the page
is loading and then get hidden after the ksg-notAllowed class is added.</p>
<pre>&lt;div class="ksg-actionButton" data-actions='items.updateBizObj'&gt;Update&lt;/div&gt;</pre>
<p>This jQuery widget registers with the central widget factory using <b>ksg-actionButton</b>.</p>
<p>use the <b>data-actions</b> attribute to specify a comma delimited list of bizproc action names, which are formatted
as [bizProcId].[actionName].</p>
<p>This widget can be attached to:<p>
<ul>
	<li>&lt;a&gt; - Use an anchor.  If user disables javascript anchor href could actually be used as a fallback.</li>
	<li>&lt;div&gt; - Use a div, span, or other basic widget.</li>
</ul>
<p>You can also manually create the widget with javascript code similar to the following:</p>
<pre>
$("#myDisplayId").actionButton({
	actions: "items.updateBizObj"
});
</pre>
*
*
* @see ksg.ui.Action
* @see ksg.ui.BizProc
* @meta-type jQuery widget
* @Depends ksg.baseWidget.js
*/
ksg.ui.widgets.actionButton = {
	options: {
	},
	
	_create: function() { var self = this; var $this = this.element; var options = this.options;
		ksg.App.bizProcMgr.registerWidget(this);
		$this.bind('click', function(event) {
			var switchName = $this.data('switch');
			if(switchName) {
				var session = ksg.App.SessionData();
				var sw = session[switchName];
				session[switchName] = sw?false:true;
			}
			
			var actionStr = $this.data('actions'), actions = actionStr.split(/\s+/);
			ksg.App.bizProcMgr.actionTriggered(actionStr, function() {
				$.each(actions, function(){
					var actionParts = this.split('.');
					var bizProc = ksg.App.bizProcMgr.getBizProc(actionParts[0]);
					if(bizProc) {
						var action = bizProc.getAction(actionParts[1]);
						if(action && action.availability == ksg.ui.Availability.Enabled) {
							action.trigger();						
						}
						else {
							//alert("action disabled");
						}
					}
				});			
			});
		});
	},
	
	_firstBizProc: function() {
		var $this = this.element;
		var actions = $this.data('actions').split(/\s+/);
		var actionParts = actions[0].split('.');
		return ksg.App.bizProcMgr.getBizProc(actionParts[0]);
	},
	
	_getActionAvailability: function() {
		var $this = this.element;
		var availability = ksg.ui.Availability.None;
		
		var actions = $this.data('actions').split(/\s+/);
		var actionParts = actions[0].split('.');
		var bizProc = ksg.App.bizProcMgr.getBizProc(actionParts[0]);
		if(bizProc) {
			var action = bizProc.getAction(actionParts[1]);
			if(action)
				availability = action.availability;
		}
		
		return availability;
	},
	
	destroy: function() {
		ksg.App.bizProcMgr.unregisterWidget(this);
	},
	
	//--- The following are required IWidget interface methods
	getParentBizProcId: function() {
		var bizProc = this._firstBizProc();
		if(bizProc)
			return bizProc.id;
		return null;
	},	
	getWidgetType: function() {return ksg.ui.BizProcWidgetType.ActionTrigger;},
	
	//--- The following are required IActionTrigger interface methods
	getActions: function() {
		return this.options.actions;
	},
	
	setupStateFromActions: function() {
		var $this = this.element;
		var availability = this._getActionAvailability();
		
		if(availability == ksg.ui.Availability.Disabled) {
			$this.removeClass("ksg-notAllowed ksg-enabled").addClass("ksg-disabled");
			if($this.hasClass("ui-button"))
				$this.button("disable");
		}
		else if(availability == ksg.ui.Availability.Enabled) {
			$this.removeClass("ksg-notAllowed ksg-disabled").addClass("ksg-enabled");
			if($this.hasClass("ui-button"))
				$this.button("enable");
		}
		else
			$this.removeClass("ksg-disabled ksg-enabled").addClass("ksg-notAllowed");
	}
};

$.widget("ksg.actionButton", ksg.ui.widgets.actionButton);
ksg.ui.widgetMap["ksg-actionButton"] = function ($el, options) {
	$el.actionButton(options); 
};
/**
*/
(function ($) {
	$(window).load(function () {
	  ksg.ui.pageLoaded = true;
	});
    var methods = {
        init: function (options) {
            var $this = this;
			if(options == null)
				options = {};
            if(!ksg.ui._setupScripts) {
				if(options.useLocalScripts == null)
					options.useLocalScripts = true;
                ksg.ui._setupScripts = true;
				ksg.services.baseUrl = options.serviceUrl;
                methods._setupScripts.apply(this, [options, function() {
					ksg.App.configMgr.init(options);
                    methods._setupWidgets.apply($this, [options]);
					
					//Get the bizproc coordinator going
					ksg.App.bizProcMgr.findAndInitDomBizProcs(true);
                }]);
            }
			else
				methods._setupWidgets.apply($this, [options]);
			return this;
        },

		_remoteLightBoxBaseUrl: "http://scscode.syrinx.ph/fancybox/",
		
        _setupScripts: function(options, success) {
			var self = this, lightBoxBaseUrl = self._remoteLightBoxBaseURl;
            if(options.includeGoogleFonts) {
                var f = options.includeGoogleFonts;
                for(var i = 0; i < f.length; i++)
                    ksg.ui.loadCssUrl("http://fonts.googleapis.com/css?family=" + f[i]);
            }
                        
            //Right now fancybox is the default lightbox, but could be changed to anything in the future.
            if(options.includeLightBox) {
				if(options.useLocalScripts == true)
					lightBoxBaseUrl = "/js/fancybox/";

				ksg.ui.loadCssUrl(lightBoxBaseUrl+"jquery.fancybox-1.3.4.css");
				//ksg.ui.loadScriptUrl(lightBoxBaseUrl+"jquery.fancybox-1.3.4.pack.js", success);
				$(".ksg-image").fancybox();
				success();
            }
            else
                success();
        },

        _setupWidgets: function( options) {
            return this.each(function () {

                var $this = $(this),
                data = $this.data('autoOp');

                // If the plugin hasn't been initialized yet
                if (!data) {
                    /* Do more setup stuff here
                    */
                    $this.data('autoOp', true);
                    var op = $this.data("options");
                    var opt = typeof(op);
                    if(opt == "string")
                        opt = $.parseJSON(opt);
                    if(op == null) {
                        var t = $this.find("textArea")                        
                        if(t && t.val() != null) {
                            op = $.parseJSON(t.val());
                            t.remove();
                        }
                    }


                    var classList =$this.attr('class').split(/\s+/);
                    $.each( classList, function(){
                        var cName = this.toString();
                        if(ksg.ui.widgetMap[cName]) {
                            ksg.ui.widgetMap[cName]($this, op);
                            $this.bind("tmplApplied", function() {
                                //Fancybox should never be referenced directly by code.  Another lightbox could be used, and this code file
                                //should be all that needs to change changed.
                                if(options.includeLightBox == true)
                                    $this.find(".ksg-image").fancybox();
                            });
                            return false;
                        }
                    });
                }
            });
        },

        destroy: function () {

            return this.each(function () {
                var $this = $(this),
                data = $this.data('autoOp');
                $this.removeData('autoOp');
            })

        }
    };

    $.fn.ksgSetupUI = function (method) {
        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, arguments);
        } else {
            $.error('Method ' + method + ' does not exist on jQuery.ksgSetupUI');
        }

    };


})(jQuery);
/**
* @class
* Displays a jQuery UI dialog when notified by ksg.ui.messenger that there is a message to display
* if the level provided is one of the levels listed in options.displayLevels.
* @meta-type jQuery widget
* @Depends ksg.baseWidget.js
*/
ksg.ui.widgets.PopupDialogMessenger = {
	options: {
		displayLevels: [ksg.ui.messenger.levels.warning, ksg.ui.messenger.levels.error]
	},
	
	_create: function() { var self = this; var $this = this.element;
		$this.dialog({
			autoOpen: false,
			modal: true,
			buttons: {
				"Close": function () {
					$(this).dialog("close");
				}
			}
		});
		
		ksg.ui.messenger.addObserver(function(msg) {
			if(self.options.displayLevels.indexOf(msg.level) != -1) {
				var title = "Notice";
				if(msg.level == ksg.ui.messenger.levels.warning)
					title = "Warning";
				else if(msg.level == ksg.ui.messenger.levels.error)
					title = "Error";
				$this.dialog("option", "title", title);
				$this.html(msg.text);
				$this.dialog("open");
			}
		});
	}
};
$.widget("ksg.popupDialogMessenger", ksg.ui.widgets.PopupDialogMessenger);

ksg.ui.widgetMap["ksg-popupDialogMessenger"] = function ($el, options) {
	$el.popupDialogMessenger(options); 
};

/**
* @class
* An observer of ksg.App.bizProcMgr rule call sets, so that whenever a bizproc is executing
* bizrules, this class will turn on an ksg-acive class to the DOM element it is attached to.
* @meta-type jQuery widget
* @Depends ksg.baseWidget.js
*/
ksg.ui.widgets.SimpleSpinner = {
	options: {
	},
	_create: function() {
		var self = this, $this = self.element, options = self.options;
		
		ksg.App.bizProcMgr.addRulCallSetObserver({
			started: function() {
				$this.addClass("ksg-active");
				clearTimeout($this.timer);
			},
			completed: function() {
				$this.timer = setTimeout(function() {$this.removeClass("ksg-active");}, 100);
			}
		});
	}
};

$.widget("ksg.simpleSpinner", ksg.ui.widgets.SimpleSpinner);

ksg.ui.widgetMap["ksg-simpleSpinner"] = function ($el, options) {
	$el.simpleSpinner(options); 
};
/**
* @class
* Works with a bizproc to show the detailed viewed of a given bizobj using templates and the templating engine
* available in the app framework.
* This widget can work with a collection of templates from the template engine and switch 
* which template it is using based on the runtime, such as if the user is in an edit mode
* versus read only. 
<p>This widget will work with the Kusog startup factory using the <b>ksg-bizObjDisplay</b> css class
on the dom element this is attached to.  The following is an example of how to use this widget
on a web page.  The <b>ksg-ui</b> is the general css class used to be picked up by the startup factory.</p>
<pre>
&lt;div class="ksg-ui ksg-bizObjDisplay" 
	data-options='{"bizProcId":"art1"}'
	data-template='{"readOnly":"ArtIdImageTitleBody", "edit":"ArtIdImageTitleBody-edit"}'&gt;
&lt;/div&gt;
</pre>
<p>You can also manually create the widget with javascript code similar to the following:</p>
<pre>
$("#myDisplayId").bizObjDisplay({
	bizProcId:"art1",
	template: {
		readOnly: "ArtIdImageTitleBody",
		edit: "ArtIdImageTitleBody-edit"
	}
});
</pre>
* @meta-type jQuery widget
* @Depends ksg.baseWidget.js
*/
ksg.ui.widgets.BizObjDisplay = $.extend({},ksg.ui.widgets.BaseWidget, /** @lends ksg.ui.widgets.BizObjDisplay# */{
	options: {
	},
	
	_create: function() {
		this._IWidget_construct();
	},
	
	destroy: function() {
		this._IWidget_destruct();
	},

	//IWidget
	getWidgetType: function() {return ksg.ui.BizProcWidgetType.Disp;},
	
	
	//--- IBizObjListDisplay
	displayBizObj: function(bizObj) {
		var self = this;
		ksg.ui.getTemplate(self._getTemplateName(), "", function(json) {
			self.element.html("");
			var obj = {
				isNotEmpty:function(name) {
					var x = ksg.bizobj.BizObj.getValue(this.data, name, "");
					return x.toString().length != 0;
				},
				gt:function(name) {
					return ksg.bizobj.BizObj.getValue(this.data, name, "");
				}
			};
			json.tmpl.tmpl($.extend({},obj,bizObj)).appendTo(self.element);
			
			//This should not have to be here, but is needed to hook up field edit listeners
			//This should be a  part of a bigger template handling system that would setup widgets 
			//in the template better
			setupListeners();
		});	
	},
	
	updateBizObj: function(bizObj) {
		this._getUpdatesFromChildElements(this.element, bizObj);
	},
	
	_getUpdatesFromChildElements: function($el, bizObj) {
		var self = this;
		$.each($el.children(), function() {
			var $child = $(this),
				className = null, fieldName = null, fieldType = null;
				
			if((className = self._findClassBeginingWith($child, "ksg-field-")) && (fieldType = ksg.ui.fields[className]) && (fieldName = $child.data("fieldname")))
				bizObj[fieldName] = fieldType.getVal($child);
			
			if(!$child.hasClass("ksg-ui"))
				self._getUpdatesFromChildElements($child, bizObj);
		});
	}
	
});
$.widget("ksg.bizObjDisplay", ksg.ui.widgets.BizObjDisplay);

ksg.ui.widgetMap["ksg-bizObjDisplay"] = function ($el, options) {
	$el.bizObjDisplay(options); 
};
/**
* @class
* Works with a bizproc to show a list of bizobjs using templates and the templating engine
* available in the app framework.
* @meta-type jQuery widget
* @Depends ksg.baseWidget.js
*/
ksg.ui.widgets.BizObjListDisplay = $.extend({},ksg.ui.widgets.BaseWidget, /** @lends ksg.ui.widgets.BizObjListDisplay# */{
	options: {
	},
	
	_create: function() { var self = this; var $this = this.element;
		ksg.App.bizProcMgr.registerWidget(this);
		$this.find('.ksg-ajax-nav').live('click', function(event) {
			var id = null;
			var a = $(this);
			while((a = a.parent())[0] != $this[0])
				if(id = a.data('bizobjid'))
					break;

			//alert("would have navigated!:" + id);
			if(id) {
				var bizProc = ksg.App.bizProcMgr.getBizProc(self.getParentBizProcId());
				if(bizProc) {
					bizProc.selectBizObj(id);
					event.preventDefault();
				}
			}
		});
	},
	
	destroy: function() {
		ksg.App.bizProcMgr.unregisterWidget(this);
	},
	
	//--- IWidget	
	getWidgetType: function() {return ksg.ui.BizProcWidgetType.List;},
	
	//--- The following are required IBizObjListDisplay interface methods
	DrivenByBizProc: function(){return true;},
	
	setSelectedBizObjKeyValue: function(val) {
		this.selectedBizObjKeyValue = val;
		this.element.find(".ksg-selected").removeClass("ksg-selected");
		this.element.find("[data-bizobjid='"+val+"']").addClass("ksg-selected");
	},
	
	showBizObjs: function(bizProc, bizObjs) {
		var self = this;
		ksg.ui.getTemplate(self._getTemplateName(), "", function(json) {
			self.element.html("");
			json.tmpl.tmpl(bizObjs.pushForward(self.MaxElements())).appendTo(self.element);
			self.setSelectedBizObjKeyValue(self.selectedBizObjKeyValue);
            self.element.trigger("tmplApplied");
		});
	},
	
	MaxElements: function() {
		var max = this.options.maxElements;
		return (!(max))?-1:max;
	}
	
});
$.widget("ksg.bizObjListDisplay", ksg.ui.widgets.BizObjListDisplay);

ksg.ui.widgetMap["ksg-bizObjListDisplay"] = function ($el, options) {
	$el.bizObjListDisplay(options); 
};
//# gridOnly
if(typeof(ksg) == "undefined") 
	ksg = {ui:{widgetMap:{}}};
//#

/**
* @namespace
* namespace - Contains all Kusog Grid related code items.
* @Depends ksg.baseWidget.js ksg.selectedRange.js
*/
ksg.ui.grid = {
	/**
	* @namespace
	*/
	columnTypes: {},
	columnDefinitions: { },
	templateHandlers: { },
	dataHandlerFactory: {
		basicArray: function(data, idFieldName) {
			return $.extend({},{
				getList: function(id, options, onSuccess) {
					onSuccess(data);
				},
				getTotalPossibleCount: function(options, onSuccess) {
					onSuccess(data.length);
				},
				getGeneralList: function(name, options) {
				},
				getIdFieldName: function() {
					return idFieldName;
				},
				shouldRequestChildListData: function() {
					return false;
				},
				hasValue: function(obj, fieldName) {
					return (fieldName in obj);
				},
				getValue: function(obj, fieldName) {
					return obj[fieldName];
				},
				setValue: function(obj, fieldName, val) {
					obj[fieldName] = val;
				}
			});
		}
	}
};


/**
* @class
* abstract class - Displays and manages a list of bizobjs in a grid formatted display, but it takes a child class to complete
* the functionality.
* The bizobj list can also be a BizObjTree structure, which will then allow the user to drill down into branches within the tree.
* @see ksg.ui.grid.DataGrid
* @meta-type abstract base class
* @importance high
*/
ksg.ui.grid.BaseGrid = {
	// default options
	options: {
		totalL1FieldName: "counts.totalL1",
		depthFieldName: "depth",
		hoverRowClass: "ui-state-highlight",
		selectedRowClass: "ui-state-active"
	},

	/**
	* The currently selected row's unique id value.
	* @type object
	*/
	selectedBizObjId: null,
   
	_create: function () { var options = this.options, self = this;
		this.id = this.element.attr('id');
		if(!(this.id))
			this.id = "";
		if(this._internalCreate) this._internalCreate();
		
		if(typeof(options.parentBizProc) == "string")
			options.parentBizProc = eval(options.parentBizProc + "BizProc");
		ksg.ui.template.processTemplate(this.templates.baseGrid,this.options, null,function(tmpl) {
			self._initGrid(tmpl);
		});
	},
	
	destroy: function() {
		if(this._internalDestroy) this._internalDestroy();
	},

	_initGrid: function(tmpl) {var $this = this.element, self = this, options = this.options;
		if(this._internalInitGrid) this._internalInitGrid(tmpl);
		
		var grid = this; //Used by grid tmpl to call methods
		$this.append(tmpl);
		this._mergeDefaultColumnOptions();

		$this.find(".gcol").live({
			'keydown': function(event) {
				var $editElement = $(this).find('.ksg-grid-cellEditor');
				var keycode = event.keyCode;
				var $gcol = null;
				var index = $(this).parentsUntil("tr").index() +1;
				if(keycode == 40)//down arrow
					$gcol = $(this).parentsUntil("tbody").next().find("td:nth-child("+index+") > .gcol");					
				else if(keycode == 38) //up arrow
					$gcol = $(this).parentsUntil("tbody").prev().find("td:nth-child("+index+") > .gcol");
				else {
					var atBegining = true, atEnd = true;
					var isContentEditable = ($editElement.hasClass('ksg-grid-cellEditor') && $editElement.attr('contentEditable') == "true")
					if(isContentEditable) {
						var selInfo = $editElement.selectedRange('getRange');
						atBegining = selInfo.start == 0;
						atEnd = selInfo.end == selInfo.contentLength;
						//var selInfo = $editElement.getSelection();
						//atBegining = selInfo.start==0;
						//atEnd = selInfo.end == selInfo.length;
					}
					
					var moveLeftCell = (keycode == 37 && atBegining);
					var moveRightCell = (keycode == 39 && atEnd);
					
					if(moveLeftCell || moveRightCell) {
						var ctime = new Date().getTime();
						if(!(self.lastCurMoveTime && (ctime - self.lastCurMoveTime < 70))) {
							self.lastCurMoveTime = ctime;
							if(moveLeftCell) {
								var $prev = $(this).parentsUntil("tr").prev();
								if($prev.length == 0)
									$gcol = $(this).parentsUntil("tbody").last().prev().find("td:last > .gcol");
								else
									$gcol = $prev.find(".gcol");
							}
							else if(moveRightCell) {
								var $next = $(this).parentsUntil("tr").next();
								if($next.length == 0)
									$gcol = $(this).parentsUntil("tbody").last().next().find("td:first > .gcol");
								else
									$gcol = $next.find(".gcol");
							}
						}
					}
				}
							
				if($gcol != null) {
					self._setEditCell($gcol,keycode);
					return false;
				}
			},
			'focus': function(event) {
				if($(event.target).hasClass("ksg-grid-cellEditor") == false) {
					var $innerControl = $(this).find(".ksg-grid-cellEditor");
					if($innerControl.length > 0) {
						if($innerControl[0].isContentEditable) {
							$innerControl.selectedRange('setCarot','start');
						}
						self._setEditCell($(this));
					}
				}
			},
			'mousedown': function(event) {
				self._setEditCell($(this));
			}
		});
		
		$this.find(".ksg-grid-dataRow").live({
			'mouseover': function(event) {
				$(this).addClass(options.hoverRowClass);
			},
			'mouseout':function(event) {
				$(this).removeClass(options.hoverRowClass);
			}
		});
		
		var lsResize = function (event, ui) {
			self.resize();
		};
		
		$(window).resize(function() {
			self.resize();
		});
		
		$this.resizable({
			containment: $this.parent().parent(),
			handles: 'e',
			resize: lsResize,
			stop: lsResize
		});
		this._setupColHeaders();
		
		$this.find(".ksg-grid-rowArea").scroll(function (e) {
			$this.find(".ksg-grid-header").scrollLeft($(".ksg-grid-rowArea").scrollLeft());
		});
		
		$this.find(".ksg-grid-rowArea table").selectable({
			filter: 'td',
			selected: function (event, ui) {
				var $this = $(ui.selected);
				var sid = $this.parentsUntil('tbody').last().find('.ksg-id').val().toString();
				//var s = $this.find('.ui-selected');
				//s.find(".gcol").focus();
				//var sr = s.parent();
				//var sid = sr.find('.ksg-id').val().toString();//.replace(/-/g, '');
				self._selectBizObj(sid);
			}
		});
		$this.find(".treeBut").live("mousedown", function () {
			self._expandBranch($(this));
		});
		$this.find(".ksg-viewit-nav").live("mousedown", function () {
			$this.trigger("click");
		});
		
		if(self.options.parentIdWidget)
			$("#"+self.options.parentIdWidget).live("bizObjSelected", function(event, pid) {
				options.baseServiceOptions.pid = pid;
				self._resetGridData();
			});
		
		
		self._resetGridData();
	},
	
	getRowIdValue: function(bizObj) {
		return this._formatRowIdValue(this.dataHandler.getValue(bizObj,this._getIdFieldName()));
	},
	
	_formatRowIdValue:function(bizObjId) {
		return this.id + "_r_" + bizObjId.replace(/ /g, "^");
	},
	
	_selectBizObj: function(selectedId, fromInternalSelect, fromSetEditCell, fromRefresh) {
		if(selectedId.length > 3 && selectedId.substr(0,3) == "957") {
			var x = "we hit first one";
			$(".noRealId").html(x);
		}
		var self = this, el = this.element, options = this.options, $idField = $(document.getElementById(self._formatRowIdValue(selectedId)));
		if(fromRefresh != true && self.selectedBizObjId == selectedId)
			return;
		self.selectedBizObjId = selectedId;
		if($idField.length == 0 && !(selectedId)) {
			el.trigger("bizObjSelected", selectedId);
			if(this._internalSelectBizObj) this._internalSelectBizObj(selectedId);
		}
		else
			$idField.each(function() {
				var $id = $(this);
				if($id.val() == selectedId || selectedId == null) {
					selectedId = $id.val();
					if(self.selectedRow)
						self.selectedRow.removeClass(options.selectedRowClass);
					self.selectedRow = $id.parentsUntil("tbody").last().addClass(options.selectedRowClass);
					//$id.parentsUntil("table").last().find("."+options.selectedRowClass).removeClass(options.selectedRowClass);
					//$id.parentsUntil("tbody:last").addClass(options.selectedRowClass);
					el.trigger("bizObjSelected", selectedId);
					if(fromSetEditCell != true)
						self._setEditCell($id.parentsUntil("tbody").last().find("td:first > .gcol"));
					if(fromInternalSelect != true && self._internalSelectBizObj) self._internalSelectBizObj(selectedId, fromRefresh);					
					return false;					
				}
			});
	},

	_setEditCell: function($gcol,keycode) {
		var inEdit = $gcol.find(".ksg-grid-cellInEdit");
		if(inEdit.length != 0)
			return;
			
		var $cell = $gcol.find(".ksg-grid-cellEditor");
		var cellTypeName = $cell.attr('cellType');
		var cellType = ksg.ui.grid.columnTypes[cellTypeName];
		if(cellType) {
			if(this._lastEditCell) {
				this._completeCellEdit(this._lastEditCell);
				this._lastEditCell.find(".ksg-grid-cellInEdit").removeClass("ksg-grid-cellInEdit");
			}
			this._lastEditCell = $gcol;
			if(cellType.edit)
				cellType.edit(this, $gcol, $cell, null, null);
				
			var $innerControl = $gcol.find(".ksg-grid-cellEditor");
			if($innerControl.length > 0) {
				$innerControl.addClass("ksg-grid-cellInEdit");
				if($innerControl.attr('contentEditable') == "true") {
					$innerControl.selectedRange('setCarot',keycode==37?'end':'start');
				}
				$innerControl.focus();
			}
		}
		this._selectBizObj($gcol.parent().parent().find(".ksg-id:input").val(),false, true, false);
	},
	
	_completeCellEdit: function($gcol) {
		var $cell = $gcol.find(".ksg-grid-cellEditor");
		var cellTypeName = $cell.attr('cellType');
		var cellType = ksg.ui.grid.columnTypes[cellTypeName];
		if(cellType && cellType.completeEdit)
				cellType.completeEdit(this, $gcol, $cell, null, null);
	},
	
	getRowChildState: function(rowIndex, bizObj, bizObjs) {		
		var options = this.options;
		var childState = 0; //0 = no children; 1=has children, but not in list; 2=has children, and present in list
		if (this.dataHandler.getValue(bizObj, options.totalL1FieldName) > 0)
			childState = 1;
			
		if(bizObjs.length > rowIndex+1 && this.dataHandler.getValue(bizObjs[rowIndex+1], options.depthFieldName) > this.dataHandler.getValue(bizObj, options.depthFieldName))
			childState = 2;

		return childState;
	},

	resize: function() {
		var el = this.element;
		el.find(".ksg-grid-header").width(el.width()); 
		el.find(".ksg-grid-rowArea").width(el.width());
		el.find(".ksg-grid-rowArea").height(el.height() - el.find(".ksg-grid-header").outerHeight(true) - el.find(".ksg-grid-footer").outerHeight(true));                
		this._refreshColumnSizes();
		if(this._internalResize) this._internalResize();
	},

	_mergeDefaultColumnOptions: function() {
		var columns = this.options.columns;
		if(columns)
			for(var i = 0; i < columns.length; i++) {				
				var defName = this.options.type + "-" + columns[i].id;
				var defCol = ksg.ui.grid.columnDefinitions[defName];
				if(defCol)
					columns[i] = $.extend({}, defCol, columns[i]);
			}
	},

	_getDataFieldId: function(col) {
		var id = col.dataField;
		if(!id || id == "")
			id = col.id;
		return id;
	},
	
	_hasIdField: function() {
		return ((this.idFieldName || this.options.columns["_id"] || ksg.ui.grid.columnDefinitions[this.options.type + "-_id"]) != null);
	},
	
	_getIdFieldName: function() {
		if(this.idFieldName)
			return this.idFieldName;

		this.idFieldName = null;
		if(this.options.columns["_id"])
			this.idFieldName = this.options.columns["_id"].dataField;				
		else if(this.options.type && ksg.ui.grid.columnDefinitions[this.options.type + "-_id"])
			this.idFieldName = ksg.ui.grid.columnDefinitions[this.options.type + "-_id"].dataField;

			if(this.idFieldName == null)
			this.idFieldName = this.dataHandler.getIdFieldName();
			
		return this.idFieldName;
	},
	
	_getTmplName: function(ending) {
		var options = this.options;
		var rowType = "";
		if(options.subType && options.subType != "")
			rowType = "-" + options.subType;
		return rowType + ending;
	},
		
	_setupColHeaders: function() {
		var $this = this.element, self = this, options = this.options;
		var $thead = $this.find(".ksg-grid-header table thead");		
		
		var sizeCol = function(col) {
			$this.find(".ksg-grid-rowArea ." + col.id).width($(col).outerWidth());
		};
			
		ksg.ui.template.processTemplate(self.templates.header, options, null, function(tmpl) {
			$thead.append(tmpl);
			var $cols = $thead.children();
			self.resize();
			
			$cols.find(".ghcol:not(.ksg-not-resizable)").resizable({ handles: 'e',
				resize: function (event, ui) {
					sizeCol(this);
				},
				stop: function (event, ui) {
					sizeCol(this);
				}
			});
			
		});
	},
	
	_refreshColumnSizes: function() {
		var $this = this.element;
		this.element.find(".ghcol").each(function() {
			$this.find(".ksg-grid-rowArea ." + this.id).width($(this).outerWidth());
		});
	},
		
	_resetGridData: function() {var $this = this.element, self = this, options = this.options;
		var $tb = $this.find(".ksg-grid-rowArea table tbody");
		$tb.children().remove();
		//# data call
		// This gets the initial list of top level parents to show after reseting the grid
		self.dataHandler.getList("", options, function (bizObjList) {
			//$this.data("initData", json);
			var bizObjs = bizObjList;
			var proc = function() {
				$this.trigger("tmplApplied");
				self._refreshTotal(true);
				self.resize();
				if(self._internalResetDataComplete) self._internlResetDataComplete();
				if(self.selectedBizObjId) {
					self._selectBizObj(self.selectedBizObjId, false, false, true);
				}
			};
			self._insertRows(bizObjs, {bizObjs:bizObjs, grid:self, options:options, columns: options.columns}, proc);
			/*
			if(bizObjs && bizObjs.length > 0) {
				ksg.ui.template.processTemplate(self.templates.dataRow, {bizObjs:bizObjs, grid:self, options:options}, null, function(tmpl) {
					$tb.append(tmpl);
					proc();
				});
			}
			else
				proc();
			*/
		});
		//# ---
	},
	_insertRows: function(bizObjs, templateData, onAfterLast, $insertAfter, index, iterationIndex) {var $this = this.element, self = this, options = this.options;
		if(bizObjs == null) {
			if(onAfterLast)
				onAfterLast();
		}
		else {
			if(index == null)
				index = 0;
			if(iterationIndex == null)
				iterationIndex = 0;
			
			if(index < bizObjs.length) {
				templateData.bizObj = bizObjs[index];
				templateData._index = index;
				ksg.ui.template.processTemplate(self.templates.dataRow, templateData, null, function(tmpl) {
					var $nextRow = null;
					if($insertAfter)
						$nextRow = $(tmpl).insertAfter($insertAfter);
					else
						$nextRow = $(tmpl).appendTo($this.find(".ksg-grid-rowArea table tbody"));
					if($nextRow)
						if(iterationIndex < 50)
							self._insertRows(bizObjs, templateData, onAfterLast, $nextRow, ++index, ++iterationIndex);
						else
							setTimeout(function() {
								if(onAfterLast)
									onAfterLast();
								self._insertRows(bizObjs, templateData, onAfterLast, $nextRow, ++index);
							}, 1);
				});
				
			}
			else if(onAfterLast)
				onAfterLast();
		}
	},
	
	_getCellTemplate: function(col, bizObj) {
		var isEditabled = this.options.editable;
		var colType= ksg.ui.grid.columnTypes[col.type];
		if(!colType)
			colType=ksg.ui.grid.columnTypes["text"];
		
		return colType.std(this,col,bizObj,isEditabled);
	},

	_refreshTotal: function(includeTotalRows) {var $this = this.element, options = this.options;
		$this.find(".gcol").attr("tabindex",0);
		$visibleRows = $this.find(".ksg-bizObjList-visibleRows");
		var visRowCount = $this.find(".ksg-grid-rowArea tr").length;
		$visibleRows.text(visRowCount);
		this._refreshColumnSizes();
		if (includeTotalRows) {
			var $totalRows = $this.find(".ksg-bizObjList-totalRows");
			//# data call
			//Gets the total number of rows available to be shown in the grid, including child nodes
			this.dataHandler.getTotalPossibleCount(options, function (count) {
				if(count)
					$totalRows.text(count);
				else
					$totalRows.text(visRowCount);
			});
			//# ---
		}
	},

	_removeChildren: function(cr) {
		var curDepth = Number(cr.find('#depth').val());
		var nr = cr.next();
		while (Number(nr.find('#depth').val()) > curDepth) {
			var o = nr;
			nr = nr.next();
			if(this.dataHandler.shouldRequestChildListData())
				o.remove();
			else {
				var southItems = o.find(".ui-icon-triangle-1-s");
				o.hide();
				southItems.removeClass("ui-icon-triangle-1-s").addClass("ui-icon-triangle-1-e");
				if(o.data("expanded") == true || southItems.length != 0)
					o.data("expanded", false);				
			}
		}
	},

	_findParent: function(cr) {
		var curDepth = Number(cr.find('#depth').val());
		var pr = cr.prev();
		var tr = (pr==null||pr.length==0)?cr:pr;
		if (curDepth > 0)
			while (Number(pr.find('#depth').val()) != curDepth - 1) {
				pr = pr.prev();
				tr = pr;
			}
		return tr;
	},
	
	_findRowWithId: function(id) {
		var idField = document.getElementById(this._formatRowIdValue(id));
		if(idField) {
			var $idField = $(idField);
			return $idField.parentsUntil("tbody").last();
		}
	},
		
	_expandBranch: function(el) {var $this = this.element, self = this, options = this.options;
		var sr = el.parentsUntil("tbody").last();
		var sid = sr.find('.ksg-id').val();
		if(sid)
			sid.toString().replace(/-/g, '');

		var curDepth = Number(sr.find('#depth').val());
		var ex = sr.data("expanded");
		if (typeof (ex) == 'undefined') {
			var nextSr = sr.next();
			var nextDepth = Number(nextSr.find('#depth').val());
			ex =(nextDepth > curDepth);
		}
		var numChildren = Number(sr.find('#numChildren').val());
		//if (numChildren > 0) {
			if (ex == true || ex == 'true') {
				el.removeClass("ui-icon-triangle-1-s").addClass("ui-icon-triangle-1-e");
				sr.data("expanded", false);
				this._removeChildren(sr);
				this._refreshTotal(false);
			}
			else {
				el.removeClass("ui-icon-triangle-1-e").addClass("ui-icon-triangle-1-s");
				sr.data("expanded", true);
				var nr = sr.next();
				if (nr == null || nr.length == 0 || nr.find('#depth').val() <= curDepth) {
					//# data call
					//Gets the child elements of the selected node to insert into the grid.
					self.dataHandler.getList(sid, options, function (bizObjs) {
						function proc() {
							self._refreshTotal(true);
							$this.trigger("tmplApplied");
						};
						
						self._insertRows(bizObjs, {bizObjs:bizObjs, grid:self, options:options, columns: options.columns}, proc, sr);
						//ksg.ui.getTemplate(options.template, self._getTmplName("-data-row"), function(tmpl) {
						//ksg.ui.template.processTemplate(self.templates.dataRow,{bizObjs:bizObjs, grid:self, options:options}, null, function(tmpl) {
							//$(tmpl).insertAfter(sr);
							//$(tmpl).tmpl({bizObjs:bizObjList, grid:self}, options).insertAfter(sr).find(".treeBut");
						//});
					});
					//# ---
				}
				else {
					while (Number(nr.find('#depth').val()) > curDepth) {
						if (Number(nr.find('#depth').val()) == curDepth + 1)
							nr.show();
						nr = nr.next();
					}
				}
			}
		//}            
	}
};

/**
* @augments ksg.ui.grid.BaseGrid
* @class
* Data Grid that uses the basic array data handler to manage its data.
* @meta-type jQuery widget
*/
ksg.ui.grid.DataGrid = $.extend({}, ksg.ui.grid.BaseGrid, /** @lends ksg.ui.grid.DataGrid# */{
	_internalCreate: function() {
		this.templates = ksg.ui.grid.templateHandlers;
		this._setupGridDataHandler([]);
	},
	_internalDestroy: function() {
	},
	_internalInitGrid: function() {
	},
	_setupGridDataHandler: function(dataArray) {
		this.dataHandler = ksg.ui.grid.dataHandlerFactory.basicArray(dataArray);
	},
	_internalSelectBizObj: function(dataId) {
	},

	/**
	* Given an array of objects, will display them based on base grid configuration.
	*/
	displayData: function(dataArray) {
		this._setupGridDataHandler(dataArray);
		this._resetGridData();
	}
});

$.widget("ksg.dataGrid", ksg.ui.grid.DataGrid);
ksg.ui.widgetMap["ksg-dataGrid"] = function ($el, options) {
	$el.dataGrid(options); 
};



/**
* @name ksg.ui.grid.templateHandlers
* @namespace
* A collection of column types available to the grid.
* @Depends ksg.gridCore.js
*/
$.extend(ksg.ui.grid.templateHandlers, /** @lends ksg.ui.grid.templateHandlers */{
	baseGrid: {id:'grid-style1-baseGrid',tmpl:'<div class="ui-widget-header ksg-grid-header"><table class="genGridTbl" border="1" cellpadding="0" cellspacing="0"><thead></thead><tbody></tbody></table></div><div class="ksg-grid-outerRowArea"><div class="ksg-grid-rowArea">	<table border="1" cellpadding="0" cellspacing="0" class="genGridTbl ui-widget-content"><tbody></tbody></table></div></div><div class="ksg-bizObjList-footer ksg-grid-footer"><span>Total Record(s): </span><span class="ksg-field ksg-bizObjList-totalRows"></span>	<span>&nbsp;&nbsp;/&nbsp;In Display:</span><span class="ksg-field ksg-bizObjList-visibleRows"></span></div>', engine: 'kite'},
	header: {id:'grid-style1-header',tmpl:'<tr>{{#columns}}<th><div id="{{id}}Col" class="ghcol {{id}}Col" style="width: {{width}}px"><a>{{header}}</a></div></th>{{/columns}}</tr>', engine: 'kite'},
	dataRow: {id:'grid-style1-data',tmpl:'<script id="artTmpl2" type="text/template"><tr class="ksg-grid-dataRow">{{each(i2, col) options.columns}}<td><div  class="gcol ${col.id}Col" style="width: ${col.width}px">{{if i2 == 0}}{{if grid._hasIdField()}}<input type="hidden" class="ksg-id" id="${grid.getRowIdValue(bizObj)}" value="${grid.dataHandler.getValue(bizObj,grid._getIdFieldName())}"/>{{/if}}{{if options.isBizObjTree}}<input type="hidden" id="depth" value="${bizObj.depth}" /><input type="hidden" id="numChildren" value="${grid.dataHandler.getValue(bizObj, grid.options.totalL1FieldName)}"/><div style=\'padding-left:${ (bizObj.depth)*20}px;display:inline-block\'><div class=\'treeBut {{if grid.getRowChildState(_index,bizObj,bizObjs) > 0}} ui-icon ${(grid.getRowChildState(_index,bizObj,bizObjs) == 1)?\'ui-icon-triangle-1-e\':\'ui-icon-triangle-1-s\'}{{/if}}\'>&nbsp;</div>{{/if}}{{/if}}{{html grid._getCellTemplate(col,bizObj)}}</div></td>{{/each}}</tr></script>','engine':'jqtmpl'},
	dataRow2: {
		id:'grid-style1-data',
		tmpl:'<tr class="ksg-grid-dataRow">{foreach $columns as $i => $col}x{/foreach}</tr>',
		engine:'jsmart'
	}
});
/**
* @name ksg.ui.grid.columnTypes
* @namespace
* A collection of column types available to the grid.
* @Depends ksg.gridCore.js
*/
(function ($) {
	$.extend(ksg.ui.grid.columnTypes, /** @lends ksg.ui.grid.columnTypes */{
		/**
		* @class
		* Displays text and uses inline editing for the text.  Not a full HTML editor.
		*/
		text: {
			std: function(grid, col, bizObj, isEditabled) {
				var s = "<div tabindex='0' cellType='text' class='ksg-grid-cellEditor ksg-grid-textcell'";
				var fieldName = grid._getDataFieldId(col); 
                var v = "";
                try {
                    if (grid.dataHandler.hasValue(bizObj, fieldName))
                        v = grid.dataHandler.getValue(bizObj, fieldName);
                }
                catch (e) {
                    v = "";
                }
				
				if(isEditabled == true)
					s+= " contentEditable='true'";
				s += ">" + v + "</div>";
				return s;
			},
			edit: function(grid, $gcol, $cell, col, bizObj) {
				$cell.focus();
			}
		},
		/**
		* @class
		* Displays an anchor link in the cell that the user can click on to navigate to the given location.
		*/
        link: {
            std: function (grid, col, bizObj, isEditabled) {
                var s = "<a href cellType='text' class='ksg-grid-cellLink ksg-grid-textcell'";
                var fieldName = grid._getDataFieldId(col);
                var v = "";
                try {
                    if (grid.dataHandler.hasValue(bizObj, fieldName))
                        v = grid.dataHandler.getValue(bizObj, fieldName);
                }
                catch (e) {
                    v = "";
                }
                s += ">" + v + "</a>";
                return s;
            },
            edit: function (grid, $gcol, $cell, col, bizObj) {
                $cell.focus();
            }
        },
		/**
		* @class
		* Displays an HTML checkbox for boolean values.  When editable, user can check the checkbox.
		*/
		checkbox: {
			std: function(grid, col, bizObj, isEditabled) {
				var s = "<input tabindex='0' cellType='checkbox' class='ksg-grid-cellEditor' ";
				if(isEditabled != true)
					s+= "disabled ";
				s += "type='checkbox' id='" + col.id + "'" + (grid.dataHandler.getValue(bizObj, grid._getDataFieldId(col))== true?" checked":"") + " />";
				return s;
			},
			edit: function(grid, $gcol, $cell, col, bizObj) {
				$cell.focus();
			}		
		},
		/**
		* @class
		* Displays an image in the cell.
		*/
		image: {
			_defaultBlankImage: "/images/blank.gif",
			std: function(grid, col, bizObj, isEditabled) {
				var s = "";
				var resourceUrl = col.resourceUrl;
				if(!resourceUrl)
					resourceUrl = "";
				var imageSize = col.imageSize;
				if(!imageSize)
					imageSize = "TinyGridSize";
				var fieldName = grid._getDataFieldId(col); 
				var imgVal = grid.dataHandler.getValue(bizObj, fieldName);
				var shouldShowImage = (imgVal && imgVal.toLowerCase() != this._defaultBlankImage);
				
				if(shouldShowImage)
					s = "<img class='ksg-grid-cellEditor' cellType='image' tabindex='0' src='"+resourceUrl+ grid.dataHandler.getValue(bizObj, "mediaCacheName")+"/"+imageSize+"/" + grid.dataHandler.getValue(bizObj, fieldName) + "' />";
				else				
					s = "<img class='ksg-grid-cellEditor' cellType='image' tabindex='0' src='/images/blank.gif' />";
				return s;
			},
			edit: function(grid, $gcol, $cell, col, bizObj) {
				$cell.focus();
			}		
		},
		/**
		* @class
		* Displays a dropdown widget when in edit mode, but shows the selected value as text when not in edit mode.
		*/
		dropdown: {
			std: function(grid, col, bizObj, isEditable) {
				var s = "<div tabindex='0' class='ksg-grid-cellEditor'  cellType='dropdown'";
				var fieldName = grid._getDataFieldId(col); 
                var v = "";
                try {
                    if (grid.dataHandler.hasValue(bizObj, fieldName))
                        v = grid.dataHandler.getValue(bizObj, fieldName);
                }
                catch (e) {
                    v = "";
                }
				s += ">" + v + "</div>";
				return s;
			},
			edit: function(grid, $gcol, $cell, col, bizObj) {
				$gcol.attr('pr', $gcol.html());
				$gcol.html("<select style='margin:0px;padding:0px;width:100%' cellType='dropdown' class='ksg-grid-cellEditor'><option>abd</option><option>123</option></select>");
				$newCell = $gcol.find(".ksg-grid-cellEditor");
				$newCell.focus();
			},
			completeEdit: function(grid, $gcol, $cell, col, bizObj) {
				$gcol.html($gcol.attr('pr'));
			}
			
		}
	});

})(jQuery);
/**
* @augments ksg.ui.grid.BaseGrid
* @class
* Works with a bizproc to show the detailed viewed of a given bizobj using the Kusog Grid jQuery UI widget.
* @meta-type jQuery widget
* @Depends ksg.gridCore.js
*/
ksg.ui.widgets.BizObjListGrid = $.extend({},ksg.ui.widgets.BaseWidget, ksg.ui.grid.BaseGrid, /** @lends ksg.ui.widgets.BizObjListGrid# */{
	_internalCreate: function() {
		var options = this.options;
		this.templates = ksg.ui.grid.templateHandlers;
		this._setupGridDataHandler([]);
		this._IWidget_construct();
		ksg.App.bizProcMgr.registerWidget(this);
	},
	_internalDestroy: function() {
		this._IWidget_destruct();
	},
	_internalInitGrid: function() {
	},
	_setupGridDataHandler: function(bizObjList) {
		var idField = "id";
		var bizProc = ksg.App.bizProcMgr.getBizProc(this.getParentBizProcId());
		if(bizProc) 
			idField = bizProc.getKeyName();
		this.dataHandler = ksg.ui.grid.dataHandlerFactory.bizObjList(bizObjList,idField);
	},
	_internalSelectBizObj: function(bizObjId, fromRefresh) {
		if(!(bizObjId) && fromRefresh == true)
			return;
		var bizProc = ksg.App.bizProcMgr.getBizProc(this.getParentBizProcId());
		if(bizProc && bizObjId != bizProc.currentBizObjId) 
			bizProc.selectBizObj(bizObjId);
	},

	
	//--- IWidget	
	getWidgetType: function() {return ksg.ui.BizProcWidgetType.List;},
	
	//--- The following are required IBizObjListDisplay interface methods
	DrivenByBizProc: function(){return true;},
	
	setSelectedBizObjKeyValue: function(bizObjId) {
		this._selectBizObj(bizObjId, true);
	},
	
	showBizObjs: function(bizProc, bizObjCursor) {
		this._setupGridDataHandler(bizObjCursor.bizObjs);
		this._resetGridData();
	},
	
	MaxElements: function() {
		var max = this.options.maxElements;
		return (!(max))?-1:max;
	}
});

$.widget("ksg.bizObjListGrid", ksg.ui.widgets.BizObjListGrid);
ksg.ui.widgetMap["ksg-bizObjListGrid"] = function ($el, options) {
	$el.bizObjListGrid(options); 
};


ksg.ui.grid.dataHandlerFactory.bizObjList = function(bizObjList, idFieldName) {
	return $.extend({},{
		getList: function(id, options, onSuccess) {
			onSuccess(bizObjList);
		},
		getTotalPossibleCount: function(options, onSuccess) {
			onSuccess(bizObjList.length);
		},
		getIdFieldName: function() {
			return idFieldName;
		},
		getGeneralList: function(name,options) {
		},
		shouldRequestChildListData: function() {
			return false;
		},
		hasValue: function(obj, fieldName) {
			return ksg.bizobj.BizObj.hasValue(obj,fieldName);
		},
		getValue: function(obj, fieldName, defValue) {
			return ksg.bizobj.BizObj.getValue(obj,fieldName, defValue)
		},
		setValue: function(obj, fieldName, val) {
			//TODO setup set value
		}
	});
};
(function( $ ) {
	var methods = {
		getRange: function() {
			if (window.getSelection) {
				var selObj = window.getSelection();
				if(selObj.rangeCount > 0) {
					var rage = selObj.getRangeAt(0);
					return {start: rage.startOffset, end: rage.endOffset, contentLength: rage.startContainer.length};
				}
			}
			else if (document.selection) {
				var range = document.selection.createRange();
				var bookmark = range.getBookmark();
				/* FIXME the following works wrong when the document is longer than 65535 chars */
				cursorPos = bookmark.charCodeAt(2) - 11; /* Undocumented function [3] */
			}

			return {start: 0, end: 0, contentLength: this.html().length };
		},
		selectAll: function() {
			if(window.getSelection) {
				var selObj = window.getSelection();
				selObj.selectAllChildren(this[0]);
			}
			else if(document.selection) {
				//TODO: Legacy IE support.
			}
		},
		setCarot: function(loc) {
			if(window.getSelection) {
				var selObj = window.getSelection();
				selObj.removeAllRanges();
				var rage = document.createRange();
				rage.selectNodeContents(this[0]);
				if(rage.startContainer.childNodes.length > 0) {
					var rage2 = document.createRange();
					if(loc == 'end') {
						var pos = $(rage.endContainer).html().length;
						rage2.setStart(rage.endContainer.childNodes[0], pos);
						rage2.setEnd(rage.endContainer.childNodes[0], pos);
					}
					else {
						rage2.setStart(rage.startContainer.childNodes[0], 0);
						rage2.setEnd(rage.startContainer.childNodes[0], 0);
					}
					selObj.addRange(rage2);
				}
			}
			else if(document.selection) {
				//TODO: Legacy IE support.
			}
		}
	};
	$.fn.selectedRange = function(method) {
        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else {
            $.error('Method ' + method + ' does not exist on jQuery.articleListDisplay');
        }
	}
})(jQuery);/**
* @class
* @Depends ksg.gridCore.js
*/
ksg.ui.template = {
	defaultEngine: "jqtmpl",
	baseScriptUrl: "/js/",
	
	loadTemplate: function(templateId, onSuccess, onError) {
		if(typeof(templateId) == "object" && templateId.tmpl) {
			onSuccess(templateId.tmpl);
			return;
		}
		
		var tmpl = document.getElementById(templateId);
		if(!tmpl) 
			onError("Template element #" + templateId + " not found");
		else
			onSuccess(tmpl.innerHTML);
	},
	
	getTemplateId: function(template) {
		if(typeof(template) == "object" && template.id)
			return template.id;
		return template;
	},

	processTemplate: function(templateId, dataset, extraInfo, onSuccess, onError, engineName) {
		if(!(engineName))
			engineName = this.defaultEngine;
		var isObject = typeof(templateId) == "object";
		if(isObject && templateId.processor)
			templateId.processor(templateId, dataset, extraInfo, onSuccess, onError);
		else {
			if(isObject && templateId.engine)
				engineName = templateId.engine;

			var engine = this.templateEngines[engineName];
			if(engine)
				engine.checkScripts(this, function() {
					engine.processTemplate(templateId, dataset, extraInfo, onSuccess, onError);
				});
		}
	},

	templateEngines: {
		"kite": {
			_compiled: {},
			checkScripts: function(core,onSuccess) {
				if(typeof(kite) == "undefined")
					$.getScript(core.baseScriptUrl + "kite.js", onSuccess);				
				else
					onSuccess();
			},
			processTemplate: function(templateId, dataset, extraInfo, onSuccess, onError) {
				var self = this;
				var cmpTmpl = self._compiled[ksg.ui.template.getTemplateId(templateId)];
				if(!(cmpTmpl)) {
					ksg.ui.template.loadTemplate(templateId, function(tmpl) {
						self._compiled[templateId] = cmpTmpl = kite(tmpl);
						onSuccess(cmpTmpl(dataset), extraInfo);
					}, function(err) {
						onError(err, extraInfo);
					});
				}
				else
					onSuccess(cmpTmpl(dataset), extraInfo);
			}
		},
		"jqote": {
			_compiled: {},
			checkScripts: function(core, onSuccess) {
				if(!($.jqotec))
					$.getScript(core.baseScriptUrl + "jquery.jqote2.min.js", onSuccess);				
				else
					onSuccess();
			},
			processTemplate: function(templateId, dataset, extraInfo, onSuccess, onError) {
				var self = this;
				var cmpTmpl = self._compiled[ksg.ui.template.getTemplateId(templateId)];
				if(!(cmpTmpl)) {
					ksg.ui.template.loadTemplate(templateId, function(tmpl) {
						self._compiled[templateId] = cmpTmpl = $.jqotec(tmpl);
						onSuccess(cmpTmpl.call(dataset, 0,0,dataset,cmpTmpl), extraInfo);
					}, function(err) {
						onError(err, extraInfo);
					});
					
				}
				else
					onSuccess(cmpTmpl.call(dataset, 0,0,dataset,cmpTmpl), extraInfo);
			}
		},
		"mustache": {
			checkScripts: function(core, onSuccess) {
				if(typeof(Mustache) == "undefined")
					$.getScript(core.baseScriptUrl + "mustache.js", onSuccess);				
				else
					onSuccess();
			},
			processTemplate: function(templateId, dataset, extraInfo, onSuccess, onError) {
				var self = this;
				ksg.ui.template.loadTemplate(templateId, function(tmpl) {
					onSuccess(Mustache.to_html(tmpl, dataset), extraInfo);
				}, function(err) {
					onError(err, extraInfo);
				});
				
			}
		},
		"jsmart": {
			_compiled: {},
			checkScripts: function(core, onSuccess) {
				if(typeof(jSmart) == "undefined")
					$.getScript(core.baseScriptUrl + "smart.js", onSuccess);				
				else
					onSuccess();
			},
			processTemplate: function(templateId, dataset, extraInfo, onSuccess, onError) {
				var self = this;
				var cmpTmpl = self._compiled[ksg.ui.template.getTemplateId(templateId)];
				if(!(cmpTmpl)) {
					ksg.ui.template.loadTemplate(templateId, function(tmpl) {
						self._compiled[templateId] = cmpTmpl = new jSmart(tmpl);
						onSuccess(cmpTmpl.fetch(dataset), extraInfo);
					}, function(err) {
						onError(err, extraInfo);
					});				
				}
				else
					onSuccess(cmpTmpl.fetch(dataset), extraInfo);
			}
		},
		"jqtmpl": {
			checkScripts: function(core, onSuccess) {
				if(!($().tmpl))
					$.getScript(core.baseScriptUrl + "jquery.tmpl.min.js", onSuccess);				
				else
					onSuccess();
			},
			processTemplate: function(templateId, dataset, extraInfo, onSuccess, onError) {
				var self = this;
				ksg.ui.template.loadTemplate(templateId, function(tmpl) {
					onSuccess($(tmpl).tmpl(dataset), extraInfo);
				}, function(err) {
					onError(err, extraInfo);
				});
			}
		},
		"handlebars": {
			_compiled: {},
			checkScripts: function(core, onSuccess) {
				if(typeof(Handlebars) == "undefined")
					$.getScript(this.baseScriptUrl + "handlebars.1.0.0.beta.3.js", onSuccess);				
				else
					onSuccess();
			},
			processTemplate: function(templateId, dataset, extraInfo, onSuccess, onError) {
				var self = this;
				var cmpTmpl = self._compiled[ksg.ui.template.getTemplateId(templateId)];
				if(!(cmpTmpl)) {
					ksg.ui.template.loadTemplate(templateId, function(tmpl) {
						self._compiled[templateId] = cmpTmpl = Handlebars.compile(tmpl);
						onSuccess(cmpTmpl(dataset), extraInfo);
					}, function(err) {
						onError(err, extraInfo);
					});				
				}
				else
					onSuccess(cmpTmpl(dataset), extraInfo);
			}
		}
	}
}
/**
* @namespace
* namespace - All code items related to security.
* @Depends ksg.base.js
* @meta-type namespace
*/
ksg.security = {
	/**
	* @namespace
	* Always present, even if the user has not authenticated, provides access to details about
	* the current user such as preferences and privileges.
	* @meta-type static class
	*/
	currentUser: {
		settings: {}
	},
	
	/**
	* @class
	* The privilege level for a given security app function.
	* @type Enum
	*/
	Privileges: {
		/** The user has not been assigned a privilege level for the given security app function. */
		NotSet: -1,
		/** The user has no access to the item in any way. */
		None: 0,
		/** The security is derived from the context. Not typically used in JavaScript environment. */
		Derived: 1,
		/** The user can execute the item, but cannot view or edit the data associated with it. Not typically used in  JavaScript environment. */
		Execute: 2,
		/** The user can view items, but not edit, add or delete them. */
		ReadOnly: 3,
		/** The user can add new items, but cannot edit or delete items. */
		AddOnly: 4,
		/** The user can edit items, but cannot add or delete items. */
		EditOnly: 5,
		/** The user can add new items, and can edit items they added, but cannot add other items or delete items. */
		Edit: 6,
		/**  The user can add, edit and view items, but cannot delete them. */
		Add: 7,
		/** The user can delete, add, edit, and view items. */
		Delete: 8
	}
};

/**
* @Depends base.bizproc.js
*/
ksg.ui.bizprocs.alfrescoManagement = function(id, dataParams) {
	return new ksg.ui.BizProc(id, dataParams, {
		alfOptions: dataParams["alf-options"],
		options: {
			refreshListOnEditToggle: true,
			refreshListOnUpdate: true
		},
		bizRules: {
			getBizObjListBizRule: "getAlfArticles",
			updateBizRule: "updateAlfArticle",
			deleteBizRule: "deleteAlfArticle"
		},
		
		CurrentEditPrivilege: function() {
			return ksg.security.Privileges.Delete;
		},
		_getBizObjDetailRuleParameters: function(id) {
			return {
				id: id, stripLeading: !this.CanEdit()
			};
		},
		_getBizObjListRuleParameters: function() {
			var options = $.extend({			
				stripLeading: !this.CanEdit()
			}, this.alfOptions);
			var pid = this._getParentBizProcValue("pid");
			if(pid)
				options.id = pid;
			return options;
		}
	});
};/**
*
* @Depends ruleMgr.js
*/
ksg.bizrule.bizRules["getAlfArticles"] = function (options, onSuccess, onError) {
	var d = { "user": options.user, "pass": options.pass, "server": options.server, "type": options.type };
	var srvUrl = 'genericproxy.php?url=' + options.server + '/tools/application/webservice/jsonservice.php&full_headers=0&full_status=0&send_cookies=0&user_agent=0&mode=0&HTTP_X_REQUESTED_WITH=1'
	d.display = 'list';
	$.ajax({
		type: 'POST',
		crossDomain: true,
		dataType: 'text',
		data: 'user=' + options.user + '&pass=' + options.pass + '&type=' + options.type,
		url: srvUrl,
		success: function (data) {
			var str = JSON.parse(data.substring(data.indexOf('{')));
			var con = str.contents;
			con = con.substring(con.indexOf('{'));
			var jsond = JSON.parse(con);
			var bizObjs = new Array();
			for (var kn in jsond.blogs) 
				bizObjs.push(jsond.blogs[kn]);
			var response = { response: { bizObjs: bizObjs, total: jsond.total, type: d.type, bizObjType: 'alfresco'} };

			onSuccess(response);
		},
		error: function (jqXHR, textStatus, errorThrown) {
			onError(errorThrown);
		}
	});



};

ksg.bizrule.bizRules["getAlfArticleDetails"] = function (options) {
	/*
	$.ajax({
		contentType: "application/json; charset=utf-8",
		url: "http://alfresco.syrinxcs.com:8080/alfresco/service/api/blog/post/node/workspace/SpacesStore/eb2c4088-aa06-43d9-92be-eb32df00c37d",
		username: "admin",
		password: "admin",
		statusCode: {
			404: function () {
				alert('page request error!');
			}
		},
		success: function (data, textStatus, jqXHR) {
			alert($.param(data));
		},
		error: function (info, d, ex) {
			alert($.param(info));
		}
	});*/
};



/**
*
* @Depends /source/ksg.bizObjGrid.js
*/
(function ($) {

	$.extend(ksg.ui.grid.columnDefinitions, {
		//alfresco BizObj column types
		"alfresco-_id":{type:"key", dataField:"id"},
		"alfresco-title": { header: "Title", "type": "text", "width": 150 },
		"alfresco-url": { header: "url", "type": "text", "width": 150 }
	});

})(jQuery);
/**
* @namespace
* namespace - Contains all the code items related to using the various Google javascript libraries.
* @Depends ksg.base.ui.js
*/
ksg.google = {
	apiLoaded: false,
	initialized: false,
	loginToken: null,
	
	options: {
		apiVersion: "2.s",
		appId: "ksg-app2",
		baseScope: 'https://www.google.com/m8/feeds',
		autoAuthenticate: true,
		googleJsUrl: "http://www.google.com/jsapi",
		authenticationCheckTimeout: 2000
	},
	
	isAuthenticated: function() {
		return this.loginToken != null;
	},
	
	setupGoogleApi: function(pageOptions) {
		var self = this, options = $.extend(this.options, pageOptions);
		var doItNow = function() {
			var gdataLoaded = function() {
				if(options.services.indexOf("contacts") >= 0)
					self.contactsService = new google.gdata.contacts.ContactsService(options.appId);

				//The need to do a setTimeout is very disturbing to me.  There is a problem where the call
				//to google.accounts.user.login will cause the browser to continue to go between the google authorization
				//page and the page hosting this because there is a cookie setup happening that takes time if we check for 
				//this too early, it wont be set and it will think it needs to authenticate again, causing a redirection cycle.
				var auth = function() {
					self.initialized = true;			
						
					if(options.autoAuthenticate == true)
						self.authenticate();
					ksg.App.bizProcMgr.findAndInitDomBizProcs(false);
				};
				var stime = new Date().getTime();
				var checkLogin = function() {
					var x = google.accounts.user.checkLogin(options.baseScope);
					
					if((x != null && x != "" )|| stime + options.authenticationCheckTimeout < new Date().getTime())
						auth();
					else
						setTimeout(checkLogin, 100);					
				};
				//debugger;
				checkLogin();
			};
			
			google.load("gdata", options.apiVersion,{"callback" : gdataLoaded});
			ksg.google.apiLoaded = true;			
		};
		if(typeof (google) == "undefined")
			ksg.ui.loadScriptUrl(options.googleJsUrl, doItNow);
		else
			doItNow();
	},
	
	authenticate: function() {
		this.loginToken = google.accounts.user.login(this.options.baseScope);
		ksg.App.bizProcMgr.findAndInitDomBizProcs(false);
	}
};

try {
	ksg.App.configMgr.registerConfigPartner(function(options) {
		if(options.google)
			ksg.google.setupGoogleApi(options.google);
	});
}
catch(e) {
}
/**
*
* @Depends ksg.gridCore.js
*/
$.extend(ksg.ui.grid.columnDefinitions, {
	//gContact BizObj column types
	"gContact-_id":{type:"key", dataField:"id"},
	"gContact-firstName": {header:"First Name", "type":"text", "width": 120, dataField:"firstName"},
	"gContact-lastName": {header:"Last Name", "type":"text", "width": 140, dataField:"lastName"},
	"gContact-email": {header:"Email", "type":"text", "width": 200, dataField:"email"},
	"gContact-phone": {header:"Phone", "type":"text", "width": 100, dataField:"phone"}
});

/**
* BizObj for Google Contact data.
* @Depends feature.bizobj.js
*/
ksg.bizobj.bizObjTypes.GContact = function(obj){ 
	$.extend(this,obj);
};
 ksg.bizobj.bizObjTypes.GContact.prototype = {
	/** */
	_keyFieldName: "id",
	/** */
	avatarUrl: "",
	/** */
	firstName: "",
	/** */
	lastName: "",
	/** */
	email: "",
	/** */
	notes: ""
};
/**
*
* @Depends base.bizproc.js
*/
ksg.ui.bizprocs.gcontacts = function(id, dataParams) {
	return new ksg.ui.BizProc(id, dataParams, {
		options: {
			maxContactResults: 2000,
			baseContactFeed: "https://www.google.com/m8/feeds/contacts/default/full"
		},
		bizRules: {
			getBizObjListBizRule: "getGoogleContacts",
			updateBizRule: "updateGoogleContact",
			deleteBizRule: "deleteGoogleContact"
		},
		
		CurrentEditPrivilege: function() {
			return ksg.security.Privileges.Delete;
		},
		_getBizObjListRuleParameters: function() {
			return this.options;
		},
		_getDeleteBizObjRuleParams: function(id, bizObj) {
			return bizObj;
		},
		isReadyToGetInitialData: function() {
			var isIt = ksg.ui.BizProc.prototype.isReadyToGetInitialData.call(this);
			return isIt && ksg.google.isAuthenticated();
		}
	});
};
/**
* 
* @Depends ruleMgr.js
*/
/** @lends ksg.bizrule.bizRules# */
ksg.bizrule.bizRules["getGoogleContacts"] = function(options, onSuccess, onError) {
	//This rule cannot work if the google contacts service has not been setup, and if the user has not
	//authenticated against system system.  Although there are suposedly public contacts we can work with read 
	//only, these rules are currently only setup to work with the authenticated user's contacts.
	if(ksg.google.contactsService && ksg.google.loginToken) {
		var query = new google.gdata.contacts.ContactQuery(options.baseContactFeed);
		query.setMaxResults(options.maxContactResults);
		
		//This is the call to Google to get the list of contacts.
		//TODO this call could also take filter/sort criteria.  Once the core filter/sort mechanism
		//is setup for base.bizproc we should support it here.
		ksg.google.contactsService.getContactFeed(query,
			function(results) {
				//TODO this code creates a simple array for bizobjs but should be using ksg.App.bizObjMgr.createList(),
				//but that is not ready yet.
				var bizObjs = [], entries = results.feed.entry;
				for(var i in entries) {
					var entry = entries[i];
					var bizObj = ksg.App.bizObjMgr.create("GContact");
					bizObj._gContact = entry;
					bizObj.id = entry.getId().getValue();
					
					//Contact name
					var name = entry.getName();
					if(name) {
						if(name.getGivenName())
							bizObj.firstName = name.getGivenName().getValue();
						if(name.getFamilyName())
						bizObj.lastName = name.getFamilyName().getValue();
					}
					
					//Contact email
					var emailAddresses = entry.getEmailAddresses();
					if(emailAddresses && emailAddresses.length > 0)
						bizObj.email = emailAddresses[0].getAddress();

					//Contact avatar
					//TODO Figure out how the hell to get a valid href for the avatar photo set for the contact.
					//the href returned by the getContactPhotoLink() is actually not usable and needs to be setup with
					//the authentication token, but I am unaware of how to do that properly.  It is not just
					//adding ?token=options.loginToken.  For now, the avatar photo is broken link.
					bizObj.avatarUrl = entry.getContactPhotoLink().getHref();
					var q2 = new google.gdata.client.Query(bizObj.avatarUrl);
					var xx = ksg.google.contactsService.getFeed(q2, function(results) {
						var x = results;
					},
					function(error) {
						var y =error;
					});
					//------------
					
					//Contact phone
					var phones = entry.getPhoneNumbers();
					if(phones && phones.length > 0)
						bizObj.phone = phones[0].getValue();
					
					//Contact notes
					var jots = entry.getJots();
					if(jots && jots.length > 0)
						bizObj.jot = jots[0].getValue();
					
					//Contact addresses
					//TODO populate address list as bizobj list
										
					bizObjs.push(bizObj);
				}
				var rc = {
					response:{bizObjs:bizObjs}
				};
				onSuccess(rc);
			},
			function(error) {
				onError(error);
			});
	}
};


ksg.bizrule.bizRules["updateGoogleContact"] = function(contact, onSuccess, onError) {
	
	if(contact && contact._gContact) {
		var gCon = contact._gContact;
		var name = gCon.getName();
		if(name == null) {
			name = new google.gdata.Name();
			gCon.setName(name);
		}
		
		var setField = function(parentName, fieldName, val) {
			var parent = gCon["get"+parentName].call(gCon);
			if(parent["get"+fieldName]() == null)
				parent["set"+fieldName](new google.gdata[fieldName]());
			if(val == null)
				parent["set"+fieldName](null);
			else
				parent["get"+fieldName]().setValue(val);
		};
		var setFirstItemField = function(parentName, itemType, fieldName, val, itemType2) {
			if(itemType2 == null)
				itemType2 = itemType;
			var items = gCon["get"+parentName]();
			var hasItem = (items != null && items.length > 0);
			var item = hasItem?items[0]:new (ksg.bizobj.BizObj.getValue(google.gdata, itemType2))();
			item["set"+fieldName](val);	
			if(!hasItem)
				gCon["add"+itemType](item);
			return hasItem;
		};
		
		setField("Name", "GivenName", contact.firstName==""?null:contact.firstName);
		setField("Name", "FamilyName", contact.lastName==""?null:contact.lastName);
		setField("Name", "FullName", null);
		setFirstItemField("EmailAddresses", "EmailAddress", "Address", contact.email, "Email");
		setFirstItemField("EmailAddresses", "EmailAddress", "Rel", "http://schemas.google.com/g/2005#other", "Email");
		if(!setFirstItemField("PhoneNumbers", "PhoneNumber", "Value", contact.phone))
			setFirstItemField("PhoneNumbers", "PhoneNumber", "Label", "Phone");
		if(!setFirstItemField("Jots", "Jot", "Value", contact.jot, "contacts.Jot"))
			setFirstItemField("Jots", "Jot", "Rel", google.gdata.contacts.Jot.REL_OTHER);

		//This is the actual call to Google to update the contact.
		gCon.updateEntry(function(entryRoot) {
			var entry = entryRoot.entry;
			contact._gContact = entry;
			onSuccess(contact);
		},
		function(error) {
			//TODO this is not properly sending back the error as expected in the base bizproc.
			onError(error);
		});
	}	
};


ksg.bizrule.bizRules["deleteGoogleContact"] = function(contact, onSuccess, onError) {
	if(contact && contact._gContact) {
		var gCon = contact._gContact;
		gCon.deleteEntry(function() {
			onSuccess({});
		},
		function(error) {
			onError(error);
		});
	}
};

/**
* @class
* @augments ksg.ui.grid.BaseGrid
* @Depends ksg.gridCore.js
*/
ksg.ui.grid.WebServiceGrid = $.extend({}, ksg.ui.grid.BaseGrid, /** @lends ksg.ui.grid.WebServiceGrid# */{
	_internalCreate: function() {
		var options = this.options;
		this.dataHandler = ksg.ui.grid.dataHandlerFactory.webServices("id",options.serviceName, options.totalCountServiceName);
		this.templates = ksg.ui.grid.templateHandlers;
	},
	_internalDestroy: function() {
	},
	
	_internalResize: function() {
		if(resizeWin)
			resizeWin();
	},

	_internalInitGrid: function() {
		var $this = this.element, self = this, options = this.options;
		//# asp.net bizproc support
		if(typeof(bizProcManager) != 'undefined')
		bizProcManager.addAfterAjaxEventHandler(function (doc, eventInfo) {
			if (eventInfo.eventId.match(/update$/i) || eventInfo.eventId.match(/delete$/i)) {
				var x = 12;
				var sr = $this.find(".ksg-grid-rowArea ."+options.selectedRowClass);
				var curDepth = Number(sr.find('#depth').val());
				var tr = self._findParent(sr);
				var rsid = sr.find('.ksg-id').val();
				var sid = tr.find('.ksg-id').val().toString().replace(/-/g, '');
				curDepth = Number(tr.find('#depth').val());
				
				var moved = false, pid, pid2;
				if(typeof(options.parentBizProc) == "object") {
					pid = options.parentBizProc.getFieldValue("parentId");
					pid2 = pid;
					if(pid != null)
						pid2 = pid.toString().replace(/-/g, '')
					if(pid2 != sid)
						moved=true;
				}
				
				//This code is designed to refresh the portion of the tree that the selected id is contained within					
				self.dataHandler.getList(sid, options, function (bizObjList) {
					if(moved == true) {
						var row = self._findRowWithId(pid);
						if(row) {
							self.dataHandler.getList(pid2, options, function (bizObjList2) {
								self._removeChildren(tr);
								self._insertRows(bizObjList, {bizObjs:bizObjList, grid:self, options:options}, function() {
									self._removeChildren(row);
									self._insertRows(bizObjList2, {bizObjs:bizObjList2, grid:self, options:options}, function() {
										self._selectBizObj(rsid, true, false, true);
									}, row);
								}, tr);
							});
						}
						else
							self._removeChildren(tr);

					}
					else {
						self._removeChildren(tr);
						self._insertRows(bizObjList, {bizObjs:bizObjList, grid:self, options:options}, function() {
							self._selectBizObj(rsid, true, false, true);
						}, tr);
					}
					//TODO: Refresh totals in footer
					$this.trigger("tmplApplied");
				});
				
				refreshRow(sid, tr, moved);				
			}
		});
		//#---
	},
	
	_internalSelectBizObj: function(bizObjId) {
		var options = this.options;
		if(typeof(options.parentBizProc) == "object")
			options.parentBizProc.triggerEvent(null, "selectBizObj", bizObjId); 
	}
});

$.widget("ksg.webServiceGrid", ksg.ui.grid.WebServiceGrid);
ksg.ui.widgetMap.addWidget("ksg-standalone-bizobj-grid", function ($el, options) { 
	$el.webServiceGrid(options); 
});

ksg.ui.grid.dataHandlerFactory.webServices = function(idFieldName, getListServiceName, getTotalCountServiceName, generalListServiceNames ) {
	return {
		/**
		* Gets a list of objects to be shown either as the primarly root list of rows or
		* as a child set of rows from a parent row being opened up via the child visibility widget.
		*/
		getList: function(id, options, onSuccess) {
			var self = this;
			var listOptions = self._serviceOptions(id, options);
			var newOnSuccess = function(json) {
				var dataList = self._getDataListFromJsonResponse(json);
				if(onSuccess)
					onSuccess(dataList.bizObjs);
			},
			newOnError = function(err) {
			};
			
			ksg.services[getListServiceName](listOptions, newOnSuccess, newOnError);
		},
		
		shouldRequestChildListData: function() {
			return true;
		},
		
		_serviceOptions: function(id, options) {
			var runtimeOptions = {};

			if(id) {
				var idFieldName = this.getIdFieldName();
				if(idFieldName != "")
					runtimeOptions[idFieldName] = id;
			}
			
			return $.extend({}, options.baseServiceOptions, runtimeOptions);
		},
		getIdFieldName: function() {
			return idFieldName;
		},

		/**
		* When the grid is only shown a subset of rows at one time, this is used to get the total count.
		* This is an optional method that is only used if the getList method doesnt also return
		* the total count.  If this method returns null or -1 then the total will not be shown.
		*/
		getTotalPossibleCount: function(options, onSuccess) {
			var self = this;
			var listOptions = self._serviceOptions("", true, true,options);
			var newOnSuccess = function(json) {
				var dataList = self._getDataListFromJsonResponse(json);
				if(onSuccess)
					onSuccess(dataList);
			},
			newOnError = function(err) {
			};
			if(getTotalCountServiceName)
				ksg.services[getTotalCountServiceName](listOptions, newOnSuccess, newOnError);
		},
		/**
		* Used by cell editors to get generate lists of data needed to help edit.  This is particularly
		* used for dropdown control cell editors, which show a list of options to set the value of the field with.
		*/
		getGeneralList: function(name,options) {
		},
		
		/**
		* When the web servie returns json, this will process the response and give back just the data list
		* ready for use by the grid.
		*/
		_getDataListFromJsonResponse: function(json) {
			return json.response;
		},
		
		hasValue: function(obj, fieldName) {
			return ksg.bizobj.BizObj.hasValue(obj,fieldName);
		},
		getValue: function(obj, fieldName, defValue) {
			return ksg.bizobj.BizObj.getValue(obj,fieldName, defValue)
		},
		setValue: function(obj, fieldName, val) {
			//TODO setup set value
		}		
	};
}
$.extend(ksg.ui.widgetMap, {
	/**
	* @name scsArticles
	* @field 
	*/
	"ksg-articles": function ($el, options) {
		$el.articleListDisplay(options); 
	},
	"ksg-asp-articles": function ($el, options) {
		var cc = new ClientControl($el.get(0), setCpxBizObjListState, getCpxBizObjListState);
		var bizProc = bizProcManager.getBizProc(options.parentBizProc);
		if (bizProc != null) {
			bizProc.addClientControl(cc);
			cc.template = options.template;
			cc.getBizObjState = boL_getBizObjState;
			cc.getBizObjElement = boL_getBizObjElement;
			cc.prCh = boL_prCh;
			cc.isUpdateable = false;
			if(options.isUpdateable)
				cc.isUpdateable = options.isUpdateable;
			cc.maxElements = options.maxElements;
			cc.hasArtForm = options.hasArtForm;
		}
	},
	"ksg-asp-bizobj": function ($el, options) {
		var bizProc = bizProcManager.getBizProc(options.parentBizProc);
		if (bizProc != null) {
			var cc = new ClientControl($el.get(0), setBizObjDetailsState, getBizObjDetailsState);
			bizProc.addClientControl(cc);
			cc.uiFields = options.fields;
			cc.pushChildValues = function (bizobj) {
				for (var i = 0; i < this.uiFields.length; i++) {
					var f = ksg.ui.fields[this.uiFields[i].t];
					if(f)
						f.setVal($(document.getElementById(this.uiFields[i].id)), bizobj.getAttribute(this.uiFields[i].n), bizobj, this.uiFields[i].n);
					else {
						alert("pushChildValues: Cannot find field type: " + this.uiFields[i].t);
					}
				}
			}
			cc.pullChildValues = function (bizobj) {
				for (var i = 0; i < this.uiFields.length; i++) {
					var f = ksg.ui.fields[this.uiFields[i].t];
					if(f) {
						var v = f.getVal($(document.getElementById(this.uiFields[i].id)));
						if(v != null)
							bizobj.setAttribute(this.uiFields[i].n, v);
					}
					else {
						alert("pullChildValues: Cannot find field type: " + this.uiFields[i].t);
					}
				}
			}
			cc.getFieldValue = function(fieldName) {
				for (var i = 0; i < this.uiFields.length; i++) {
					if(this.uiFields[i].n == fieldName) {
						var f = ksg.ui.fields[this.uiFields[i].t];
						if(f) 
							return f.getVal($(document.getElementById(this.uiFields[i].id)));						
					}
				}
			}
		}
	},
	"ksg-asp-menu": function ($el, options) {
		var c = new ClientControl($el.get(0), setMenuState, getMenuState);
		var bizProc = bizProcManager.getBizProc("SyrinxMenu");
		if (bizProc != null)
			bizProc.addClientControl(c);
	},
	"ksg-asp-actionButton": function ($el, options) {
		var c = new ClientControl($el.get(0), setActionButtonState, getActionButtonState);
		if (options.visible == false)
			$el.hide();
		var bizProc = bizProcManager.getBizProc(options.parentBizProc);
		if (bizProc != null)
			bizProc.addClientControl(c);
	},
	"ksg-asp-calendar": function ($el, options) {
		var c = new ClientControl($el.get(0), setCalendarState, getCalendarState);
		var bizProc = bizProcManager.getBizProc(options.parentBizProc);
		if (bizProc != null)
			bizProc.addClientControl(c);
	}
});

//-----------

function parseUsaDate(date) {
    return new Date(date.replace(/^(\d+).(\d+).(\d+).(.*)$/, "$3/$1/$2 $4"));
};

function toUsaDate(date) {
    if (nitobi.base.DateMath.invalid(date)) {
        return "";
    }
    var pz = nitobi.lang.padZeros;
    return pz(date.getMonth() + 1) + "-" + pz(date.getDate()) + "-" + date.getFullYear();
};

//-----------

function getBizObjFromControl(clientId) {
    var docEl = nitobi.xml.createXmlDoc('<BizObj />').documentElement;
    eval("updateBizObj" + clientId + "(docEl);");
    return docEl;
}
function updateControlFromBizObj(clientId, bizobj) {
    eval("showBizObj" + clientId + "(bizobj);");
}

//-----------

function setComboSelectedRowByKey(combo, key) {
    var ds = combo.GetList().GetXmlDataSource();
    var numRows = ds.GetNumberRows();
    var setVal = false;
    for (var p = 0; p < numRows; p++)
        if (ds.GetRow(p)[0] == key) {
            $ntb(combo.GetId() + 'SelectedRowIndex').value = p;
            combo.GetList().SetSelectedRow(p);
            combo.SetTextValue(ds.GetRow(p)[1]);
            setVal = true;
            break;
        }
    if (!setVal)
        combo.SetTextValue(key);

}
function getComboSelectedRowKey(combo) {
    var fld = $ntb(combo.GetId() + 'SelectedValue0');
    return fld.value;
    //	var ds =combo.GetList().GetXmlDataSource();	
    //	var index = combo.GetList().GetSelectedRowIndex();
    //	if(index == -1)
    //		index = window.document.getElementById(combo.GetId()+'SelectedRowIndex').value;
    //	var numRows = ds.GetNumberRows();
    //	return (index == null || index < 0 || numRows == 0)?null:ds.GetRow(index)[0];
}

function setComboState(stateEl) {
    var refresh = stateEl.getAttribute('refresh');
    if (refresh != null && this.dhtmlObj.GetMode() != "unbound") {
        var cl = this.dhtmlObj.GetList();
        cl.Clear();
        cl._syx = this;
        cl.GetPage(0, 50, null, 0, null, function (EBAComboSearchNewRecords, list) {
            //setSelectedRowByKey(list._syx.dhtmlObj,list._syx.lastKey);
        });
    }
}

function getComboState(stateEl) {
    //	var lastKey = getSelectedRowKey(this.dhtmlObj);
    //	if((lastKey == null || lastKey.length == 0) && this.lastKey != null)
    //		lastKey = this.lastKey;
    //	//stateEl.setAttribute('selected', lastKey);
    //	stateEl.setAttribute('selected', this.dhtmlObj.GetList().GetSelectedRowIndex());
}


//-----------------
function setInnerHtmlWithScript(element, html) {
    document.getElementById(element).innerHTML = html;

    var re = /<script\b[\s\S]*?>([\s\S]*?)<\//ig;
    var match;
    while (match = re.exec(html)) {
        eval(match[1]);
    }
};


var globalEval = function globalEval(src) {
	if(src == null || src.length == 0)
		return;
    if (window.execScript) {
        window.execScript(src);
        return;
    }
    var fn = function () {
        window.eval.call(window, src);
    };
    fn();
};


//--- ExtendedGrid.js --------
var oldExtendedSetupGrid = null;
if (typeof(extendedSetupGrid) != "undefined")
    oldExtendedSetupGrid = extendedSetupGrid;

extendedSetupGrid = function (grid) {
    oldExtendedSetupGrid(grid);
    var bizProc = eval(eval(grid.ID + "ParentBizProc"));
    if (bizProc != null) {
        for (var pos = 0; pos < bizProc.ClientControls.length; pos++)
            if (bizProc.ClientControls[pos].id == grid.ID)
                return;

        grid.ClientControl = new ClientControl(grid, setGridState, getGridState);
        grid.ClientControl.id = grid.ID;
        bizProc.addClientControl(grid.ClientControl);
        grid.BizProc = bizProc;
    }
}
//oldExtendedSetupGrid = extendedSetupGrid;

function setGridState(stateEl) {
    var g = this.dhtmlObj;
	var rc = stateEl.getAttribute('rowCount');
	rc = Number(rc);
    if (stateEl.getAttribute('refresh') != null) {
        //this.dhtmlObj.refresh();
        var scrollPos = $ntb(g.ID + "_ScrollInfo").value;

        g.clearData();
        g.clearSurfaces();
        if (scrollPos != "NaN,NaN")
            g.subscribeOnce('DataReady', function () {
                try {
                    g.rowCount = rc;
					g.knownRowCount = rc;
                    g.setRowCount(rc);
                    g.setupGridScrollPosition(scrollPos);
                    window.setTimeout(function () {
                        g.setRowCount(rc); g.setupGridScrollPosition(scrollPos); g.activeCellObject = null; g.activeCell = null;
                    }, 50);
                } catch (e) { }
            }, null, new Array());
        g.dataBind();
    }
    else if (stateEl.getAttribute('rowCount') != null) {
        g.knownRowCount = rc;
        g.setRowCount(rc);
    }
	try{resizeWin();}catch(e){}
}

function getGridState(stateEl) {
    var hiddenField = document.getElementById(this.id + "_SelRowInfo");
    stateEl.setAttribute('selectedRows', hiddenField.value);

    if (this.dhtmlObj.datatable.log.selectNodes("//" + nitobi.xml.nsPrefix + "data/*").length != 0) {
        stateEl.setAttribute('updates', this.dhtmlObj.datatable.log.xml);
        this.dhtmlObj.datatable.flushLog();
    }
}

function gridCellFocus(eventArgs) {
    var grid = eventArgs.getSource();
    var cell = eventArgs.getCell();
    var row = cell.getRow();
    if (grid.syrinxLastRow != row) {
        grid.syrinxLastRow = row;
        if (grid.datatable.log.selectNodes("//" + nitobi.xml.nsPrefix + "data/*").length != 0) {
            grid.BizProc.triggerEvent(grid.ClientControl.id, 'bizObjUpdated', this.dhtmlObj.datatable.log.xml);
            this.dhtmlObj.datatable.flushLog();
        }
    }
}

function gridCellEditComplete(eventArgs) {
    try {
        if (eventArgs.getEvent().type == "blur" || eventArgs.getEvent().type == "keydown") {
            var cell = eventArgs.getCell();
            var col = cell.getColumn();
            var row = cell.getRow();
            var grid = eventArgs.getSource();
            var backward = eventArgs.getEvent().shiftKey;
            var keyCode = eventArgs.getEvent().keyCode;
            //var realBlur = true;
            var doUpdate = false;


            if (eventArgs.getEvent().type == "blur") {
                var lastKey = -1;
                try { lastKey = grid.cellEditor.lastKeyCode; } catch (e) { }
                if (lastKey == 13)
                    doUpdate = true;
            }
            else if (keyCode == 38 || keyCode == 40 || keyCode == 13)
                doUpdate = true;

            if (doUpdate && grid.datatable.log.selectNodes("//" + nitobi.xml.nsPrefix + "data/*").length != 0) {
                grid.BizProc.triggerEvent(grid.ID, 'bizObjUpdated', grid.datatable.log.xml);
                grid.datatable.flushLog();
            }
        }
    }
    catch (e) { }
}

function getSelectedRowAsJSON(gridId) {

}

function getGridRowInfo(gridId) {
    var g = nitobi.getComponent(gridId);
    var r = g.getSelectedRow();
    var c = g.columnCount();
    if (r == -1 || c == -1)
        return null;

    var docEl = nitobi.xml.createXmlDoc('<BizObj />').documentElement;
    for (var p = 0; p < c; p++) {
        var v = "";
        if (g.getColumnObject(p).getModel().getAttribute("editor") == "IMAGE")
            v = g.getCellValue(r, p);
        else {
            v = g.getCellText(r, p).replace(/&nbsp;/g, " ");
            if (v.match(/^\s*$/) != null)
                v = "";
        }
        docEl.setAttribute(g.getColumnObject(p).getModel().getAttribute("ColumnName"), v);
    }
    return docEl;
}
function updateGridRowInfo(gridId, bizobj) {
    if (bizobj == null)
        return;
    var g = nitobi.getComponent(gridId);
    var r = g.getSelectedRow();
    var c = g.columnCount();
    for (var p = 0; p < c; p++) {
        var n = g.getColumnObject(p).getModel().getAttribute("ColumnName");
        var a = bizobj.getAttributeNode(n);
        var nt = g.getColumnObject(p).getModel().getAttribute("editor");
        if (a != null && nt != "LISTBOX" && nt != "CHECKBOX")
            g.getCellObject(r, p).setValue(a.value, a.value);
    }
}

//--- GOgleMapGlobalScript.js
function setGMapState(stateEl) {
    try {
        var html = stateEl.getAttribute('html');
        if (html != null && html != '')
            this.dhtmlObj.innerHTML = html;

        var script = stateEl.getAttribute('script');
        if (script != null && script.length > 0)
            eval(script);
    } catch (e) { }
}
function getGMapState(stateEl) {
}

//--- EditImage.js --- 
function setScsImage(img, baseDir) {
    var media = window.showModalDialog(baseDir + "/popups/InsertImagePopup.aspx?T=Insert Image", null, "dialogWidth:750px;dialogHeight:500px;center:yes; resizable: yes; help: no");
    if (media != false && media != null) {
        $("#" + img).attr('src', media.mediaUrl);
    }
}

function clearScsImage(img) {
    $("#" + img).attr('src', '');
}

function getScsImageSrc($img, fullName) {
    var x = $img.attr('src');
    if (!fullName) {
        var r = x.match(/.*?\img\/[^\/]+\/[^\/]+\/(.*)$/);
        if (r != null)
            x = r[1];
    }
    if (x.toLowerCase() == "/images/blank.gif")
        x = "";
    return x;
}

//--- ArtForms.js
function findArtFormData(parentNames) {
    var names = parentNames.split(',');
    for (var c = 0; c < names.length; c++) {
        var parentElement = $ntb(names[c]);
        if (parentElement != null)
            return getArtFormData(parentElement);
    }
}
function getArtFormData(parentElement, el) {
    if (typeof validateFormFields == 'function')
        validateFormFields();

    if (el == null) {
        var doc = nitobi.xml.createXmlDoc('<ArtForm />');
        el = doc.documentElement;
    }
    addFormElements(parentElement, el);
    return el.xml;
}

function addFormElements(parentElement, docEl) {
    if (parentElement.hasChildNodes()) {
        var children = parentElement.childNodes;
        for (var i = 0; i < children.length; i++) {
            var child = children[i];
            if (child.nodeName.toUpperCase() == "INPUT") {
                var title = child.title;
                //docEl.setAttribute("InputType", child.type.toLowerCase());
                if (child.type.toLowerCase() == "checkbox") {
                    if (child.checked)
                        docEl.setAttribute(child.name, "true");
                    else
                        docEl.setAttribute(child.name, "false");

                }
                else if (child.type.toLowerCase() == "radio") {
                    if (child.checked)
                        docEl.setAttribute(child.name, child.value);
                }
                else
                    docEl.setAttribute(child.name, child.value);
                docEl.setAttribute(child.name + ".title", title);
            }
            else if (child.nodeName.toUpperCase() == "TEXTAREA") {
                //docEl.setAttribute("InputType", child.nodeName.toLowerCase());
                docEl.setAttribute(child.name, child.value);
            }
            else if (child.nodeName.toUpperCase() == "SELECT") {
                var v = child.value;
                if ((v == null || v == "") && child.selectedIndex > 0)
                    v = child.options[child.selectedIndex].text;

                docEl.setAttribute(child.name, v);
            }
            else
                addFormElements(child, docEl);
        }
    }

}

function showArtFormData(parentElement, xml) {
    if (xml == null || xml.length == 0)
        return;
    var doc = nitobi.xml.createXmlDoc(xml);
    var docEl = doc.documentElement;
    setupFormElements(parentElement, docEl);
    if (typeof setupFormFields == 'function')
        setupFormFields();
}

function setupFormElements(parentElement, docEl) {
    if (parentElement.hasChildNodes()) {
        var children = parentElement.childNodes;
        for (var i = 0; i < children.length; i++) {
            var child = children[i];
            var attrib = findXmlAttributeFromBaseName(child.name, docEl);
            // if(child.name != null && child.name != "" && docEl.getAttribute(child.name) != null)
            if (attrib != null) {
                if (child.nodeName.toUpperCase() == "INPUT") {
                    if (child.type.toLowerCase() == "checkbox") {
                        if (attrib.value == "true")
                            child.checked = true;
                        else
                            child.checked = false;
                        //child.checked = docEl.getAttribute(child.name)
                    }
                    else if (child.type.toLowerCase() == "radio") {
                        if (attrib.value == child.value)
                            child.checked = true;
                    }
                    else
                        child.value = attrib.value;
                }
                else if (child.nodeName.toUpperCase() == "TEXTAREA")
                    child.value = attrib.value;
                else if (child.nodeName.toUpperCase() == "SELECT")
                    for (var p = 0; p < child.options.length; p++)
                        if (child.options[p].value == attrib.value || child.options[p].text == attrib.value) {
                            child.options[p].selected = true;
                            child.selectedIndex = p;
                            break;
                        }
                        else
                            setupFormElements(child, docEl);
            }
            else
                setupFormElements(child, docEl);
        }
    }

}

function findXmlAttributeFromBaseName(baseName, docEl) {
    if (baseName != null && baseName.length > 0) {
        var attribs = docEl.attributes;
        for (var p = 0; p < attribs.length; p++)
            if (attribs[p].name == baseName || (attribs[p].name.length < baseName.length && baseName.substr(0, attribs[p].name.length) == attribs[p].name))
                return attribs[p];
    }
    return null;
}

function addCommas(nStr) {
    nStr += '';
    x = nStr.split('.');
    x1 = x[0];
    x2 = x.length > 1 ? '.' + x[1] : '';
    var rgx = /(\d+)(\d{3})/;
    while (rgx.test(x1)) {
        x1 = x1.replace(rgx, '$1' + ',' + '$2');
    }
    return x1 + x2;
}


//--- JQueryBaseLibrary.js ----
jQuery.cookie = function (key, value, options) {

    // key and value given, set cookie...
    if (arguments.length > 1 && (value === null || typeof value !== "object")) {
        options = jQuery.extend({}, options);

        if (value === null) {
            options.expires = -1;
        }

        if (typeof options.expires === 'number') {
            var days = options.expires, t = options.expires = new Date();
            t.setDate(t.getDate() + days);
        }

        return (document.cookie = [
            encodeURIComponent(key), '=',
            options.raw ? String(value) : encodeURIComponent(String(value)),
            options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
            options.path ? '; path=' + options.path : '',
            options.domain ? '; domain=' + options.domain : '',
            options.secure ? '; secure' : ''
        ].join(''));
    }

    // key and possibly options given, get cookie...
    options = value || {};
    var result, decode = options.raw ? function (s) { return s; } : decodeURIComponent;
    return (result = new RegExp('(?:^|; )' + encodeURIComponent(key) + '=([^;]*)').exec(document.cookie)) ? decode(result[1]) : null;
};



//--- ReadOnly.js ---
var globalEditChanges = false;
function navTo(evt) {
    var el = evt.srcElement;
    if (evt.altKey && el.contentEditable == "true")
        window.location.href = el.href;
}

function getROCTextValue(el) {
    var acEl = ($(el).children().length == 1 && $(el).children().first().attr('tagName') == 'A') ? $(el).children().first() : $(el);
    if (acEl.attr("contentEditable") == "true" && (acEl.attr("scsChanged") == "true" || acEl.attr("scsChanged") == true))
        return acEl.html();
    return null;
}

var notEditKeys = [9, 11, 17, 35, 36, 37, 38, 39, 49];
function isNoEditKey(k) {
    for (var p = 0; p < notEditKeys.length; p++)
        if (notEditKeys[p] == k)
            return true;
}

function fldChange(evt) {
    if (typeof (disableGlobalEditChanges) != "undefined" && bizProcManager.inEvent == true ||
        (typeof (disableGlobalEditChanges) != "undefined" && disableGlobalEditChanges == true))
        return;
    if (evt.type == "change" || (evt.type == "keydown" && !isNoEditKey(evt.keyCode))) {
        var el = evt.srcElement;
        if (el == null)
            el = evt.target;
        globalEditChanges = true;
        if (el != null)
            $(el).attr("scsChanged", true);
    }
}

function setupListeners() {
    $("input, textarea, select").each(function () {
        var t = $(this);
        if (!t.hasClass('notInEdit') && !this.id != null && this.id.match(/^__/) == null && this.scslis == null &&
                (this.type == null || this.type != "hidden") && t.closest(".notInEdit").length == 0) {
            t.change(function (e) { fldChange(e); });
            this.scslis = true;
        }
    });
    $(".CEDit").each(function () {
        if (!$(this).hasClass('notInEdit') && this.scslis == null) {
            $(this).keydown(function (e) { fldChange(e); });
            this.scslis = true;
        }
        if (this.tagName == "A")
            $(this).click(function (e) { { navTo(e); } });
    });
}

//$(window).unload(function () {
$(window).bind('beforeunload', function () {
    if (globalEditChanges) {
        globalEditChanges = false;
        if (confirm("You have unsaved changes.  Would you like to save them before navigating away?"))
            bizProcManager.triggerEvent(null, new EventInfo("globalEdit", "updateBizObj"), true);
    }
});
var confirmSave = null;
$(window).load(function () {
    if (typeof (disableGlobalEditChanges) != "undefined" && disableGlobalEditChanges == true)
        return;
    setupListeners();
	if(typeof (bizProcManager) != "undefined") {
		bizProcManager.addAfterAjaxEventHandler(function (doc, eventInfo) {
			if ((eventInfo.eventId != null && eventInfo.eventId.match(/_update$/) != null) ||
				(eventInfo.ctlId != null && eventInfo.ctlId.match(/_update$/) != null))
				globalEditChanges = false;
			setupListeners();
		});

		bizProcManager.addBeforeAjaxEventHandler(function (bizProc, eventInfo) {
			if ((eventInfo.eventId == "bizObjSelected" || eventInfo.eventId == "gm1") && globalEditChanges) {
				if (confirm("You have unsaved changes.  Would you like to save them before navigating away?")) {
					bizProcManager.triggerEvent(null, new EventInfo("globalEdit", "updateBizObj"), true);
					globalEditChanges = false;
				}
				else
					globalEditChanges = false;
			}
		});
	}
	ksg.App.bizProcMgr.addActionTriggerObserver({
		completed: function(actionStr) {
			if(actionStr.match(/update/i))
				globalEditChanges = false;
		}
	});
});

//--- ComplexBizObjListDisplay.cs ---
function checkAll(fromEl, onOff) {
    var els = document.getElementsByTagName('input');
    for (var c = 0; c < els.length; ++c)
        if (els[c].id.length > fromEl.length && els[c].id.substring(0, fromEl.length) == fromEl)
            els[c].checked = onOff;
}

function boL_getBizObjState(stateEl) {
    this.prCh(this.dhtmlObj, stateEl);
}

function boL_prCh(el, stateEl) {
    var idPat = /(.*)_(\d+)_(\d+)$/;
    var idPat2 = /(.*)_(\d+)$/;
    var cs = el.childNodes;
    for (var i = 0; i < cs.length; i++) {
        var c = cs[i];
        var id = c.id;
        if (id != null && id.match(idPat) != null) {
            var fieldName = findUniquePart(RegExp.$1, RegExp.$1);
            var row = RegExp.$2;
            var typeIndex = RegExp.$3;
            var bizObj = this.getBizObjElement(stateEl, row);
            try {
                var val = BizObjFieldTypes[typeIndex].script(c);
                if (val != null)
                    bizObj.setAttribute(fieldName, val);
            } catch (e) { }
        }
        else if (this.hasArtForm == true && $(c).hasClass('ArtForm') && id.match(idPat2) != null) {
            var row = RegExp.$2;
            var bizObj = this.getBizObjElement(stateEl, row);
            var fieldName = findUniquePart(RegExp.$1, RegExp.$1);
            var af = bizObj.ownerDocument.createElement(fieldName);
            bizObj.appendChild(af);
            getArtFormData(c, af);
        }
        else
            this.prCh(c, stateEl);
    }
}

function findUniquePart(fullId, shorterId) {
    try {
        var pos = shorterId.lastIndexOf('_');
        if (pos != -1) {
            var shorterId = shorterId.substr(0, pos);
            if (nitobi.html.getElement(shorterId) != null)
                return fullId.substr(pos + 1);
            else
                return findUniquePart(fullId, shorterId);
        }
        return fullId;
    }
    catch (err) {
        var x = err;
    }
}

function setCpxBizObjListState(stateEl) {
    this.template = stateEl.getAttribute('template');
    var html = stateEl.getAttribute('html');
    if (html != null && html != '')
        this.dhtmlObj.innerHTML = html;

    var script = stateEl.getAttribute('script');
    eval(script);
}

function getCpxBizObjListState(stateEl) {
    stateEl.setAttribute('template', this.template);
    stateEl.setAttribute('maxElements', this.maxElements);
    if (this.isUpdateable)
        this.getBizObjState(stateEl);
}

function boL_getBizObjElement(stateEl, rowNum) {
    var bizObj = stateEl.selectSingleNode('BizObj[@_row = \'' + rowNum + '\']');
    if (bizObj == null) {
        bizObj = stateEl.ownerDocument.createElement('BizObj');
        bizObj.setAttribute('_row', rowNum);
        stateEl.appendChild(bizObj);
    }
    return bizObj;
}

var BizObjFieldTypes = [
	{ type: 'textbox', script: function (dhtmlEl) { return dhtmlEl.value; } },
	{ type: 'hiddenfield', script: function (dhtmlEl) { return dhtmlEl.value; } },
	{ type: 'checkbox', script: function (dhtmlEl) { return dhtmlEl.checked ? 'True' : 'False'; } },
	{ type: 'dropdowncalendar', script: function (dhtmlEl) { return nitobi.html.getElement(dhtmlEl.id + 'Fld').value; } },
	{ type: 'nitobicomboboxbizobjlistdisplay', script: function (dhtmlEl) { return getSelectedRowKey(nitobi.getComponent(dhtmlEl.id + '_cm')); } },
    { type: 'combo', script: function (dhtmlEl) { return $ntb(dhtmlEl.id + 'SelectedValue0').value; } },
	{ type: 'radiobutton', script: function (dhtmlEl) { return dhtmlEl.checked ? 'True' : 'False'; } },
    { type: 'dropdownlist', script: function (dhtmlEl) { return dhtmlEl.options(dhtmlEl.selectedIndex).value; } },
    { type: 'editableimage', script: function (dhtmlEl) { var x = dhtmlEl.src; var i = x.indexOf('/img/'); if (i > 0) x = x.substr(i); return x; } },
	{ type: 'readonlytext', script: function (dhtmlEl) { return getROCTextValue(dhtmlEl) } }
];


//--- NitobiBizObjDisplay.cs ---
function setBizObjDetailsState(stateEl) {
    //var newMe = eval(this.id + 'cc');
    var html = stateEl.getAttribute('html');
    if (html != null && html != '') {
        this.dhtmlObj = $(html).replaceAll($(this.dhtmlObj)).get(0);
        var options = $(this.dhtmlObj).data("options");
        this.uiFields = options.fields;
    }


    var script = stateEl.getAttribute('script');
    globalEval(script);
    var bizObj = stateEl.selectSingleNode('BizObj');
    if(bizObj)
        this.pushChildValues(bizObj);

//    var procs = bizProcManager.bizProcs;
//    var c = null;
//    for (var bps in procs)
//        if (bps != 'toJSONString' && (procs[bps].ClientControls.length == 0 || (c = nitobi.html.getElement(procs[bps].ClientControls[0].id)) == null || c.parentNode == null)) {
//            procs[bps].dead = true;
//        }

//    var newBps = new Array();
//    for (var bps in bizProcManager.bizProcs)
//        if (bps != 'toJSONString' && !procs[bps].dead)
//            newBps.push(procs[bps]);
//    bizProcManager.bizProcs = newBps;

    //TODO: This should be in ArticleTranslationDisplay, but for now its here.
    var formData = stateEl.getAttribute('formData');
    if (formData != null)
        showArtFormData(this.dhtmlObj, formData);
}

function getBizObjDetailsState(stateEl) {
    var bizobj = stateEl.ownerDocument.createElement('BizObj');
    stateEl.appendChild(bizobj);
    if (this.pullChildValues != null)
        this.pullChildValues(bizobj);
}

//--- NitobiPaginationDisplay.cs ---
function setPaginationState(stateEl) {
    try {
        var html = stateEl.getAttribute('html');
        if (html != null && html != '')
            this.dhtmlObj.innerHTML = html;
    } catch (e) { }
}
function getPaginationState(stateEl) {
}


//--- OldAnimi.js ---
function animi(pname, it, fs, dt) {
    this.prt = document.getElementById(pname);
    this.pos = -1;
    this.dt = dt; this.it = it;
    this.dp = 0; this.fs = fs;
    eval(pname + "a=this");
}
animi.prototype.go = function () {
    var lp = this.pos, prt = this.prt, chlds = $(prt).find("." + this.it); //childNodes;
    if (chlds.length <= 1) {
        chlds.css("display", "block");
        return;
    }
    for (var p = ((lp >= chlds.length - 1) ? -1 : lp) + 1; p < chlds.length; p = (p == chlds.length - 1) ? 0 : p + 1) {
        var c = chlds.eq(p);
        if (lp >= 0) chlds.eq(lp).fadeOut(this.fs);
        c.css("top", "0px").css("display", "none");
        c.fadeIn(this.fs);
        this.pos = p;
        setTimeout(prt.id + "a.go()", this.dt[this.dp]); this.dp++;
        if (this.dp == this.dt.length) this.dp = 0;
        return;
    }
}

//--- menu startup ---
function setMenuState(stateEl) {
    try {
        var html = stateEl.getAttribute('html');
        if (html != null && html != '') {
            $('#' + this.id).replaceWith(html);
            setupMenuEvents();
        }
    } catch (e) { }
}
function getMenuState(stateEl) {

}

//--- Action Button ---
function setActionButtonState(stateEl) {
    try {
        this.dhtmlObj.disabled = stateEl.getAttribute('enabled').toLowerCase() == 'true' ? false : true;
        this.dhtmlObj.style.display = stateEl.getAttribute('visible').toLowerCase() == 'true' ? 'inline' : 'none';
        var label = stateEl.getAttributeNode('label');
        if (label != null)
            this.dhtmlObj.innerHTML = label.text;
    } catch (e) { }
}
function getActionButtonState(stateEl) {
    try { stateEl.setAttribute('action', this.dhtmlObj.name); } catch (e) { }
}

$(document).ready(function () {
    $(".searchField").keydown(function (e) {
        if (e.which == 13) {
            $('.SearchBtn').click();
        }
    }).click(function () {
        this.select();
    });
});

//---Calendar ---
function setCalendarState(stateEl)
{
	try {
		var title = stateEl.getAttribute('title');
		var body = stateEl.getAttribute('body');
		if(body != null && body != '')
		{
			if ($('#' + this.id + ' .CalTitle').length != 0) {
				$('#' + this.id + ' .CalTitle').replaceWith(title);
				$('#' + this.id + ' .CalBody').replaceWith(body);
			}
			else {
				$('#' + this.id).html(title + body);
				
			}
		}
		setCalSizeNow();
		var script = stateEl.getAttribute('script');
		if(script != null && script.length > 0)
			eval(script);
	}catch(e){}	
}

function getCalendarState(stateEl)
{
	//Calendar control is currently read only.
}
function BizProcCoordinator(pageId, baseUrl) {
    this.pageId = pageId;
    this.baseUrl = baseUrl + '?';
    this.bizProcs = new Array();
    this.inEvent = false;
    this.afterAjaxEventHandlers = new Array();
    this.beforeAjaxEventHandlers = new Array();
}

BizProcCoordinator.prototype = {
	addAfterAjaxEventHandler: function (handler) {
		this.afterAjaxEventHandlers.push(handler);
	},

	addBeforeAjaxEventHandler: function (handler) {
		this.beforeAjaxEventHandlers.push(handler);
	},

	addBizProc: function (bizProc) {
		this.bizProcs.push(bizProc);
	},

	getBizProc: function (id) {
		for (var i = 0; i < this.bizProcs.length; i++)
			if (this.bizProcs[i].id == id)
				return this.bizProcs[i];
		return null;
	},

	refreshPage: function () {
		window.location.href = window.location.href;
	},

	triggerEvent: function (bizProc, eventInfo, forceSyncRequest) {
		if (this.inEvent) {
			this.lastEvent = [bizProc, eventInfo];
			return; //Blow off event trigger if in an event already!
		}

		var cont = true;
		for (var p = 0; p < this.beforeAjaxEventHandlers.length; p++)
			try {
				var rc = this.beforeAjaxEventHandlers[p](bizProc, eventInfo);
				if (cont && rc == false)
					cont = false;
			} catch (e) {
			}

		if (!cont)
			return;

		this.disabledButtons = new Array();
		if (eventInfo.disableButtons == true) {
			$(".AcBut").each(function (i) {
				if (!this.disabled) {
					bizProcManager.disabledButtons.push(this);
					this.disabled = true;
				}
			});
			$(".AjaxIndi").css("display", "inline");
		}
		this.inEvent = true;
		try {
			var doc = ksg.util.createXmlDoc('<ClientEvent />');
			var docEl = doc.documentElement;
			docEl.setAttribute('bizProcId', bizProc == null ? '' : bizProc.id);
			eventInfo.addState(docEl);
			for (var p = 0; p < this.bizProcs.length; p++)
				this.processBizProc(doc, docEl, this.bizProcs[p]);

			return this.sendRequest(doc, eventInfo, forceSyncRequest);
		}
		catch (e) {
			//alert("error:" + e);
			this.releaseWaitState();
		}
	},

	processBizProc: function (doc, docEl, bizProc) {
		var bizProcEl = doc.createElement('BizProc');
		bizProc.getState(bizProcEl);
		docEl.appendChild(bizProcEl);
	},

	sendRequest: function (doc, eventInfo, forceSyncRequest, attemptNum) {
		var attempt = 1;
		if (attemptNum != null)
			attempt = attemptNum;
		if (attempt > 3) {
			this.releaseWaitState();
			alert("General Failure Communicating With Web Site.");
			return;
		}
		if (doc == null) return;
		var d = ksg.util.createXmlString(doc.documentElement);
		var u = this.baseUrl + 'pi=' + this.pageId + '&RequestType=' + doc.documentElement.getAttribute('event');
		var async = forceSyncRequest ? false : true;
		$.ajax({ type: "POST", async: async,
			url: u,
			data: d,
			processData: false,
			dataType: "xml",
			contentType: "text/xml",
			success: function (doc) { bizProcManager.processWebResponse(doc, eventInfo); if (eventInfo.eventHandler != null) eventInfo.eventHandler(); },
			error: function (a, b, c) {
				setTimeout(function () { bizProcManager.sendRequest(doc, eventInfo, forceSyncRequest, attempt + 1); }, 200);
			}
		});
	},

	releaseWaitState: function () {
		this.inEvent = false;
		for (var i = 0; i < this.disabledButtons.length; i++)
			try { this.disabledButtons[i].disabled = false; } catch (e) { }
		$(".AjaxIndi").css("display", "none");
	},

	processWebResponse: function (doc, eventInfo) {
		if (doc.documentElement != null && doc.documentElement.getAttribute("gotoView") != null) {
			this.inEvent = false; //Needed incase an unload ajax event happens.
			window.location.href = doc.documentElement.getAttribute("gotoView");
		}
		else {
			try {
				var tempBizProcs = new Array();
				var firstLen = this.bizProcs.length;
				for (var pos = 0; pos < this.bizProcs.length; pos++) {
					var process = true;
					for (var p2 = 0; p2 < tempBizProcs.length; p2++) {
						if (tempBizProcs[p2] == this.bizProcs[pos]) {
							process = false;
							break;
						}
					}
					if (process) {
						tempBizProcs.push(this.bizProcs[pos]);
						var bpid = this.bizProcs[pos].id;
						this.bizProcs[pos].processControlStates(doc);
						if (firstLen != this.bizProcs.length) {
							pos = 0;
							firstLen = this.bizProcs.length;
						}
					}
				}
			}
			catch (e) {
				alert("Error:" + e);
			}

			this.releaseWaitState();

			var indEls = doc.selectNodes("//ControlStates/State[@independent = 'true']");
			if (indEls != null)
				for (var i = 0; i < indEls.length; i++) {
					var script = indEls[i].getAttribute("script");
					if (script != null && script != "")
						try { eval(script); } catch (e) { }
				}

			for (var p = 0; p < this.afterAjaxEventHandlers.length; p++)
				try {
					this.afterAjaxEventHandlers[p](doc, eventInfo);
				} catch (e) {
				}

			if (this.lastEvent != null) {
				var l = this.lastEvent;
				this.lastEvent = null;
				this.triggerEvent(l[0], l[1]);
			}
			return (doc.documentElement == null) ? "" : doc.documentElement.getAttribute("curId");
		}
	}
}


function EventInfo(ctlId, eventId, val, eventHandler, disableButtons) {
    this.disableButtons = disableButtons == false ? false : true;
    this.ctlId = ctlId;
    this.eventId = eventId;
    this.val = val;
    this.eventHandler = eventHandler;
}

EventInfo.prototype.addState = function (eventEl) {
    eventEl.setAttribute('event', this.eventId);
    eventEl.setAttribute('id', this.ctlId);
    if (this.val != null)
        eventEl.setAttribute('value', this.val);
}
function ClientBizProc(id) {
    this.id = id;
    this.ClientControls = new Array();
    bizProcManager.addBizProc(this);
}

ClientBizProc.prototype.addClientControl = function (ctl) {
    for (var pos = 0; pos < this.ClientControls.length; pos++)
        if (this.ClientControls[pos].id == ctl.id) {
            this.ClientControls[pos] = ctl;
            return;
        }
    this.ClientControls[this.ClientControls.length] = ctl;
}

ClientBizProc.prototype.triggerEvent = function (ctlId, eventId, val, eventHandler, disableButtons) {
    try {
        if (ctlId == null)
            ctlId = this.id;
        bizProcManager.triggerEvent(this, new EventInfo(ctlId, eventId, val, eventHandler, disableButtons));
    }
    catch (e) { }
}

ClientBizProc.prototype.getState = function (bizProcEl) {
    bizProcEl.setAttribute('id', this.id);
    this.insertControlStates(bizProcEl.ownerDocument, bizProcEl);
}

ClientBizProc.prototype.getFieldValue = function(fieldName) {
    for (var pos = 0; pos < this.ClientControls.length; pos++) {
        var clientCtl = this.ClientControls[pos];
		if(clientCtl.getFieldValue){
			var v = clientCtl.getFieldValue(fieldName);
			if(v)
				return v;
		}
	}
}

ClientBizProc.prototype.processControlStates = function (doc) {
    for (var pos = 0; pos < this.ClientControls.length; pos++) {
        var clientCtl = this.ClientControls[pos];
        var clientId = clientCtl.id;
        if (clientCtl.dhtmlObj != null) {
            if (clientId == null || clientId == '')
                clientId = clientCtl.dhtmlObj.id;
            var stateEl = doc.selectSingleNode("//ControlStates/State[@id = '" + clientId + "']");
            if (stateEl != null && clientCtl.setState != null)
                clientCtl.setState(stateEl);
        }
    }
}

ClientBizProc.prototype.insertControlStates = function (doc, bizProcEl) {
    var states = doc.createElement('ControlStates');
    bizProcEl.appendChild(states);
    for (var pos = 0; pos < this.ClientControls.length; pos++) {
        var clientCtl = this.ClientControls[pos];
        if (clientCtl.getState != null && clientCtl.dhtmlObj != null) {
            var stateEl = doc.createElement('State');
            var clientId = clientCtl.id;
            if (clientId == null || clientId == '')
                clientId = clientCtl.dhtmlObj.id;
            stateEl.setAttribute('id', clientId);
            this.ClientControls[pos].getState(stateEl);
            states.appendChild(stateEl);
        }
    }
}

function ClientControl(dhtmlObj, setStateFun, getStateFun, showBizObjFun, updateBizObjFun) {
    this.dhtmlObj = dhtmlObj;
    this.setState = setStateFun;
    this.getState = getStateFun;
    this.showBizObj = showBizObjFun;
    this.updateBizObj = updateBizObjFun;
    if (dhtmlObj != null)
        this.id = dhtmlObj.id;
}

/**
* @Depends base.bizproc.js
*/
ksg.ui.bizprocs.articleManagement = function(id, dataParams) {
	return new ksg.ui.BizProc(id, dataParams, {
		artOptions: dataParams["art-options"],
		options: {
			refreshListOnEditToggle: true,
			refreshListOnUpdate: true
		},
		bizRules: {
			getBizObjListBizRule: "getArticles",
			getBizObjBizRule: "getArticle",
			updateBizRule: "updateArticle",
			deleteBizRule: "deleteArticle"
		},
		
		CurrentEditPrivilege: function() {
			return ksg.security.Privileges.Delete;
		},
		_getBizObjDetailRuleParameters: function(id) {
			return {
				id: id, stripLeading: !this.CanEdit()
			};
		},
		_getBizObjListRuleParameters: function() {
			var options = $.extend({			
				stripLeading: !this.CanEdit()
			},this.artOptions);
			var pid = this._getParentBizProcValue("pid");
			if(pid)
				options.id = pid;
				
			return options;
			
		}
	});
};


//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of Syrinx Community Server (SCS).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==

/**
* ArticleListDisplay
*/
(function ($) {
    var methods = {
        init: function (options) {

            return this.each(function () {

                var $this = $(this),
             data = $this.data('listDisp');

                // If the plugin hasn't been initialized yet
                if (!data) {

                    /*
                    Do more setup stuff here
                    */

                    $(this).data('listDisp', {
                        target: $this,
                        options: options,
                        setupPager: false
                    });

                }
				if($this.children().length == 0)
					methods.showPage.apply(this, [1]);
            });
        },
        destroy: function () {

            return this.each(function () {

                var $this = $(this),
             data = $this.data('listDisp');

                $this.removeData('listDisp');

            })

        },
        showPage: function (pageNum) {
            var $this = $(this), data = $this.data('listDisp');
            var pagerId = "#" + $this.attr("id") + "-pager";
            data.options.page = pageNum;
            ksg.services.getArticles(data.options, function (json) {
                if (!data.setupPager) {
                    data.setupPager = true;
                    var numPages = (json.response.total / data.options.pageSize);
                    if (numPages > 1) {
                        var $pp = (typeof (data.options.pagerTemplateId) == "undefined") ? $("#" + $this.attr("id") + "-pager-page") : $(data.options.pagerTemplateId);
                        for (var p = 0; p < numPages; p++)
                            $pp.tmpl({ index: p + 1 }).appendTo(pagerId);

                        $(pagerId + " .page-selector").bind('click', function () {
                            methods.showPage.apply($this.get(0), [Number(this.id.substr(1))]);
                        });
                    }
                }
                data.totalRows = json.response.total;
                var $tmpl = (typeof (json.template) != "undefined") ? $(json.template) : null;
                if (data.options.templateId != null && typeof (data.options.templateId) != "undefined")
                    $tmpl = $(data.options.templateId);
                var resourceUrl = json.resourceUrl;
                if (data.options.resourceUrl != null && typeof (data.options.resourceUrl) != "undefined")
                    resourceUrl = data.options.resourceUrl;

                $(pagerId + " li.page-selector").removeClass("active");
                $(pagerId + " #i" + pageNum + ".page-selector").addClass("active");
                $this.children().remove();
                $tmpl.tmpl(json.response.bizObjs, $.extend({ resourceUrl: json.response.resourceUrl }, ksg.bizobj.bizObjTypes.Article)).appendTo($this);
                $this.trigger("tmplApplied");
            },
        function (e) {
            var x = e;
        });
        }
    };

    $.fn.articleListDisplay = function (method) {
        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, arguments);
        } else {
            $.error('Method ' + method + ' does not exist on jQuery.articleListDisplay');
        }

    };


})(jQuery);

/**
*
* @Depends ksg.gridCore.js
*/
(function ($) {

	$.extend(ksg.ui.grid.columnDefinitions, {
		//Article BizObj column types
		"article-_id":{type:"key", dataField:"id"},
		"article-title": {header:"Title", "type":"text", "width": 300},
		"article-uniqueTitle": {header:"Unique Title", "type":"text", "width": 150},
		"article-image": {header:"Img", "type":"image", "width": 350, dataField: "primaryPicture.name"},
		"article-numChild": {header:"# C", "type":"number", "width": 350, dataField: "counts.totalL1"},
		"article-numViews": {header:"# V", "type":"number", "width": 350, dataField: "counts.totalViews"},
		"article-updatedBy": {header:"Updated By", "type":"text", "width": 350, dataField: "counts.lastChildUpdatedBy.userName"},
		"article-updatedOn": {header:"Updated On", "type":"date", "width": 350, dataField: "counts.dateUpdated"},
		"article-createdBy": {header:"Created By", "type":"text", "width": 100, dataField: "counts.author.userName"},
		"article-createdOn": {header:"Created On", "type":"date", "width": 150, dataField: "counts.dateCreated"},
		
		"article-suggestedDisplayType": {header:"Type", type:"text", width:150}
		
	});

})(jQuery);
/**
*
* @Depends ksg.gridCore.js
*/
(function ($) {
    $.extend(ksg.ui.grid.columnDefinitions, {
        //Media BizObj column types
        "attachement-gridImage": { header: "Icon", "type": "text", "width": 40 },
        "attachement-filePathName": { header: "Path", "type": "text", "width": 330 },
        "attachement-description": { header: "Description", "type": "text", "width": 330 },
        "attachement-fileCacheName": {header: "File Cache Name", "type" : "text","width":120}
    });
})(jQuery);

/**
* @Depends ksg.base.services.js
*/
$.extend(ksg.services, /** @lends ksg.services# */{
    getArticleCount: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/getArticleCount/" + options.id, success, error, "x" + options.id, options);
    },
    getArticle: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/getArticle/", success, error, "x" + options.id.replace(/-/g, ""), options);
    },
    getArticles: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/getArticles/" + options.id, success, error, "x" + options.id.replace(/-/g, ""), options);
    },
    updateArticle: function (article, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/updateArticle/", success, error, null, article);
    },
    deleteArticle: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteArticle/", success, error, null, options);
    },
    deleteArticleContentFilter: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteArticleContentFilter/", success, error, null, options);
    },
    deleteArticleContentFilter: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteArticleContentFilter/", success, error, null, options);
    },
    deleteArticleAttachmentGroupFile: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteArticleAttachmentGroupFile/", success, error, null, options);
    },
    getArticleAttachmentGroupFiles: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/getArticleAttachmentGroupFiles/" + options.id, success, error, "x" + options.id, options);
    },
    getArticleAttachmentGroups: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/getArticleAttachmentGroups/" + options.id, success, error, "x" + options.id, options);
    }

});

/**
* @Depends ksg.base.services.js
*/
$.extend(ksg.services, /** @lends ksg.services# */{
    deleteSiteSync: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteSiteSync/", success, error, null, options);
    }
});
/**
*
* @Depends ksg.gridCore.js
*/
(function ($) {
    $.extend(ksg.ui.grid.columnDefinitions, {
        //Media BizObj column types
		"calendar-_id":{type:"key", dataField:"id"},
        "calendar-keyName": { header: "Name", "type": "text", "width": 300 }
    });
})(jQuery);

/**
* @Depends ksg.base.services.js
*/
$.extend(ksg.services, {
    getCalendars: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/getCalendars", success, error, null, options);
    },
    getCalendarEventTypes: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/getCalendarEventTypes/", success, error, null, options);
    },
    deleteCalendar: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteCalendar/", success, error, null, options);
    },
    deleteCalendarEvent: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteCalendarEvent/", success, error, null, options);
    },
    deleteCalendar: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteCalendar/", success, error, null, options);
    }
});
/**
* @Depends feature.bizobj.js
*/
ksg.bizobj.bizObjTypes.Category = function(obj){ 
	$.extend(this,obj);
};
 ksg.bizobj.bizObjTypes.Category.prototype = {
	_keyFieldName: "id",
	
	id: null,
	categorySetId: null,
	displayName: "",
	keyword: "",
	openGraphName: "",
	matchCount: 0,
	onlyCatagories: false,
	primaryImage: "",
	showInPublicListings: true,
	properties: ksg.App.bizObjMgr.createList("CategoryProperty"),
	
	name: function() { var self = this;
		var dn = self.getItem("displayName");
		if(Cmn.IsEmpty(dn))
			dn = self.getItem("keyword");
		return dn;
	},
	nameWithCount: function() {
		return self.getItem("name") + "&nbsp;(" + self.getItem("matchCount") + ")";
	},
	
	testMe: function() {return "hello";}
};
/**
*
* @Depends ksg.gridCore.js
*/
(function ($) {
    $.extend(ksg.ui.grid.columnDefinitions, {
        //Media BizObj column types
        "calendarEventType-title": { header: "Title", "type": "text", "width": 300 }
    });
})(jQuery);

/**
*
* @Depends ksg.gridCore.js
*/
(function ($) {

	$.extend(ksg.ui.grid.columnDefinitions, {
		//CategorySet BizObj column types
		"categorySet-_id" : {"type":"key", "dataField": "id"},
        "categorySet-type": {header:"Type", dataField: "associable.bizObjType", "type":"dropdown", "getListService": "getCategorySetTypes"},
        "categorySet-name": {header:"Name", "type":"text"},
        "categorySet-associableDisplayInfo": {header:"Associated Info", "type":"dropdown", "getListService": "getCategoryAssociableTypes", "getListServiceParams":"$colVal('type')$", "textField": "displayName"},
		
		//Category BizObj column types
		"category-_id" : {"type":"key", "dataField": "id"},
        "category-image":{header:"Image", dataField:"primaryImage", "type": "image", "width": 80},
        "category-displayName":{header:"Display Name", "type": "text", "width": 150},
        "category-keyword":{header:"Searchable Keyword", "type": "text", "width": 150},
        "category-inListing":{header:"In Listings", dataField:"showInPublicListings", "type": "checkbox", "width": 50},
        "category-openGraphName":{header:"Open Graph Name", "type": "dropdown", "width": 150, "getListService": "getOpenGraphNames", "updateItemService": "updateOpenGraphName"},
		
		//CategoryProperty BizObj column types
		"categoryProperty-_id" : {"type":"key", "dataField": "id"},
		"categoryProperty-propertyName" : {header:"Name", "type": "text"},
		"categoryProperty-displayName" : {header:"Display Label", "type": "text"},
		"categoryProperty-propertyType" : {header:"Type", "type": "dropdown", "getListService": "getCategoryPropertyTypes", "updateItemService": "updateCategoryPropertyType"},
		"categoryProperty-propertyOptions" : {header:"Options", "type": "text"},
		"categoryProperty-isSecure" : {header:"Secure", "type": "checkbox"}				
	});

})(jQuery);
/**
* @Depends ksg.base.services.js
*/
$.extend(ksg.services, /** @lends ksg.services# */{
    getCategorySets: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/getCategorySets/", success, error, null, options);
    },
    getCategories: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/getCategories/", success, error, null, options);
    },
    getCategoryProperties: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/getCategoryProperties/", success, error, null, options);
    },
    deleteCategoryset: function (options, sucess, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteCategoryset/", success, error, null, options);
    },
    deleteCategorySetCategory: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteCategorySetCategory/", success, error, null, options);
    },
    deleteCategoryProperty: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteCategoryProperty/", success, error, null, options);
    }
});
/**
*
* @Depends ksg.gridCore.js
*/
(function ($) {
    $.extend(ksg.ui.grid.columnDefinitions, {
        //Contact BizObj column types
        "contact-_id": { type: "key", dataField: "id" },
        "contact-firstName": { header: "First Name", "type": "text", "width": 100 },
        "contact-lastName": { header: "Last Name", "type": "text", "width": 125 },
        "contact-typeName": { header: "Type Name", "type": "text", "width": 80, dataField: "type.name" },
        "contact-email": { header: "Email", "type": "text", "width": 100 },
        "contact-phone": { header: "Phone", "type": "text", "width": 100 },
        "contact-companyName": {header:"Company Name","type":"text","width":150}
    });
})(jQuery);

/**
* @Depends ksg.base.services.js
*/
$.extend(ksg.services, /** @lends ksg.services# */{
	getContact: function (options, success, error) {
		ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/getContact", success, error, null, options);
	},
	getContactCount: function (options, success, error) {
		ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/getContactCount", success, error, null, options);
	},
	getContacts: function (options, success, error) {
		ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/getContacts", success, error, null, options);
	},
    deleteContactType: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteContactType", success, error, null, options);
    },
    deleteAddressType: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteAddressType", success, error, null, options);
    },
    deleteContact: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteContact", success, error, null, options);
    }	
});
/**
* @Depends ksg.base.services.js
*/
$.extend(ksg.services, {
    deleteBizObjDefinition: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteBizObjDefinition/", success, error, null, options);
    },
    deleteBizObjField: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteBizObjField/", success, error, null, options);
    },
    deleteDynBizObjAssociation: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteDynBizObjAssociation/", success, error, null, options);
    },
    deleteBizObjInstance: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteBizObjInstance/", success, error, null, options);
    }
});
/**
* @Depends ksg.base.services.js
*/
$.extend(ksg.services, {
    deleteProduct: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteProduct/", success, error, null, options);
    },
    deleteSalesOrder: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteSalesOrder/", success, error, null, options);
    },
    deleteSalesOrderItem: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteSalesOrderItem/", success, error, null, options);
    },
    deleteProductSpecificShippingBox: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteProductSpecificShippingBox/", success, error, null, options);
    },
    deleteOrderHandlingFee: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteOrderHandlingFee/", success, error, null, options);
    },
    deleteQuantityDiscount: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteQuantityDiscount/", success, error, null, options);
    },
    deleteCodedDiscount: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteCodedDiscount/", success, error, null, options);
    },
    deleteTaxDefinition: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteTaxDefinition/", success, error, null, options);
    },
    deleteRegionalSalesTax: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteRegionalSalesTax/", success, error, null, options);
    }
});
/**
* @Depends ksg.base.services.js
*/
$.extend(ksg.services, {
    deleteCompanyPaymentProcessor: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteCompanyPaymentProcessor/", success, error, null, options);
    }
});
/**
* @Depends ksg.base.services.js
*/
$.extend(ksg.services, {
    deleteShippingBox: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteShippingBox/", success, error, null, options);
    },
    deleteRateTableDeliveryOption: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteRateTableDeliveryOption/", success, error, null, options);
    },
    deleteRateTableOptionFacet: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteRateTableOptionFacet/", success, error, null, options);
    }
});
/**
* @Depends ksg.base.services.js
*/
$.extend(ksg.services, {
    deleteEditSession: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteEditSession/", success, error, null, options);
    }
});
/**
*
* @Depends ksg.gridCore.js
*/
(function ($) {
    $.extend(ksg.ui.grid.columnDefinitions, {
        //fileSysDirectory BizObj column types
		"fileSysDirectory-_id":{type:"key", dataField:"keyName"},
		"fileSysDirectory-depthName": { header: "Icon", "type": "image", "width": 200 },
		"fileSysDirectory-fileCount": { header: "Name", "type": "text", "width": 55 }
    });
})(jQuery);

/**
*
* @Depends ksg.gridCore.js
*/
(function ($) {
    $.extend(ksg.ui.grid.columnDefinitions, {
        //fileSysFile BizObj column types
		"fileSysFile-_id":{type:"key", dataField:"keyName"},
		"fileSysFile-image": { header: "Icon", "type": "image", "width": 200 },
		"fileSysFile-name": { header: "Name", "type": "text", "width": 100 },
		"fileSysFile-download": { header: "Download", "link": "text", "width": 100 },
		"fileSysFile-dateCreated": { header: "Created", "type": "text", "width": 100 },
		"fileSysFile-size": { header: "Size", "type": "text", "width": 75 }
    });
})(jQuery);

/**
* @Depends ksg.base.services.js
*/
$.extend(ksg.services, {
	getFileSysCount: function (options, success, error) {
		ksg.util.svcCall(ksg.services.baseUrl + "/webservice/getFileSysCount", success, error, null, options);
	},
	getFileSysFiles: function (options, success, error) {
		ksg.util.svcCall(ksg.services.baseUrl + "/webservice/getFileSysFiles", success, error, null, options);
	}
});
/**
* @Depends ksg.base.services.js
*/
$.extend(ksg.services, {
    deleteFilterSortSave: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteFilterSortSave/", success, error, null, options);
    }
});
/**
* @Depends ksg.base.services.js
*/
$.extend(ksg.services, {
	getDeveloperHelpTopics: function (options, success, error) {
		ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/getDeveloperHelpTopics", success, error, null, options);
	},
	getDeveloperHelpTopic: function (options, success, error) {
		ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/getDeveloperHelpTopic/" + options.id, success, error, null, options);
	}
});
/**
* @Depends ksg.base.services.js
*/
$.extend(ksg.services, {
    deleteCulture: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/webservice/deleteCulture", success, error, null, options);
    },
    deleteTranslation: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/webservice/deleteTranslation", success, error, null, options);
    }
});
/**
* @Depends base.bizproc.js
*/
ksg.ui.bizprocs.mediaItemsManagement = function (id, dataParams) {
	return new ksg.ui.BizProc(id, dataParams, {
		imgOptions: dataParams["media-options"],
		bizRules: {
			getBizObjListBizRule: "getMediaItems",
			updateBizRule: "updateMediaItem",
			getBizObjBizRule:"getMediaItemDetails"
		},

		CurrentEditPrivilege: function () {
			return ksg.security.Privileges.Delete;
		},

		_getBizObjDetailRuleParameters: function (id) {
			var bizobj = this.currentBizObj;
			return { name: id, cacheName: this.imgOptions.cacheName, previewSize: this.imgOptions.previewSize};
		},
		_getBizObjListRuleParameters: function () {
			var options = $.extend({
				stripLeading: !this.CanEdit()
			}, this.imgOptions);
			var pid = this._getParentBizProcValue("pid");
			if (pid != null)
				options.parentPath = pid.replace(/:/g, "/");
			else
				options.parentPath = "";

			return options;
		},
		_getUpdateBizObjRuleParams: function (bizObj) {
			//bizObj["cacheName"] = this.imgOptions.cacheName;
			return bizObj;
		},
		_keyName: "name"
	});
};


/**
* @Depends base.bizproc.js
*/
ksg.ui.bizprocs.mediaLibraryManagement = function (id, dataParams) {
    return new ksg.ui.BizProc(id, dataParams, {
        artOptions: dataParams["media-options"],
        bizRules: {
        	getBizObjListBizRule: "getMediaLibraryDirectories"
        },

        CurrentEditPrivilege: function () {
            return ksg.security.Privileges.Delete;
        },
        _getBizObjDetailRuleParameters: function (id) {
            return {
                id: id, stripLeading: !this.CanEdit()
            };
        },
        _getBizObjListRuleParameters: function () {
            var options = $.extend({
                stripLeading: !this.CanEdit()
            }, this.artOptions);
            var pid = this._getParentBizProcValue("pid");
            if (pid)
                options.id = pid;

            return options;

        },
		_keyName: "keyName"

    });
};


/**
*
* @Depends ksg.gridCore.js
*/
(function ($) {
    $.extend(ksg.ui.grid.columnDefinitions, {
        //Media BizObj column types
		"mediaDir-_id":{type:"key", dataField:"keyName"},
        "mediaDir-name": { header: "Name", "type": "text", "width": 200 },
        "mediaDir-fileCount": { header: "Count", "type": "text", "width": 100 },
        "mediaDir-keyName": { header: "KeyName", "type": "text", "width": 100 }
    });
})(jQuery);

/**
* @Depends ksg.base.services.js
*/
$.extend(ksg.services, /** @lends ksg.services# */{
	getMediaItems: function (options, success, error) {
		ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/getMediaItems/", success, error, "xMediaItems"+options.parentPath.replace(/\/|\s/g,""), options);
	},
	getMediaLibraryDirectories: function (options, success, error) {
		ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/getMediaLibraryDirectories", success, error, "xMediDir", options);
	},
	getMediaLibraries: function (options, success, error) {
		ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/getMediaLibraries", success, error, null, options);
	},
	updateMediaItem: function (options, success, error) {
		ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/updateMediaItem", success, error, null, options);
	},
	getMediaItemDetails: function (options, success, error) {
		ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/getMediaItemDetails", success, error, null, options);
	}
});
/**
*
* @Depends ksg.gridCore.js
*/
(function ($) {
    $.extend(ksg.ui.grid.columnDefinitions, {
        //slideShow BizObj column types
        "events-_id": { type: "key", dataField: "id" },
        "events-eventName": { header: "Name", "type": "text", "width": 150 },
        "events-emailTo": { header: "Email To", "type": "text", "width": 150 },
        "events-emailFrom": { header: "email From", "type": "text", "width": 70 },
        "events-emailArticle": { header: "Article", "type": "text", "width": 70 }
    });
})(jQuery);

/**
* @Depends ksg.base.services.js
*/
$.extend(ksg.services, {
    getNotificationEvents: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/webservice/getNotificationEvents", success, error, null, options);
    },
    getNotificationEventCount: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/webservice/getNotificationEventCount", success, error, null, options);
    },
    getNotificationEmails: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/webservice/getNotificationEmails", success, error, null, options);
    },
    getNotificationEmailCount: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/webservice/getNotificationEmailCount", success, error, null, options);
    },
    deleteNotifyObserver: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteNotifyObserver", success, error, null, options);
    }


});
/**
* @Depends ksg.base.services.js
*/
$.extend(ksg.services, {
    deleteArticleMetaTag: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteArticleMetaTag", success, error, null, options);
    },
    deleteCompanyUrlRemapping: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteCompanyUrlRemapping", success, error, null, options);
    },
    deletePageMetaTag: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deletePageMetaTag", success, error, null, options);
    }
});
/**
*
* @Depends ksg.gridCore.js
*/
(function ($) {
    $.extend(ksg.ui.grid.columnDefinitions, {
        //slideShow BizObj column types
        "slideShow-_id": { type: "key", dataField: "id" },
        "slideShow-title": { header: "Title", "type": "text", "width": 250 },
        "slideShow-suggestedDisplayType": { header: "Display Type", "type": "text", "width": 150 }
    });
})(jQuery);

// --- JQueryBizObjListAnimi.V2.js ---
function JquerySlideShow(pname) {
    this.parentEl = $('#' + pname);
    this.timer = null;
    this.slideAnimating = false;
    this.mouseInSlide = false;
    this.tickOnMouseLeave = false;
    this.slideTimers = new Array();
    this.cmdQ = new Array();
    eval(pname + "a=this");
    this.resetSlideShowState();

    var width = this.getSlideInfo(null, "ssWidth", "0");
    var height = this.getSlideInfo(null, "ssHeight", "0");
    if (width != 0 && height != 0) {
        this.parentEl.find(".ksg-slideshow").width(width).height(height);
        this.parentEl.width(width).height(height);
    }

    var me = this;
    this.parentEl.mouseenter(function () {
        me.mouseEnter();
    });

    this.parentEl.mouseleave(function () {
        me.mouseLeave();
    });

    this.setupInitialSlideEffects();

    if (this.getConfigBool(null, "autoStart", true)) {
        var startDelay = parseInt(this.getSlideInfo(null, "startDelay", "0"));
        this.timer = setTimeout(function () {
            var chlds = me.parentEl.find(".ksg-slide");
            me.callSlideFunction($(chlds[me.pos]), true);
            me.animateSlideLayers($(chlds[me.pos]), me);
            me.timer = setTimeout(pname + "a.tick()", me.getSlideTimeout($(chlds[me.pos])));
        }, startDelay);
    }
}

JquerySlideShow.prototype.SlideAnimators = new Object();

JquerySlideShow.prototype.setupInitialSlideEffects = function () {
    var me = this;
    this.parentEl.find(".ksg-slide-layer").each(function (index) {
        var uo = me.getConfigBool($(this), "useOutline", false);
        var us = me.getConfigBool($(this), "useShadow", false);
        var um = me.getConfigBool($(this), "useMirror", false);
        var options = {
            outline: uo, outlineColor1: "#808080", outlineColor2: "#808080", outlineWeight: 1,
            shadow: us, shadowColor: "#000", shadowBlur: 1, shadowOffsetTop: 3, shadowOffsetLeft: 3, shadowOpacity: 0.08,
            mirror: um, mirrorColor: "#000"
        };
        if (uo || us)
            $(this).find("h1").FontEffect(options);
    });
}


JquerySlideShow.prototype.mouseEnter = function () {
    this.mouseInSlide = true;
}

JquerySlideShow.prototype.mouseLeave = function () {
    this.mouseInSlide = false;
    if (this.tickOnMouseLeave) {
        this.tick();
        this.tickOnMouseLeave = false;
    }
}

JquerySlideShow.prototype.go = function () {
    if (this.timer)
        return;
    this.tick();
}

JquerySlideShow.prototype.tick = function (dontDoNextTick, doPrev) {
    this.slideAnimating = true;
    var lp = this.pos;
    var chlds = this.parentEl.find(".ksg-slide");
    if (chlds.length <= 1) {
        chlds.css("display", "block");
        return;
    }

    if (this.mouseInSlide && this.getConfigBool(null, "pauseWhileMouseInSlide", false)) {
        this.tickOnMouseLeave = true;
        return;
    }

    var curSlide = { pos: this.pos, obj: this.pos != -1 ? chlds.eq(lp) : null };
    var nextSlide = this.getNextVisibleSlide(lp, doPrev);
    var aniSpeed = this.getSlideAnimationSpeed(curSlide.obj, nextSlide.obj);

    if (curSlide.obj) {
        this.callSlideFunction(curSlide.obj, false);
        this.hideSlideLayers(curSlide.obj);
    }

    this.getAnimiFunction(nextSlide.obj)(this, aniSpeed, curSlide, nextSlide, doPrev);
    this.callSlideFunction(nextSlide.obj, true);
    this.animateSlideLayers(nextSlide.obj, this);

    this.pos = nextSlide.pos;
    if (dontDoNextTick != true && !(nextSlide.onLast && this.getConfigBool(null, "loop", true) == false))
        this.timer = setTimeout(this.parentEl.attr("id") + "a.tick()", this.getSlideTimeout(nextSlide.obj));
}

JquerySlideShow.prototype.hideSlideLayers = function (slide) {
    for (var i in this.slideTimers)
        clearTimeout(this.slideTimers[i]);
    this.slideTimers = new Array();
    slide.find(".ksg-slide-layer").stop().hide();
}

JquerySlideShow.prototype.animateSlideLayers = function (slide, slideShow) {
    slide.find(".ksg-slide-layer").each(function (index, layer) {

        var layerDelay = $(layer).attr("startDelay");
        layertDelay = layerDelay == null ? 0 : parseInt(layerDelay);
        var animiTime = $(layer).attr("animiTime");
        animiTime = (animiTime == null || animiTime == "") ? 5000 : parseInt(animiTime);
        var startCss = JquerySlideShow.prototype.getCssObject($(layer).attr("startCss"));
        var endCss = JquerySlideShow.prototype.getCssObject($(layer).attr("endCss"));
        slideShow.slideTimers.push(setTimeout(function () {
            $(layer).css(startCss).show();
            if (endCss.length != 0)
                $(layer).animate(endCss, animiTime,
                function () {
                    // Animation complete.
                });
        }, layerDelay));

    });
}

JquerySlideShow.prototype.getCssObject = function (cssString) {
    return (cssString != null && cssString.length != 0) ? eval("(" + cssString + ")") : new Object();
}

JquerySlideShow.prototype.getAnimiFunction = function (slide) {
    return JquerySlideShow.prototype.SlideAnimators[this.getSlideInfo(slide, "transition", "fade")];
}

JquerySlideShow.prototype.slideAnimationComplete = function () {
    this.slideAnimating = false;
    if (this.cmdQ.length != 0)
        this.move(this.cmdQ.pop());
}

JquerySlideShow.prototype.stop = function () {
    this.pause();
    this.resetSlideShowState();
}

JquerySlideShow.prototype.pause = function () {
    if (this.timer) {
        window.clearTimeout(this.timer);
        this.timer = null;
    }
}

JquerySlideShow.prototype.move = function (doPrev) {
    if (this.slideAnimating) {
        this.cmdQ.unshift(doPrev);
        return;
    }
    var isOff = this.timer == null;
    this.pause();
    this.tick(isOff, doPrev);
}

JquerySlideShow.prototype.resetClearMemoryGo = function () {
    this.clearShownOnFirstMemory();
    this.stop();

    var chlds = this.parentEl.find(".ksg-slide");
    this.callSlideFunction($(chlds[this.pos]), true);
    this.animateSlideLayers($(chlds[this.pos]), me);
    this.timer = setTimeout(pname + "a.tick(false)", this.getSlideTimeout($(chlds[this.pos])));
}


JquerySlideShow.prototype.getNextVisibleSlide = function (lp, doPrev) {
    var chlds = this.parentEl.find(".ksg-slide");
    var p = arguments.length == 0 ? -1 : lp;
    var c = null;
    do {
        if (doPrev)
            p = (p <= 0) ? (chlds.length - 1) : (p - 1);
        else
            p = (p >= (chlds.length - 1)) ? 1 : (p + 1);
        c = chlds.eq(p);
    } while (!this.shouldShowSlide(c));
    return { pos: p, obj: c, onLast: p == chlds.length - 1 };
}

JquerySlideShow.prototype.resetSlideShowState = function () {
    this.pos = -1;
    var lp = this.pos, prt = this.parentEl, chlds = prt.find(".ksg-slide");
    chlds.css("top", "0px").css("display", "none");

    if (chlds.length != 0) {
        var si = this.getNextVisibleSlide();
        this.pos = si.pos;
        si.obj.show();
        return;
    }
}



JquerySlideShow.prototype.clearShownOnFirstMemory = function () {
    $.cookie(this.parentEl.attr("id"), "");
}

JquerySlideShow.prototype.shouldShowSlide = function (slide) {
    var s = !slide.hasClass("FirstArticle") && !slide.hasClass("FirstChild");
    if (s) {
        if (this.getConfigBool(slide, "onlyShowOnFirstViewing", false)) {
            var c = $.cookie(this.parentEl.attr("id"));
            if (c != "t")
                $.cookie(this.parentEl.attr("id"), "t");
            else
                s = false;
        }
    }

    return s;
}

JquerySlideShow.prototype.getConfigBool = function (slide, name, def) {
    return this.getSlideInfo(slide, name, def == true ? "true" : "false").toLowerCase() == "true";
}

JquerySlideShow.prototype.getSlideTimeout = function (slide) {
    //timeouts are specified in 10ths of a second, but javascript timeout uses millisceonds
    return this.getSlideInfo(slide, "showTime", 40) * 100;
}

JquerySlideShow.prototype.callSlideFunction = function (slide, isShowing) {
    var slideId = this.getSlideInfo(slide, "slideId", null);
    if (slideId != null) {
        try {
            var f = eval((isShowing ? "show_" : "hide_") + slideId);
            if (typeof f == "function")
                f(slide, this);
        }
        catch (e) {
        }
    }
}

JquerySlideShow.prototype.getSlideInfo = function (slide, name, defVal) {
    var t = null, slideInfo = null;
    if (slide != null)
        t = slide.attr(name);
    if (t == null && slide != null)
        t = slide.find(".ksg-slide-info").attr(name);

    if (t == null || t == "")
        t = this.parentEl.find(".ksg-slideshow-info").attr(name);

    if (t == null || t == "")
        t = defVal;
    return t;
}

JquerySlideShow.prototype.getSlideAnimationSpeed = function (item, infoItem) {
    if (infoItem == null)
        infoItem = item;
    var sp = this.getSlideInfo(infoItem, "animiSpeed", "normal");
    if (sp != "normal" && sp != "slow" && sp != "fast")
        sp = parseInt(sp);

    return sp;
}

JquerySlideShow.prototype.SlideAnimators.fade = function (slideShow, aniSpeed, slideOut, slideIn) {

    slideIn.obj.css("top", "0px").css("left", "0px").css("display", "none");
    if (slideOut.obj)
        slideOut.obj.fadeOut(aniSpeed);
    slideIn.obj.fadeIn(aniSpeed, function () { slideShow.slideAnimationComplete(); });
}

JquerySlideShow.prototype.SlideAnimators.rotate = function (slideShow, aniSpeed, slideOut, slideIn, doPrev) {
    var w = slideShow.parentEl.width();
    var dir = doPrev ? '+=' : '-=';
    var leftPos = doPrev ? (-w) : w;
    var easing = slideShow.cmdQ.length != 0 ? 'linear' : 'swing';

    slideIn.obj.css("top", "0px").css("display", "block").css("left", leftPos);
    slideIn.obj.animate({ left: dir + w }, 800, easing, function () { slideShow.slideAnimationComplete(); });
    if (slideOut)
        slideOut.obj.animate({ left: dir + w }, 800, easing);
}
/**
* @Depends ksg.base.services.js
*/
$.extend(ksg.services, {
    getSlideShowCount: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/webservice/getSlideShowCount", success, error, null, options);
    },
    getSlideShows: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/webservice/getSlideShows", success, error, null, options);
    },
    deleteSlideShow: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteSlideShow", success, error, null, options);
    },
    deleteSlideShowSlide: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteSlideShowSlide", success, error, null, options);
    }
});
	//--- ImagePan.js

	function ImagePan(image, bounce, startImage, initSpeed) {
		this.spin = true;
		this.bounce = bounce != null ? bounce : false;
		this.moveSpeed = 0;
		this.imgPosX = 0;
		this.ctrlMove = false;
		this.lastX;
		this.increaseSpeed = 1;
		this.maxSpeed = 20;
		this.delayTime = 25;
		this.panningDisplay = image;
		this.imageInfo = null;
		this.waitingForImage = false;
		var t = this;
		if (!this.bounce)
			$(image).mouseup(function (e) { t.endMove(e); }).mousedown(function (e) { t.startMove(e); }).mousemove(function (e) { t.mouseMove(e); });
		jQuery.data(image, "pan", this);
		if (startImage != null)
			this.setImage(startImage);
		if (initSpeed != null)
			this.moveAt(initSpeed);
	}

	ImagePan.prototype.panImage = function () {
		var t = this;
		if (t.panningDisplay == null) return;
		if (t.waitingForImage && t.imageInfo.complete) {
			t.waitingForImage = false;
			t.panningDisplay.style.backgroundImage = "url(" + t.imageInfo.src + ")";
		}
		if (t.moveSpeed != 0 || t.waitingForImage) {
			t.panningDisplay.style.backgroundPosition = (t.imgPosX += t.moveSpeed) + "px 0px";
			if (t.bounce == true && !t.waitingForImage) {
				if (t.moveSpeed > 0 && t.imgPosX >= 0)
					t.moveSpeed = -t.moveSpeed;
				else if (Math.abs(t.imgPosX) >= t.imageInfo.width - $(t.panningDisplay).width())
					t.moveSpeed = -t.moveSpeed;
			}
			if (t.spin == true || t.waitingForImage)
				setTimeout(function () { t.panImage(); }, t.delayTime);
		}
	}


	ImagePan.prototype.stop = function () {
		if (this.panningDisplay == null) return;
		this.moveSpeed = 0;
	}

	ImagePan.prototype.moveAt = function (speed) {
		var t = this;
		if (t.panningDisplay == null) return;
		var oldMoveSpeed = t.moveSpeed;
		if (t.moveSpeed == 0)
			t.moveSpeed = speed;
		else if (t.moveSpeed < 0)
			t.moveSpeed = -Math.abs(speed);
		else
			t.moveSpeed = Math.abs(speed);

		if (oldMoveSpeed == 0)
			t.panImage();
	}

	ImagePan.prototype.moveMore = function (dir) {
		var t = this;
		if (t.panningDisplay == null) return;
		var oldMoveSpeed = t.moveSpeed;
		if (dir == "left")
			t.moveSpeed -= t.increaseSpeed;
		else
			t.moveSpeed += t.increaseSpeed;

		if (oldMoveSpeed == 0)
			t.panImage();
	}

	ImagePan.prototype.startMove = function (e) {
		if (this.panningDisplay == null) return;
		this.ctrlMove = true;
		this.lastX = e.pageX;
	}
	 ImagePan.prototype.endMove = function (e) {
		if (this.panningDisplay == null) return;
		this.ctrlMove = false;
	}
	ImagePan.prototype.mouseMove = function (e) {
		var t = this;
		if (t.panningDisplay == null) return;
		if (t.ctrlMove) {
			var x = e.pageX; //window.event.clientX;
			if (t.spin) {
				//alert("d");
				var oldMoveSpeed = t.moveSpeed;
				if ((x - t.lastX >= 5) && t.moveSpeed < t.maxSpeed)
					t.moveSpeed += t.increaseSpeed;
				else if ((t.lastX - x >= 5) && t.moveSpeed > -t.maxSpeed)
					t.moveSpeed -= t.increaseSpeed;
				if (oldMoveSpeed == 0)
					t.panImage();
				if (oldMoveSpeed != t.moveSpeed)
					t.lastX = x;
			}
			else
				t.panningDisplay.style.backgroundPositionX = (t.imgPosX += (x - t.lastX));
		}
	}
	ImagePan.prototype.setImage = function (imgFile) {
		var t = this;
		if (t.panningDisplay == null) return;

		t.imageInfo = new Image();
		t.imageInfo.src = imgFile;
		t.waitingForImage = true;
		if (t.panningDisplay == null) return;

		if (t.moveSpeed == 0)
			t.panImage();
	}

	function getPan(id) {
		return jQuery.data($("#" + id).get(0), "pan");
	}

	
/**
* @Depends ksg.setupUI.js
*/
	var timeout = 300;
	var closetimer = null;
	var openMenus = new Array();
	$(document).ready(setupMenuEvents);

	function setupMenuEvents() {
		$(".SubMenuParent").mouseenter(function (eventObj) {
			var t = $(this);
			var tparent = t.offsetParent(".SubMenu").prev(".SubMenuParent");
			var bheight = $(window).height();
			var bwidth = $(window).width();
			var bhScr = $(window).scrollLeft();
			var bvScr = $(window).scrollTop();
			closeMenus(tparent, t);
			addMenuInArray(t);
			if (!t.hasClass("active"))
				t.addClass("active");
			var cm = t.next(".SubMenu");
			var cmw = cm.width(), cmh = cm.height();

			if (t.hasClass("HorzMenu")) {
				if (t.offset().left + t.width() + cmw > (bwidth + bhScr))
					cm.css("left", t.position().left - cmw);
				else
					cm.css("left", t.position().left + t.width())
				cm.css("top", t.position().top);

			}
			else {
				if ((t.offset().top + t.height() + cmh > (bheight + bvScr)) && (t.position().top - cmh >= 0))
					cm.css("top", t.position().top - cmh);
				else
					cm.css("top", t.position().top + t.height());

				if (t.offset().left + cmw > (bwidth + bhScr)) {
					if (t.offset().left + t.width() > (bwidth + bhScr))
						cm.css("left", bwidth + bhScr - cmw);
					else
						cm.css("left", t.position().left + t.width() - cmw);
				}
				else
					cm.css("left", t.position().left)
			}

			if (cm.hasClass("fadeMenu"))
				cm.fadeIn("def");
			else if (cm.hasClass("slideMenu"))
				cm.slideDown("def");
			else if (cm.hasClass("toggleMenu"))
				cm.toggle("def");
			else
				cm.css("display", "block");
			menuItemOpen = true;
			eventObj.stopPropagation();
		}).mouseleave(function (eventObj) {
			var s = $(eventObj.relatedTarget).offsetParent(".SubMenu").prev(".SubMenuParent");
			var tp = $(this).offsetParent(".SubMenu").prev(".SubMenuParent");
			if (s.length == 0 || s.get(0) != tp.get(0)) {
				setMenuTimer();
			}
			else if (s.get(0) == tp.get(0)) {
				cancelTimer();
				closetimer = window.setTimeout(function () { closeMenus(tp); }, timeout);
			}
			else {
				closeMenus(s);
			}
		});
		$(".SubMenu").mouseenter(function (eventObj) {
			closeMenus($(this).prev(".SubMenuParent").eq(0));
			eventObj.stopPropagation();

		}).mouseleave(function (eventObj) {
			setMenuTimer();
		});
	}

	var menuItemOpen = false;
	function setMenuTimer() {
		cancelTimer();
		closetimer = window.setTimeout("closeMenus()", timeout);
	}
	function closeMenus(inMenParent, inMen) {
		if (typeof inMenParent == "number")
			inMenParent = null;
		cancelTimer();
		for (var i = openMenus.length - 1; i >= 0; i--) {
			if (inMenParent == null || inMenParent == 0 || inMenParent.get(0) != openMenus[i].get(0)) {
				if (inMen != null && inMen.get(0) == openMenus[i].get(0))
					break;
				openMenus[i].removeClass("active");
				var cm = openMenus[i].next(".SubMenu");
				if (cm.hasClass("fadeMenu"))
					cm.fadeOut("def");
				else if (cm.hasClass("slideMenu"))
					cm.slideUp("def");
				else if (cm.hasClass("toggleMenu"))
					cm.toggle("def");
				else
					cm.css("display", "none");
				openMenus.pop();
			}
			else if (inMenParent.get(0) == openMenus[i].get(0))
				break;
		}
		if (openMenus.length == 0)
			menuItemOpen = false;

	}
	function cancelTimer() {
		if (closetimer) {
			window.clearTimeout(closetimer);
			closetimer = null;
		}
	}
	function addMenuInArray(men) {
		for (var i = 0; i < openMenus.length - 1; i++)
			if (men.get(0) == openMenus[i].get(0))
				return;
		openMenus.push(men);
	}
	

/**
* @Depends ksg.base.services.js
*/
$.extend(ksg.services, {
    deleteSecurePage: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteSecurePage", success, error, null, options);
    }
});
/**
* @Depends ksg.base.services.js
*/
$.extend(ksg.services, /** @lends ksg.services# */{
    deleteUserEmailVerification: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteUserEmailVerification", success, error, null, options);
    }
});
/**
*
* @Depends ksg.gridCore.js
*/
(function ($) {

    $.extend(ksg.ui.grid.columnDefinitions, {
        //UserGroup BizObj column types
        "userGroup-name": { header: "Name", "type": "text", "width": 150 },
        "userGroup-description": { header: "Description", "type": "text", "width": 200 },
        "userGroup-autoNotify": { header: "Auto Notify", "type": "text", "width": 100 },
        
        //User BizObj column types
        "user-userName": {header: "User Name", "type" : "text", "width":150},
        "user-enable" : {header: "Active" , "type" : "text" , "width" : 50}
    });

})(jQuery);
/**
*
* @Depends ksg.gridCore.js
*/
(function ($) {

    $.extend(ksg.ui.grid.columnDefinitions, {
        //User BizObj column types
        "user-_id": { type: "key", dataField: "id" },
        "user-userName": {header: "User Name", "type" : "text", "width":150},
        "user-enable" : {header: "Active" , "type" : "text" , "width" : 50}
    });

})(jQuery);
/**
*
* @Depends ksg.gridCore.js
*/
(function ($) {

    $.extend(ksg.ui.grid.columnDefinitions, {
        //UserGroup BizObj column types
        "userGroup-_id": { type: "key", dataField: "id" },
        "userGroup-name": { header: "Name", "type": "text", "width": 150 },
        "userGroup-description": { header: "Description", "type": "text", "width": 200 },
        "userGroup-autoNotify": { header: "Auto Notify", "type": "text", "width": 100 }
    });

})(jQuery);
/**
* @Depends ksg.base.services.js
*/
$.extend(ksg.services, /** @lends ksg.services# */{
    deleteAllCompanyMemberships: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteAllCompanyMemberships", success, error, null, options);
    },
    deleteCompanyMembership: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteCompanyMembership", success, error, null, options);
    },
    deleteCompany: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteCompany", success, error, null, options);
    }
});
/**
* @Depends ksg.base.services.js
*/
$.extend(ksg.services, {
    loginUser: function (userid, pwd, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/webservice/loginUser/" + userid + "/" + pwd, success, error);
    },
    logoffUser: function (success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/webservice/logoffUser", success, error);
    },

    /** Company Users and User GroupsServices **/
    getCompanyUsers: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/webservice/getCompanyUsers", success, error, null, options);
    },
    getCompanyUserCount: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/webservice/getCompanyUserCount", success, error, null, options);
    },
    getCompanyUserGroups: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/webservice/getCompanyUserGroups", success, error, null, options);
    },
    getCompanyUserGroupCount: function (options, success, error) {
        ksg.util.svcCall(ksg.services.baseUrl + "/webservice/getCompanyUserGroupCount", success, error, null, options);
    },

    deleteUser: function (options, success, error) {
    	ksg.util.svcCall(ksg.services.baseUrl + "/jsonservice/deleteUser", success, error, null, options);
    }


});

