duplicateObj = function (o,inArr,notInArr) {
	n = {};
	for (var i in o) {
		if ((!inArr || inArr.indexOf(i)!==-1) && (!notInArr || notInArr.indexOf(i)===-1))
			n[i]=o[i];
	}
	return n;
}

Array.prototype.extract=function(p,ra){
	a=[];
	for(var i=0;i<this.length;i++){
		eval('a.push(this[i].'+p+');');
	};
	if (ra) return a;
	return a.join(',');
}
/*globals Ext, CSRFKiller */

Array.prototype.distinct = function () {
	var r = new Array();
	o:for(var i = 0, n = this.length; i < n; i++){
		for(var x = 0, y = r.length; x < y; x++){
			if(r[x]==this[i]){
				continue o;
			}
		}
		r[r.length] = this[i];
	}
	return r;
}

Ext.namespace("Ext.ux", "Ext.ux.data", "Ext.ux.tree"); //Used by extensions

// Required by data mirroring
Ext.override(Ext.util.Observable, {
  resetEvents: function() {
    var e, es = this.events;
    this.events = {};
    for(e in es) {
      this.events.e = true;
    }
  }
});

Ext.onReady(function() {
 Ext.Ajax.on('beforerequest', function(conn, options) {
    if(typeof options.params == 'object') {
      //Make the two possibilities easier
      options.params = Ext.urlEncode(options.params);
    } else if(options.params && typeof options.params == "string") {
      //options.params = options.params+'&'+CSRFKiller.field+'='+CSRFKiller.token;
    } else if(typeof options.params == 'undefined' && options.form) {
      //options.params = CSRFKiller.field+'='+CSRFKiller.token;
    }
 });
});

Ext.override(Ext.form.Field, {
  setFieldLabel: function(text) {
    var ct = this.el.findParent('div.x-form-item', 3, true);
    var label = ct.first('label.x-form-item-label');
    label.update(text);
  }
});

Ext.override(Ext.data.Store, {
  // Their load records function isn't very extensible,
  // so I had to copy it in here
  loadRecords : function(o, options, success){
    if(!o || success === false){
        if(success !== false){
            this.fireEvent("load", this, [], options);
        }
        if(options.callback){
            options.callback.call(options.scope || this, [], options, false);
        }
        return;
    }
    var r = o.records, t = o.totalRecords || r.length;
    if(!options || options.add !== true){
        if(this.pruneModifiedRecords){
            this.modified = [];
        }
        for(var i = 0, len = r.length; i < len; i++){
            r[i].join(this);
        }
        if(this.snapshot){
            this.data = this.snapshot;
            delete this.snapshot;
        }
        this.data.clear();
        this.data.addAll(r);
        this.totalLength = t;

        this.onDataChanged(); //This line added

        this.fireEvent("datachanged", this);
    }else{
        this.totalLength = Math.max(t, this.data.length+r.length);
        this.add(r);
    }

    this.fireEvent("load", this, r, options);
    if(options.callback){
        options.callback.call(options.scope || this, r, options, true);
    }
  },
  onDataChanged: function() {
    this.applySort();
  }
});


Ext.override(Ext.tree.TreeNodeUI, {
  onDblClick : function(e){
    e.preventDefault();
    if(this.disabled){
      return;
    }
    if(this.checkbox){
      this.toggleCheck();
    }
    // Removed expanding the node, put a dblclick
    // listener on if you want it
    this.fireEvent("dblclick", this.node, e);
  }
});

Ext.override(Ext.Window, {
  showMask: function() {
    if(this.modal){
      Ext.getBody().addClass("x-body-masked");
      this.mask.setSize(Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true));
      this.mask.show();
    }
  },
  hideMask: function() {
    if(this.modal){
      this.mask.hide();
      Ext.getBody().removeClass("x-body-masked");
    }
  }
});

Ext.override(Ext.tree.TreePanel, {
	findNode: function(prop, value) {
		return this.findNodeBy(function(node) {
		  return (node.attributes[prop] == value);
		});
	},
	findNodeBy: function(fn, scope) {
		for (var id in this.nodeHash) {
		  var node = this.nodeHash[id];
		
		  // It's up to the user to specify unique
		  // constraints
		  if(fn.call((scope || this),  node)) {
		    return node;
		  }
		}
	}
});

// Override show / hide Container
Ext.override(Ext.form.Field, {
	showContainer: function() {
		this.enable();
		this.show();
		this.getEl().up('.x-form-item').setDisplayed(true); // show entire container and children (including label if applicable)
	},
	hideContainer: function() {
		this.disable(); // for validation
		this.hide();
		this.getEl().up('.x-form-item').setDisplayed(false); // hide container and children (including label if applicable)
	},
	setContainerVisible: function(visible) {
		if (visible) {
			this.showContainer();
		} else {
			this.hideContainer();
		}
		return this;
		}
});

// Override reBuild grid
Ext.override(Ext.grid.GridPanel,{
    getSelections: function() {
    	return this.getSelectionModel().getSelections();
    },
	reBuild: function (){
    	this.reconfigure(this.store,this.getColumnModel());
    }
});

// Override getSelectedIds

Ext.override(Ext.grid.GridPanel,{
	getSelectedIds: function (){
		var ids='';
    	var m = this.getSelectionModel().getSelections(); 
		for(var i=0; i<m.length; i++){
			var ss = m[i].id;
			if(i===0){
				ids = ss;
			} else {
			    ids += "," + ss;
			}
		}
		return ids.toString();
    }
});

