/*
 * Valence Core JavaScript
 * Copyright(c) 2008-2010, CNX Corporation
 */
// show a general error
var vvShowError = function(code, text) {
	Ext.getBody().unmask();
	Ext.Msg.alert('AN ERROR OCCURED', '(' + code + ') - ' + text);
};

// set location of blank url
Ext.BLANK_IMAGE_URL = '/extjs/resources/images/default/s.gif';

// create Valence object
Valence = {};

// create Valence contants object
Valence.constants = {
	utf8ByteOrderMark: '\u00ef\u00bb\u00bf'
};

// create Valence lang object
Valence.lang = {
	lit: {},
	msg: {},
	getLanguage: function() {
		var lpath = location.pathname;
		var lang = lpath.substring(lpath.search('-') + 1, lpath.substring(1).search(/\//) + 1);
		if (lang.search('/') >= 0) {
			return 'en';
		} else {
			return lang;
		}
	}
};

// create Valence util object
Valence.util = function() {
	return {
		showMessage: function(title, msg) {
			parent.showMessage(title, msg);
		},
		showError: function(code, text) {
			vvShowError(code, text);
		},
		execScriptFiles: function(config) {
			var scriptIndex = 0;
			var getFiles = function(scriptIndex) {
				config = config ||
				{};
				Ext.apply(this, config);
				Ext.Ajax.request({
					method: 'GET',
					url: this.urls[scriptIndex],
					callback: function(options, success, response) {
						try {
							var responseString = '';
							responseString = response.responseText;
							eval.call(window, response.responseText);
						} catch (e) {
						}
						if (this.urls.length - 1 > scriptIndex) {
							scriptIndex++;
							getFiles(scriptIndex);
						} else {
							if (this.callback) {
								this.callback.call(window);
							}
						}
					}
				});
			};
			getFiles(scriptIndex);
		},
		execDynamicScript: function(config) {
			config = config ||
			{};
			Ext.apply(this, config);
			var localEvalResponse = this.evalResponse;
			Ext.Ajax.request({
				url: 'vvcall.pgm',
				params: {
					pgm: this.pgm,
					action: this.action
				},
				callback: function(options, success, response) {
					if (localEvalResponse) {
						eval(response.responseText);
					} else {
						return response.responseText;
					}
				}
			});
		},
		encodeUTF16: function(textString) {
			var haut = 0;
			var n = 0;
			var CPstring = '';
			var dec2hex = function(textString) {
				return (textString + 0).toString(16).toUpperCase();
			};
			try {
				for (var i = 0; i < textString.length; i++) {
					var b = textString.charCodeAt(i);
					if (b < 0 || b > 0xFFFF) {
						CPstring += 'Error: byte out of range ' + dec2hex(b) + '!';
					}
					if (haut != 0) {
						if (0xDC00 <= b && b <= 0xDFFF) {
							CPstring += dec2hex(0x10000 + ((haut - 0xD800) << 10) + (b - 0xDC00));
							haut = 0;
							continue;
						} else {
							CPstring += 'Error in: surrogate out of range ' + dec2hex(haut) + '!';
							haut = 0;
						}
					}
					if (0xD800 <= b && b <= 0xDBFF) {
						haut = b;
					} else {
						cp = dec2hex(b);
						while (cp.length < 4) {
							cp = '0' + cp;
						}
						CPstring += cp;
					}
				}
			} catch (e) {
			}
			return CPstring;
		},
		decodeUTF16: function(inStr) {
			try {
				inStr = inStr.replace(/([A-Fa-f0-9]{4})/g, function(matchstr, hex) {
					var result = '';
					var n = parseInt(hex, 16);
					if (n <= 0xFFFF) {
						result += String.fromCharCode(n);
					} else {
						if (n <= 0x10FFFF) {
							n -= 0x10000
							result += String.fromCharCode(0xD800 | (n >> 10)) + String.fromCharCode(0xDC00 | (n & 0x3FF));
						} else {
							result += 'hex2Char error: Code point out of range: ' + Valence.util.dec2hex(n);
						}
					}
					return result;
				});
				return inStr;
			} catch (e) {
				return inStr;
			}
		},
		XMLdocToString: function(XMLdoc) {
			var XMLstring;
			try {
				XMLstring = new XMLSerializer().serializeToString(XMLdoc);
			} catch (e) {
				XMLstring = XMLdoc.xml;
			}
			return XMLstring;
		},
		decodeUTF16XMLattribute: function(XMLdoc, node, attrib) {
			var nodes = Ext.DomQuery.select(node, XMLdoc);
			Ext.each(nodes, function(thisNode) {
				thisNode.setAttribute(attrib, Valence.util.decodeUTF16(thisNode.getAttribute(attrib)));
			});
		}
	}
}();

// create Valence tab object
Valence.tab = function() {
	return {
		isRendered: function(option) {
			var count = 0;
			var result = false;
			parent.Ext.select("iframe[id^='']", true).each(function(o) {
				if (o.id == 'frame_' + option) {
					result = true;
				};
				count += 1;
			});
			return result;
		},
		getTab: function(option) {
			var count = 0;
			result = -1;
			parent.Ext.select("iframe[id^='']", true).each(function(o) {
				if (o.id == 'frame_' + option) {
					result = count;
				};
				count += 1;
			});
			return parent.frames[result];
		},
		closeTab: function(option) {
			parent.tabPanelMain.remove('tab_' + option);
		},
		showTab: function(option) {
			parent.tabPanelMain.findById('tab_' + option).show();
		},
		launchTab: function(option, params) {
			parent.launchPortalOpt(option, params);
		},
		launchTabByForce: function(option, params, specialName) {
			parent.launchPortalOptByForce(option, params, specialName);
		}
	}
}();

Ext.ux.SliderTip = Ext.extend(Ext.Tip, {
	minWidth: 10,
	offsets: [0, -10],
	init: function(slider) {
		slider.on('dragstart', this.onSlide, this);
		slider.on('drag', this.onSlide, this);
		slider.on('dragend', this.hide, this);
		slider.on('destroy', this.destroy, this);
	},
	onSlide: function(slider) {
		this.show();
		this.body.update(this.getText(slider));
		this.doAutoWidth();
		this.el.alignTo(slider.thumb, 'b-t?', this.offsets);
	},
	getText: function(slider) {
		return slider.getValue();
	}
});

Ext.ux.vvPagingToolbarPlugin = Ext.extend(Ext.util.Observable, {
	init: function(pbar) {
		this.pagingBar = pbar;
		pbar.on('render', this.onRender, this);
		pbar.on('beforedestroy', this.onDestroy, this);
	},
	onRender: function(pbar) {
		Ext.each(pbar.items.getRange(2, 6), function(c) {
			c.hide();
		});
		this.slider = new Ext.Slider({
			width: 114,
			minValue: 1,
			maxValue: 1,
			plugins: new Ext.ux.SliderTip({
				bodyStyle: 'padding:5px;',
				getText: function(s) {
					return String.format('Page <b>{0}</b> of <b>{1}</b>', s.value, s.maxValue);
				}
			})
		});
		this.slider.on('changecomplete', function(s, v) {
			pbar.changePage(v);
		});
		this.numRows = new Ext.form.ComboBox({
			store: new Ext.data.SimpleStore({
				fields: ['text', 'value'],
				data: [['10', 10], ['25', 25], ['50', 50], ['100', 100], ['250', 250], ['500', 500]]
			}),
			mode: 'local',
			displayField: 'text',
			valueField: 'value',
			editable: false,
			forceSelection: true,
			value: pbar.pageSize,
			allowBlank: false,
			triggerAction: 'all',
			width: 50,
			maskRe: /[0-9]/,
			listeners: {
				select: {
					fn: function(combo) {
						pbar.pageSize = combo.getValue();
						pbar.doLoad(0);
					}
				},
				render: {
					fn: function(combo) {
						combo.getEl().set({
							maxlength: 3
						});
					}
				}
			}
		});
		pbar.insert(5, new Ext.Toolbar.Spacer({
			width: 4
		}));
		pbar.insert(5, this.slider);
		pbar.insert(5, new Ext.Toolbar.Spacer({
			width: 4
		}));
		pbar.insert(12, new Ext.Toolbar.Separator());
		pbar.insert(13, new Ext.Toolbar.TextItem({
			text: 'Rows:'
		}));
		pbar.insert(14, this.numRows);
		pbar.on('change', function(pb, data) {
			this.slider.maxValue = data.pages;
			this.slider.setValue(data.activePage);
		}, this);
	},
	onDestroy: function() {
		this.slider.destroy();
	}
});

// Valence grid panel with dynamic record and columns (must be in meta data)
Ext.ux.vvGridPanel = Ext.extend(Ext.grid.GridPanel, {
	initComponent: function() {
		var config = {
			loadMask: true,
			autoLoad: false,
			ds: new Ext.data.Store({
				autoLoad: this.autoLoad,
				baseParams: this.baseParams,
				listeners: this.storeListeners,
				proxy: this.proxy,
				pruneModifiedRecords: this.pruneModifiedRecords,
				reader: new Ext.data.JsonReader(),
				remoteSort: this.remoteSort,
				sortInfo: this.sortInfo,
				storeId: this.storeId,
				url: this.url
			}),
			bbar: new Ext.PagingToolbar({
				pageSize: this.pageSize,
				store: this.storeId,
				displayInfo: true,
				displayMsg: 'Showing records {0} - {1} of {2}',
				emptyMsg: "No records to display",
				plugins: [new Ext.ux.vvPagingToolbarPlugin()]
			})
		};
		Ext.apply(this, config);
		Ext.apply(this.initialConfig, config);
		Ext.ux.vvGridPanel.superclass.initComponent.apply(this, arguments);
	},
	onRender: function(ct, position) {
		this.colModel.defaultSortable = true;
		Ext.ux.vvGridPanel.superclass.onRender.call(this, ct, position);
		this.el.mask('Loading...');
		this.store.on('metachange', function() {
			if (typeof(this.store.reader.jsonData.columns) === 'object') {
				var columns = [];
				if (this.rowNumberer) {
					columns.push(new Ext.grid.RowNumberer());
				}
				if (this.checkboxSelModel) {
					columns.push(new Ext.grid.CheckboxSelectionModel());
				}
				Ext.each(this.store.reader.jsonData.columns, function(column) {
					columns.push(column);
				});
				this.getColumnModel().setConfig(columns);
			}
			this.el.unmask();
		}, this);
		this.store.load({
			params: {
				page: 1,
				start: 0,
				limit: this.pageSize
			}
		});
	}
});

// get in initial url parameters
try {
	Ext.getUrlParam = function(param) {
		var params = Ext.urlDecode(location.search.substring(1));
		return param ? params[param] : params;
	}
} catch (e) {
}

// set session id parm
var sid = Ext.getUrlParam('sid');
// set option parm
var opt = Ext.getUrlParam('opt');

var BEFOREREQUEST = "beforerequest", REQUESTCOMPLETE = "requestcomplete", REQUESTEXCEPTION = "requestexception", UNDEFINED = undefined, LOAD = 'load', POST = 'POST', GET = 'GET', WINDOW = window;

// private
function handleResponse(response) {
	this.transId = false;
	var options = response.argument.options;
	response.argument = options ? options.argument : null;
	this.fireEvent(REQUESTCOMPLETE, this, response, options);
	if (options.success) {
		options.success.call(options.scope, response, options);
	}
	if (options.callback) {
		options.callback.call(options.scope, options, true, response);
	}
}

// private
function handleFailure(response, e) {
	this.transId = false;
	var options = response.argument.options;
	response.argument = options ? options.argument : null;
	this.fireEvent(REQUESTEXCEPTION, this, response, options, e);
	if (options.failure) {
		options.failure.call(options.scope, response, options);
	}
	if (options.callback) {
		options.callback.call(options.scope, options, false, response);
	}
}

// extend Ext.data.Connection to include session id and option number
Ext.override(Ext.data.Connection, {
	request: function(o) {
		var me = this;
		if (me.fireEvent(BEFOREREQUEST, me, o)) {
			if (o.el) {
				if (!Ext.isEmpty(o.indicatorText)) {
					me.indicatorText = '<div class="loading-indicator">' + o.indicatorText + "</div>";
				}
				if (me.indicatorText) {
					Ext.getDom(o.el).innerHTML = me.indicatorText;
				}
				o.success = (Ext.isFunction(o.success) ? o.success : function() {
				}).createInterceptor(function(response) {
					Ext.getDom(o.el).innerHTML = response.responseText;
				});
			}
			
			var p = o.params, url = o.url || me.url, method, cb = {
				success: me.handleResponse,
				failure: me.handleFailure,
				scope: me,
				argument: {
					options: o
				},
				timeout: o.timeout || me.timeout
			}, form, serForm;
			
			
			if (Ext.isFunction(p)) {
				p = p.call(o.scope || WINDOW, o);
			}
			
			if (!me.extraParams) {
				me.extraParams = {
					'sid': sid,
					'opt': opt
				};
			}
			
			p = Ext.urlEncode(me.extraParams, Ext.isObject(p) ? Ext.urlEncode(p) : p);
			
			if (Ext.isFunction(url)) {
				url = url.call(o.scope || WINDOW, o);
			}
			
			if ((form = Ext.getDom(o.form))) {
				url = url || form.action;
				if (o.isUpload || /multipart\/form-data/i.test(form.getAttribute("enctype"))) {
					return me.doFormUpload.call(me, o, p, url);
				}
				serForm = Ext.lib.Ajax.serializeForm(form);
				p = p ? (p + '&' + serForm) : serForm;
			}
			
			method = o.method || me.method || ((p || o.xmlData || o.jsonData) ? POST : GET);
			
			if (method === GET && (me.disableCaching && o.disableCaching !== false) || o.disableCaching === true) {
				var dcp = o.disableCachingParam || me.disableCachingParam;
				url = Ext.urlAppend(url, dcp + '=' + (new Date().getTime()));
			}
			
			o.headers = Ext.apply(o.headers ||
			{}, me.defaultHeaders ||
			{});
			
			if (o.autoAbort === true || me.autoAbort) {
				me.abort();
			}
			
			if ((method == GET || o.xmlData || o.jsonData) && p) {
				url = Ext.urlAppend(url, p);
				p = '';
			}
			return (me.transId = Ext.lib.Ajax.request(method, url, cb, p, o));
		} else {
			return o.callback ? o.callback.apply(o.scope, [o, UNDEFINED, UNDEFINED]) : null;
		}
	}
});

// extend Ext.data.Store to fix apply of baseParams
Ext.override(Ext.data.Store, {
	execute: function(action, rs, options) {
		// blow up if action not Ext.data.CREATE, READ, UPDATE, DESTROY
		if (!Ext.data.Api.isAction(action)) {
			throw new Ext.data.Api.Error('execute', action);
		}
		// make sure options has a params key
		options = Ext.applyIf(options ||
		{}, {
			params: {}
		});
		
		// have to separate before-events since load has a different signature than create,destroy and save events since load does not
		// include the rs (record resultset) parameter.  Capture return values from the beforeaction into doRequest flag.
		var doRequest = true;
		
		if (action === 'read') {
			//Ext.applyIf(options.params, this.baseParams);
			doRequest = this.fireEvent('beforeload', this, options);
		} else {
			// if Writer is configured as listful, force single-record rs to be [{}] instead of {}
			// TODO Move listful rendering into DataWriter where the @cfg is defined.  Should be easy now.
			if (this.writer.listful === true && this.restful !== true) {
				rs = (Ext.isArray(rs)) ? rs : [rs];
			}   // if rs has just a single record, shift it off so that Writer writes data as '{}' rather than '[{}]'
			else 
				if (Ext.isArray(rs) && rs.length == 1) {
					rs = rs.shift();
				}
			// Write the action to options.params
			if ((doRequest = this.fireEvent('beforewrite', this, action, rs, options)) !== false) {
				this.writer.write(action, options.params, rs);
			}
		}
		if (doRequest !== false) {
			// Send request to proxy.
			var params = Ext.apply({}, options.params, this.baseParams);
			if (this.writer && this.proxy.url && !this.proxy.restful && !Ext.data.Api.hasUniqueUrl(this.proxy, action)) {
				params.xaction = action; // <-- really old, probaby unecessary.
			}
			// Note:  Up until this point we've been dealing with 'action' as a key from Ext.data.Api.actions.
			// We'll flip it now and send the value into DataProxy#request, since it's the value which maps to
			// the user's configured DataProxy#api
			this.proxy.request(Ext.data.Api.actions[action], rs, params, this.reader, this.createCallback(action, rs), this, options);
		}
		return doRequest;
	}
});

Ext.ns('Ext.ux.tree');

Ext.ux.tree.TreeFilterX = Ext.extend(Ext.tree.TreeFilter, {
	expandOnFilter: true,
	filter: function(value, attr, startNode) {
		// expand start node
		if (false !== this.expandOnFilter) {
			startNode = startNode || this.tree.root;
			var animate = this.tree.animate;
			this.tree.animate = false;
			startNode.expand(true, false, function() {
				// call parent after expand
				Ext.ux.tree.TreeFilterX.superclass.filter.call(this, value, attr, startNode);
			}
.createDelegate(this));
			this.tree.animate = animate;
		} else {
			// call parent
			Ext.ux.tree.TreeFilterX.superclass.filter.apply(this, arguments);
		}
	},
	filterBy: function(fn, scope, startNode) {
		startNode = startNode || this.tree.root;
		if (this.autoClear) {
			this.clear();
		}
		var af = this.filtered, rv = this.reverse;
		var f = function(n) {
			if (n === startNode) {
				return true;
			}
			if (af[n.id]) {
				return false;
			}
			var m = fn.call(scope || n, n);
			if (!m || rv) {
				af[n.id] = n;
				n.ui.hide();
				return true;
			} else {
				n.ui.show();
				var p = n.parentNode;
				while (p && p !== this.root) {
					p.ui.show();
					p = p.parentNode;
				}
				return true;
			}
			return true;
		};
		startNode.cascade(f);
		if (this.remove) {
			for (var id in af) {
				if (typeof id != "function") {
					var n = af[id];
					if (n && n.parentNode) {
						n.parentNode.removeChild(n);
					}
				}
			}
		}
	}
});

