Baf = {

	pageSize: 25,
	texts: {
	'delete': {
		confirmTitle: 'Delete {itemType} ?',
		confirmBody: 'Do you really want to delete the selected {itemType} ?',
		maskText: 'Please wait...Deleting!',
		errorTitle: 'Error',
		errorBody: 'Please select at least one {itemType} !'
	},
	pagingToolbar: {
		displayMsg: 'Displaying items {0} - {1} of {2}',
		emptyMsg: "No items to display"
	}
	},
	Window: function(config) {
		var defaultConfig = {
			_recursive: true,
			width: 350,
			height:200,
			minWidth: 300,
			minHeight: 50,
			layout: 'fit',
			plain:true,
			modal:true,
			bodyStyle:'padding:5px;',
			buttonAlign:'center'
		};
		this.override(defaultConfig,config);
		return new Ext.Window(defaultConfig);
	},
	Viewport: function(config) {
		var defaultConfig = {
			_recursive: true,
			waitMsg: "Loading...",
			layout:"fit",
			bodyStyle:'padding:5px;',
			buttonAlign:'center'
		};
		this.override(defaultConfig,config);
		return new Ext.Viewport(defaultConfig);
	},
	Loader: function(config) {
		var defaultConfig = {
			_recursive:true,
			listeners:{
				_recursive:true,
				'beforeload' : function(loader,node) {
					if (node==node.getOwnerTree().getRootNode())	/* Mask tree only if loaded node is root */
					node.getOwnerTree().el.mask("Loading...");
				},
				'load' : function(loader,node) {
					if (node==node.getOwnerTree().getRootNode())	/* Un-mask tree only if loaded node is root */
					node.getOwnerTree().el.unmask();
				},
				'loadexception' : function(loader,node) {
					if (node==node.getOwnerTree().getRootNode())	/* Un-mask tree only if loaded node is root */
					node.getOwnerTree().el.unmask();
				}
			}
		};
		this.override(defaultConfig,config);
		return new Ext.tree.TreeLoader(defaultConfig);
	},
	TreePanel :function(config) {
		return new Ext.tree.TreePanel(this.treeConfig(config));
	},
	ColumnTree :function(config) {
		return new Ext.tree.ColumnTree(this.treeConfig(config));
	},
	ColumnTreeMultiSelect :function(config) {
		return new Ext.tree.ColumnTreeMultiSelect(this.treeConfig(config));

	},
	treeConfig: function(config) {
		var defaultConfig = {
			_recursive:true,
			rootVisible:false,
			autoScroll:true,
			idName: 'id',
			listeners: {
				_recursive:true,
				afterDelete: {
					fn: function(ids) {
						var selModel = this.getSelectionModel();

						if (selModel.selNode) {
							selModel.selNode.remove();
						} else if (selModel.selNodes) {
							var toRemove=[];
							for (var i=0;i<selModel.selNodes.length;i++) {
								toRemove.push(selModel.selNodes[i]);
							}
							for (i=0;i<toRemove.length;i++) {
								toRemove[i].remove();
							}
						}
					}
				},
				afterAdd: {
					fn: function(parentNode,node) {
						parentNode.addChild(node);
					}
				},
				afterEdit: {
					fn: function(node,a) {
						/* 	node 	- the node to be changed
						a 		- attributes array to be changed in the node */
						for (var i in a) {
							node.attributes[i] = a[i];
						}
						node.refresh();
					}
				}
			}
		};
		this.override(defaultConfig,config);
		return defaultConfig;
	},
	CustomTree :function(config) {

		var tree = {};

		var functions = {
			filterSelection: function() {
				var t = tree;
				var selNodes = t.getSelectionModel().selNodes;
				if (selNodes.length>1) {
					var type = selNodes[0].attributes[customSettings.nodeTypeName];
					var rule = null;
					if ((r=config.rules) && (sel=r.selection) && (st=sel[type])) {
						rule = st;
					}
					var toRemove=[];
					for(i=1;i<selNodes.length;i++) {
						var currentType = selNodes[i].attributes[customSettings.nodeTypeName];
						if ((rule && rule.types && !rule.types.inArray(currentType)) || (rule.fn && !rule.fn(selNodes[0],selNodes[i]))) {
							toRemove.push(selNodes[i]);
						}
					}
					for(i=0;i<toRemove.length;i++) {
						toRemove[i].unselect();
					}
				}
			},
			dragOver: function(e) {
				var dropNode = e.dropNode[0];
				var type = dropNode.attributes[customSettings.nodeTypeName];
				var targetType = e.target.attributes[customSettings.nodeTypeName];

				var rule = null;
				if ((r=config.rules) && (sel=r.dragOver) && (st=sel[type])) {
					rule = st;
				}

				if ((rule && rule.types && !rule.types.inArray(targetType)) || (rule.fn && !rule.fn(e))) {
					return false;
				}
				return true;
			},
			beforeNodeDrop: function(e) {
				tree.el.mask("Please wait...",'x-mask-loading');
				e.target.addListener('append',function() {
					functions.move(e);
				},null,{single: true});
				return true;
			},
			move: function(e) {
				Ext.Ajax.request({
					url: config.urls.move,
					params: {
						ids: e.dropNode.extract('attributes.'+tree.idName),
						parent_id: e.target.attributes[tree.idName]
					},
					success: function(response, options) {
						tree.el.unmask();
					}
				});
			},
			copy: function () {
				var selNodes = tree.getSelectionModel().selNodes;
				if (selNodes.length>0) {
					config.clipboard = [];
					for (var i=0;i<selNodes.length;i++) {
						config.clipboard.push(selNodes[i]);
					}
				}
			},
			paste: function(c) {
				var attributes = {};
				for (var d in c.parentNode.attributes) {
					if (typeof(c.parentNode.attributes[d]) != "object") {
						attributes[d]=c.parentNode.attributes[d];
					}
					
				}
				var parent = c.parentNode;
				tree.el.mask("Please wait...",'x-mask-loading');
				Ext.Ajax.request({
					url: config.urls.copy,
					params: {
						ids: config.clipboard.extract('attributes.'+tree.idName),
						container_id: parent.attributes[tree.idName],
						attributes: Ext.util.JSON.encode(attributes)
					},
					success: function(o) {
						var response = Ext.util.JSON.decode(o.responseText);
						var clipboard = config.clipboard;
						tree.el.unmask();
						if (response.success){
							parent.reload();
							if (response.info && response.info.length>0) {
								Ext.Msg.alert('Warning', response.info);
							}
						} else {
							clipboard=[];
							Ext.Msg.alert('Error', 'Invalid request! Operation aborted.');
						}
					}
				});
			}
		};

		var customSettings = {
			_recursive:true,
			functions: functions,
			QuickFilter: new Ext.tree.QuickFilter(),
			animate: false,
			enableDD: true,
			ddGroup: 'DDGroup',
			nodeTypeName: 'nodeType',
			columns:[{
				header:'Name',
				width:440,
				dataIndex:'name'
			}],
			contextmenu: function(n) {
				var t = n.attributes[customSettings.nodeTypeName];
				var attr = n.attributes;
				var selNodes = tree.getSelectionModel().selNodes;
				var singleSel = (selNodes.length>1) ? false : true;
				var b = [];

				/* add copy / paste buttons, if 'clipboard' was specified in 'config' var */
				if (config.clipboard) {
					var rule = null;
					if ((r=config.rules) && (sel=r.copy)) rule = sel;
					var copyButton = new Ext.menu.Item({
						text    : 'Copy',
						iconCls : 'edit-copy',
						href	: 'javascript:;',
						disabled: (rule.fn && rule.fn(n,config.clipboard)=='disabled'),
						hidden	: ((rule && rule.types && !rule.types.inArray('*') && !rule.types.inArray(t)) || (rule.fn && rule.fn(n,config.clipboard)=='hidden')),
						handler : function() { functions.copy(); }
					});
					rule = null;
					if ((r=config.rules) && (sel=r.paste)) rule = sel;
					var pasteButton = new Ext.menu.Item({
						text    : 'Paste',
						iconCls : 'edit-paste',
						href	: 'javascript:;',
						disabled: (rule.fn && rule.fn(n,config.clipboard)=='disabled'),
						hidden	: ((rule && rule.types && !rule.types.inArray('*') && !rule.types.inArray(t)) || (rule.fn && rule.fn(n,config.clipboard)=='hidden')),
						handler : function() { functions.paste({parentNode: n}); }
					});
					if (!copyButton.hidden || !pasteButton.hidden) {
						b = b.concat([copyButton, pasteButton, '-']);
					}
				}

				b = b.concat([
				new Ext.menu.Item({
					text    : 'Refresh',
					iconCls : 'refresh-all',
					href	: 'javascript:;',
					disabled: !singleSel,
					hidden	: n.isLeaf(),
					handler : function() { n.reload(); }
				}),
				new Ext.menu.Item({
					text    : 'Expand All',
					iconCls : 'expand-all',
					href	: 'javascript:;',
					disabled: !singleSel,
					hidden	: n.isLeaf(),
					handler : function() { n.expand(true); }
				}),
				new Ext.menu.Item({
					text    : 'Collapse All',
					iconCls : 'collapse-all',
					href	: 'javascript:;',
					disabled: !singleSel,
					hidden	: n.isLeaf(),
					handler : function() { n.collapse(true); }
				}),
				new Ext.menu.Separator({
					hidden: n.isLeaf()
				}),
				new Ext.menu.Item({
					text    : 'Quick Search (Ctrl+Q)',
					iconCls	: 'search-icon',
					href	: 'javascript:;',
					handler : function() { tree.QuickFilter.run(); }
				}),
				new Ext.menu.Item({
					text    : 'Advanced Search (Ctrl+F)',
					iconCls	: 'search-icon2', href	: 'javascript:;',
					handler : function() { tree.getBottomToolbar().activate(); }
				})
				]);
				return b;
			},
			listeners: {
				_recursive:true,
				click: {
					fn: function(node) {
						/* call user defined function */
						if (config.functions && (fn = config.functions.click)) {
							if (fn()===false) return false;
						}

						functions.filterSelection();
						tree.quickfilter = tree;//modif
						if (tree.getBottomToolbar()){
							tree.getBottomToolbar().set(node,node.attributes.model);//modif
						}

						/* call user defined function */
						if (config.functions && (fn = config.functions.afterclick)) {
							if (fn(node)===false) return false;
						}
					}
				},
				nodedragover: {
					fn: function(e) {
						/* call used defined function */
						if (config.functions && (fn = config.functions.dragover)) {
							if (fn()===false) return false;
						}
						return functions.dragOver(e);
					}
				},
				beforenodedrop: {
					fn: function(e) {
						/* call used defined function */
						if (config.functions && (fn = config.functions.beforenodedrop)) {
							if (fn()===false) return false;
						}
						functions.beforeNodeDrop(e);
					}
				},
				contextmenu:{
					fn: function(node, e) {
						/* call used defined function */
						if (config.functions && (fn = config.functions.contextmenu)) {
							if (fn()===false) return false;
						}

						functions.filterSelection();

						if (!node.isSelected()) return;

						var XY = e.getXY();

						tree.quickfilter = tree;
						if (tree.getBottomToolbar()){
							tree.getBottomToolbar().set(node,node.attributes.model);
						}

						var items = (config.contextmenu ? config.contextmenu(node) : []);
						if (customSettings.contextmenu) {
							items = items.concat(customSettings.contextmenu(n));
						}
						var menu = new Ext.menu.Menu({
							items: items,
							listeners:{
							'itemclick':{
								fn: function() { this.hide(); }
							}
							}
						});
						menu.showAt(XY);
					}
				}
			},
			loader: Baf.Loader({
				_recursive:true,
				dataUrl: config.urls.load,
				uiProviders:{
				'col': Ext.tree.ColumnNodeUIMultiSelect
				},
				listeners: {
					_recursive:true,
					beforeload: {
						fn: function (loader,node) {
							/* call used defined function */
							if (config.functions && (fn = config.functions.beforeload)) {
								var flag = fn(loader,node);
								if (flag===false || flag===true) return flag;
							}

							var baseParams = loader.baseParams;
							delete baseParams.parent_id;
							baseParams.parent_id = node.attributes.id;
						}
					}
				}
			})
		};
		this.override(customSettings,config.treeConfig);
		tree = new Ext.tree.ColumnTreeMultiSelect(this.treeConfig(customSettings));
		tree.QuickFilter.init(tree);
		return tree;
	},
	Grid: function(config) {
		var defaultConfig = {
			_recursive: true,
			title:'# title not set #',
			border:false,
			loadMask:{msg: 'Loading...'},
			trackMouseOver:true,
			selModel: new Ext.grid.RowSelectionModel({singleSelect:false}),
			enableColLock:false,
			viewConfig: {
				_recursive: true,
				emptyText:"No records found!",
				forceFit: true
			},
			listeners: {
				_recursive:true,
				afterEdit: {
					fn: function() {
						this.store.reload();
					}
				},
				afterDelete: {
					fn: function() {
						this.store.reload();
					}
				}
			}
		};
		this.override(defaultConfig,config);
		return new Ext.grid.GridPanel(defaultConfig);
	},
	Store: function(config) {
		var defaultConfig = {
			_recursive: true,
			remoteSort: true
		};
		this.override(defaultConfig,config);
		return new Ext.data.Store(defaultConfig);
	},
	Reader: function(config,dataArray) {
		var defaultConfig = {
			_recursive: true,
			root: 'results',
			id: 'id',
			totalProperty: 'total'
		};
		this.override(defaultConfig,config);
		return new Ext.data.JsonReader(defaultConfig,dataArray);
	},
	PagingToolbar: function(config) {
		var defaultConfig = {
			_recursive: true,
			pageSize: this.pageSize,
			displayInfo: true,
			displayMsg: this.texts.pagingToolbar.displayMsg,
			emptyMsg: this.texts.pagingToolbar.emptyMsg
		}
		this.override(defaultConfig,config);
		return new Ext.PagingToolbar(defaultConfig)
	},
	Toolbar: function(config) {
		var defaultConfig = {
			_recursive: true,
			items: []
		}
		this.override(defaultConfig,config);
		return new Ext.Toolbar(defaultConfig)
	},
	Button: function(config) {
		var defaultConfig = {
			_recursive: true,
			text: 'No text'
		}
		this.override(defaultConfig,config);
		return new Ext.Button(defaultConfig)
	},
	Delete: function(_component,config) {
		var defaultConfig = {
			_recursive: true,
			method: 'GET',
			httpVar: 'delData',
			itemType: 'item',
			url: null,
			params:{},
			confirmTitle: this.texts['delete'].confirmTitle,
			confirmBody: this.texts['delete'].confirmBody,
			maskText: this.texts['delete'].maskText,
			errorTitle: this.texts['delete'].errorTitle,
			errorBody: this.texts['delete'].errorBody
		};

		this.override(defaultConfig,config);

		return function(params,_handler) {
			if (!params) params={};
			var ids = _component.getSelectedIds();
			
			if(ids.length > 0) {
				Ext.MessageBox.confirm(
				str_replace('{itemType}',defaultConfig.itemType,defaultConfig.confirmTitle),
				str_replace('{itemType}',defaultConfig.itemType,defaultConfig.confirmBody),
				function(btn) {
					if(btn == 'yes'){
						_component.el.mask(defaultConfig.maskText,'x-mask-loading');

						if (!params[defaultConfig.httpVar]) {
							params[defaultConfig.httpVar] = ids;
						}

						Ext.Ajax.request({
							url: defaultConfig.url,
							scope: this,
							method:defaultConfig.method,
							params: params,
							success: function(response, options) {
								_component.el.unmask();
								if(Ext.decode(response.responseText).success === false) {
									Ext.Msg.alert(defaultConfig.errorTitle, Ext.decode(response.responseText).errorInfo);
								} else {
									if (_handler) _handler();
									_component.fireEvent('afterDelete',ids);
								}
							}
						});
					}
				}
				);
			} else {
				Ext.MessageBox.alert(defaultConfig.errorTitle, str_replace('{itemType}',defaultConfig.itemType,defaultConfig.errorBody));
			}
		}
	},

	HttpVar: function () {
		return function(v) {
			return 'data['+this.config.model+']['+v+']';
		}
	},


	override: function(defaultConfig,newConfig) {
		if (newConfig) {
			for (var i in newConfig) {
				if (newConfig[i] && newConfig[i]!==null && typeof newConfig[i] == 'object' && typeof defaultConfig[i] != 'undefined' && defaultConfig[i]._recursive) {
					this.override(defaultConfig[i],newConfig[i]);
				} else {
					defaultConfig[i]=newConfig[i];
				}
			}
		}
	},
	structure: function(obj,parent) {
		for (var i in obj) {
			if (typeof(obj[i]._)!='undefined' || i=='_') {
				if (i=='_') {
					obj[i]._parent=parent._;
					obj[i]._children=obj;
				} else {
					this.structure(obj[i],obj);
				}
			}
		}
	}
}