Ext.override(Ext.tree.TreePanel,{
	getSelectedIds: function () {
		if (!this.idName) this.idName = 'id';
		
		var ids = ''; var ids_array = [];
		var selModel = this.getSelectionModel();
		
		if (selModel.selNode) {		/* Single Selection Model */
			ids_array = [selModel.selNode];
		} else if (selModel.selNodes) {
			ids_array = selModel.selNodes;
		}
		
		return ids_array.extract('attributes.'+this.idName);
    },
    getNodeByAttribute: function(attrib, value, node) {
    	if (!node) node = this.getRootNode();
		var nodeFound = null;
		node.cascade(function fnCheckAttrib() {
			if(this.attributes[attrib] && this.attributes[attrib] == value)
			{
				nodeFound = this;
				return false;
			}
		});
		return nodeFound;
	},
	getNodesByAttributes: function(atts, node, single) {
    	if (!node) node = this.getRootNode();
		var nodesFound = [];
		node.cascade(function fnCheckAttrib() {
			
			var found = true;
			
			for (var i in atts) {
				if(!this.attributes[i]) {
					found = false;
				} else {
					if (typeof atts[i].inArray == 'function') {
						if (!atts[i].inArray(this.attributes[i])) {
							found = false;
						}
					} else {
						if (this.attributes[i] != atts[i]) {
							found = false;
						}
					}
				}
			}
			
			if (found) {
				if (single) {
					nodesFound = this;
					return false;
				} else {
					nodesFound.push(this);
				}
			}

		});
		return nodesFound;
	}
});



/*	Overrides default load functionality of the PagingToolbar
	Making it retain all previous store's filters	*/

Ext.PagingToolbar.override({
    doLoad : function(start){
    	if (this.store.lastOptions && this.store.lastOptions.params)
        	var o = this.store.lastOptions.params;
        else var o = {};
        var pn = this.store.paramNames;
        o[pn.start] = start;
        o[pn.limit] = this.pageSize;
        if(this.fireEvent('beforechange', this, o) !== false){
            this.store.load({params:o});
        }
    }
});


Ext.override(Ext.tree.TreeNode, {
	addChild: function(node,unique,before) {
		var tree = this.getOwnerTree();
		if (tree.idName && !unique) 
			unique = tree.idName;
			
		if (!unique) 
			unique = 'id';
		
		if (this.isExpanded()) {
//			this.beginUpdate();
			var appendedNode = this.insertBefore(node,before);
//			this.endUpdate();
			tree.fireEvent('afterNodeAdd',tree,this,appendedNode,before);
		} else {
			this.addListener('expand',function() {
				var foundNode = this.findChild(unique,node.attributes[unique]);
				if (!foundNode) {
//					this.beginUpdate();
					var appendedNode = this.insertBefore(node,before);
//					this.endUpdate();
					tree.fireEvent('afterNodeAdd',tree,this,appendedNode,before);
				} else {
					tree.fireEvent('afterNodeAdd',tree,this,foundNode,before);
				}
			},null,{single: true});
			this.expand();
		}
	},
	addChildren: function(nodes,unique) {
		if (!unique) unique = 'id';
		
		if (this.isExpanded()) {
			for (var i=0; i<nodes.length;i++) {
				this.appendChild(nodes[i]);
			}
		} else {
			this.addListener('expand',function() {
				for (var i=0; i<nodes.length;i++) {
					
					if (!this.findChild(unique,nodes[i].attributes[unique])) {
						this.appendChild(nodes[i]);
					}
					
				}
			},null,{single: true});
			this.expand();
		}
	},
	copy: function(customAtts) {
		var atts = this.attributes;
		if (customAtts)
			for (var i in customAtts) 
				atts[i] = customAtts[i];
		return new Ext.tree.TreeNode(atts);
	},
	isLoaded: function() {
		if (this.childNodes.length>0) {
			return true;
		}
		return false;
	},
	reload: function(callback) {
		if (this.getOwnerTree())
			this.getOwnerTree().loader.load(this,callback);
	},
	getParentBy : function(property, value) {
		if (!this.parentNode) return false;
		if (this.parentNode.attributes[property]==value) {
			return this.parentNode;
		} else {
			return this.getParentBy(property, value);
		}
	}
});

Ext.override(Ext.BoxComponent,{
	setInnerHtml: function(v) {
		this.el.dom.innerHTML=v;
	},
	getInnerHtml: function(v) {
		return this.el.dom.innerHTML;
	}
});


Ext.DomQuery.matchers[2] = {
    re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?(["']?)(.*?)\4)?[\]\}])/,
    select: 'n = byAttribute(n, "{2}", "{5}", "{3}", "{1}");'
};

// fix the [] problem in name (still required for ext 3.x)
Ext.override(Ext.form.Radio, {
    onClick : function(){
    	if(this.el.dom.checked != this.checked){
			var els = this.getCheckEl().select('input[name="' + this.el.dom.name + '"]');
			els.each(function(el){
				if(el.dom.id == this.id){
					this.setValue(true);
				}else{
					Ext.getCmp(el.dom.id).setValue(false);
				}
			}, this);
		}
    },
    setValue : function(v){
    	if (typeof v == 'boolean') {
            Ext.form.Radio.superclass.setValue.call(this, v);
        } else if (this.rendered) {
            var r = this.getCheckEl().child('input[name="' + this.el.dom.name + '"][value=' + v + ']', true);
            if(r){
                Ext.getCmp(r.id).setValue(true);
            }
        }
        return this;
    }
});
