Ext.override(Ext.DataView, {
    onUpdate : function(ds, record){
        var index = this.store.indexOf(record);
        if(index > -1){
            var sel = this.isSelected(index),
                original = this.all.elements[index],
                node = this.bufferRender([record], index)[0];

            this.all.replaceElement(index, node, true);
            if(sel){
                this.selected.replaceElement(original, node);
                this.all.item(index).addClass(this.selectedClass);
            }
            this.updateIndexes(index, index);
        }
    }
});Ext.override(Ext.data.DataReader, {
    realize: function(rs, data){
        if (Ext.isArray(rs)) {
            for (var i = rs.length - 1; i >= 0; i--) {
                // recurse
                if (Ext.isArray(data)) {
                    this.realize(rs.splice(i,1).shift(), data.splice(i,1).shift());
                }
                else {
                    // weird...rs is an array but data isn't??  recurse but just send in the whole invalid data object.
                    // the else clause below will detect !this.isData and throw exception.
                    this.realize(rs.splice(i,1).shift(), data);
                }
            }
        }
        else {
            // If rs is NOT an array but data IS, see if data contains just 1 record.  If so extract it and carry on.
            if (Ext.isArray(data) && data.length == 1) {
                data = data.shift();
            }
            if (!this.isData(data)) {
                // TODO: Let exception-handler choose to commit or not rather than blindly rs.commit() here.
                //rs.commit();
                throw new Ext.data.DataReader.Error('realize', rs);
            }
            rs.phantom = false; // <-- That's what it's all about
            rs._phid = rs.id;  // <-- copy phantom-id -> _phid, so we can remap in Store#onCreateRecords
            rs.id = this.getId(data);
            rs.data = data;

            rs.commit();
			rs.store.reMap(rs);
        }
    }
});Ext.override(Ext.data.Record, {

});Ext.override(Ext.data.Store, {
});Ext.override(Ext.form.TextArea, {
	// This will add a DOM attribute to prevent spellcheck in at least Firefox...
	onRender:Ext.form.TextArea.prototype.onRender.createSequence(function() {
		this.el.dom.spellcheck = "";
	})
});Ext.ns('monoql.bar');
monoql.bar.bar = function() {
	var cls = 'monoql-bar-bar';
	var Class = Ext.extend(Ext.Toolbar, {
		initComponent: function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.bar');
monoql.bar.menubar = function() {
	var cls = 'monoql-bar-menubar';
	var Class = Ext.extend(monoql.bar.bar, {
		initComponent: function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.bar');
monoql.bar.toolbar = function() {
	var cls = 'monoql-bar-toolbar';
	var Class = Ext.extend(monoql.bar.bar, {
		initComponent: function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.bar');
monoql.bar.connectiontreetoolbar = function() {
	var cls = 'monoql-bar-connectiontreetoolbar';	
	var Class = Ext.extend(monoql.bar.toolbar, {
		style:'border-left-width:0px;border-top-width:0px;',
		initComponent: function() {
			this.newconnectionbutton = new monoql.button.button({
				text:'New Connection',
				iconCls:cls + '-newconnectionbutton-icon',
				enableToggle:true
			});
			this.refreshbutton = new monoql.button.button({
				text:'',
				disabled:true,
				iconCls:cls + '-refreshbutton-icon',
				onConnectionTreeSelectionChange:function(selModel, node) {
					this.setDisabled(!selModel.getSelectedNode());
				}
			});
			this.newconnectionbutton.on('toggle', this.onNewConnectionButtonToggle, this);
			this.on('render', this.onConnectionTreeToolBarRender, this);
			this.items = [this.newconnectionbutton, '->', this.refreshbutton];
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		},
		onConnectionTreeToolBarRender:function(toolbar) {
			Ext.getCmp('viewport').connectionform.on('hide', this.onUiConnectionFormHide, this);
		},
		onUiConnectionFormHide:function(form) {
			this.newconnectionbutton.toggle(false);
		},
		onNewConnectionButtonToggle:function(button, pressed) {
			if (pressed) {
				if (!ui.connectionform.rendered) {
					ui.connectionform.render(Ext.getBody());
				}
				ui.connectionform.show().el.anchorTo(button.el, 'tl-bl');
			} else {
				ui.connectionform.hide();
			}
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.bar');
monoql.bar.querytabstatusbar = function() {
	var cls = 'monoql-bar-querytabstatusbar';
	var Class = Ext.extend(monoql.bar.toolbar, {
		initComponent: function() {
			this.connectionstatusdisplayfield = new Ext.form.DisplayField({
				value:''
			});
			this.hoststatusdisplayfield = new Ext.form.DisplayField({
				value:'Host Info...'
			});
			this.userstatusdisplayfield = new Ext.form.DisplayField({
				value:'User Info...'
			});
			this.databasestatusdisplayfield = new Ext.form.DisplayField({
				value:''
			});
			this.timerdisplayfield = new Ext.form.DisplayField({
				value:'00:00:00'
			});
			this.rowcountdisplayfield = new Ext.form.DisplayField({
				value:'0 Rows'
			});
			this.items = [this.connectionstatusdisplayfield, '->',
				'-', this.hoststatusdisplayfield,
				'-', this.userstatusdisplayfield,
				'-', this.databasestatusdisplayfield,
				'-', this.timerdisplayfield,
				'-', this.rowcountdisplayfield
			];
			this.querytab.on('connectionchange', this.onQueryTabConnectionChange, this);
			this.querytab.on('databasechange', this.onQueryTabDatabaseChange, this);
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		},
		onQueryTabConnectionChange:function(tab, oldConn, newConn) {
			this.updateConnectionStatus(newConn);
			this.updateUserStatus(newConn);
			this.updateHostStatus(newConn);
		},
		onQueryTabDatabaseChange:function(tab, oldDb, newDb) {
			this.updateDatabaseStatus(newDb);
		},
		updateConnectionStatus:function(conn) {
			var text = conn.get('name');
			this.connectionstatusdisplayfield.setValue(text);
		},
		updateUserStatus:function(conn) {
			var text = conn.get('username');
			this.userstatusdisplayfield.setValue(text);
		},
		updateHostStatus:function(conn) {
			var text = conn.get('host');
			this.hoststatusdisplayfield.setValue(text);
		},
		updateDatabaseStatus:function(database) {
			this.databasestatusdisplayfield.setValue(database || 'No Database');
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.bar');
monoql.bar.maintoolbar = function() {
	var cls = 'monoql-bar-maintoolbar';
	var Class = Ext.extend(monoql.bar.toolbar, {
		height:26,
		initComponent: function() {
			this.filemenu = new monoql.menu.filemenu();
			this.editmenu = new monoql.menu.editmenu();
			this.toolsmenu = new monoql.menu.toolsmenu();
			this.datamenu = new monoql.menu.datamenu();
			this.helpmenu = new monoql.menu.helpmenu();
			this.openfilebutton = new monoql.button.openfilebutton();
			this.savefilebutton = new monoql.button.savefilebutton();
			this.runquerybutton = new monoql.button.runquerybutton();
			this.cancelquerybutton = new monoql.button.cancelquerybutton();
			this.addquerytabbutton = new monoql.button.addquerytabbutton();
			this.resultstogridbutton = new monoql.button.resultstogridbutton();
			this.resultstotextbutton = new monoql.button.resultstotextbutton();
			this.resultstofilebutton = new monoql.button.resultstofilebutton();
			this.connectioncombobox = new monoql.form.connectioncombobox({
				disabled:true
			});
			this.databasecombobox = new monoql.form.databasecombobox({
				disabled:true
			});
			this.items = [{
				text:'File',
				menu:this.filemenu
			}, {
				text:'Edit',
				menu:this.editmenu
			}, {
				text:'Tools',
				menu:this.toolsmenu
			}, {
				text:'Data',
				menu:this.datamenu
			}, {
				text:'Help',
				menu:this.helpmenu
			},
				'-', 
				this.openfilebutton, 
				this.savefilebutton,
				'-', 
				this.runquerybutton, 
				this.cancelquerybutton,
				this.addquerytabbutton,
				'-', 
				this.resultstogridbutton, 
				this.resultstotextbutton, 
				this.resultstofilebutton,
				'-',
				this.connectioncombobox,
				'-',
				this.databasecombobox
			];
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		},
		initListeners:function() {
			ui.tabs.on({
				scope:this,
				tabchange:this.onMainTabSetTabChange,
				add:this.onMainTabSetAdd
			});
			this.connectioncombobox.on('select', this.onConnectionComboBoxSelect, this);
		},
		onMainTabSetAdd:function(tabset, tab, index) {
			if (tab.getXType()==='monoql-tab-querytab') {
				tab.queryform.on({
					scope:this,
					beforequery:this.onQueryTabBeforeQuery,
					query:this.onQueryTabQuery,
					queryresult:this.onQueryTabQueryResult,
					cancelquery:this.onQueryTabCancelQuery
				});
			}
		},
		onQueryTabBeforeQuery:function(queryform, query, connection) {
		},
		onQueryTabQuery:function(queryform, query, connection) {
			this.runquerybutton.disable();
			this.cancelquerybutton.enable();
		},
		onQueryTabQueryResult:function(queryform, query, connection, result) {
			this.cancelquerybutton.disable();
			this.runquerybutton.enable();
		},
		onQueryTabCancelQuery:function(queryform, connection) {
			this.cancelquerybutton.disable();
			this.runquerybutton.enable();
		},
		onMainTabSetTabChange:function(tabset, tab) {
			(!tabset.getActiveTab() ? this.onNoActiveTab : this.onActiveTab).call(this, tab);
		},
		onNoActiveTab:function() {
			this.runquerybutton.disable();
			this.connectioncombobox.reset();
			this.connectioncombobox.disable();
			this.databasecombobox.reset();
			this.databasecombobox.disable();
			delete this.databasecombobox.lastQuery;
		},
		onActiveTab:function(tab) {
			if (tab.getXType()==='monoql-tab-querytab' && !tab.executing) {
				this.runquerybutton.enable();
			}
			if (tab.connection) {
				this.connectioncombobox.setValue(tab.connection.get('id'));
				this.connectioncombobox.enable();
				this.databasecombobox.setValue(tab.database);
				this.databasecombobox.enable();
			}
		},
		onConnectionComboBoxSelect:function(combo, record, index) {
			this.databasecombobox.reset();
			delete this.databasecombobox.lastQuery;
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.bar');
monoql.bar.tablegridpagingtoolbar = function() {
	var cls = 'monoql-bar-tablegridpagingtoolbar';
	var Class = Ext.extend(Ext.ux.grid.livegrid.Toolbar, {
		initComponent: function() {
			Ext.applyIf(this, {
				view:this.grid.view,
				displayInfo:true,
			});
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.bar');
monoql.bar.resultgridpagingtoolbar = function() {
	var cls = 'monoql-bar-resultgridpagingtoolbar';
	var Class = Ext.extend(Ext.ux.grid.livegrid.Toolbar, {
		initComponent: function() {
			Ext.applyIf(this, {
				view:this.grid.view,
				displayInfo:true,
			});
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.menu = function() {
	var cls = 'monoql-menu-menu';
	var Class = Ext.extend(Ext.menu.Menu, {
		defaultType:'monoql-menu-item',
		initComponent: function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.item = function() {
	var cls = 'monoql-menu-item';
	var Class = Ext.extend(Ext.menu.Item, {
		initComponent: function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.filemenu = function() {
	var cls = 'monoql-menu-filemenu';
	var Class = Ext.extend(monoql.menu.menu, {
		initComponent:function() {
			this.newquery = new monoql.menu.item({
				text:'New Query',
				iconCls:cls + '-newquery'
			});
			this.open = new monoql.menu.item({
				text:'Open',
				iconCls:cls + '-open'
			});
			this.save = new monoql.menu.item({
				text:'Save',
				iconCls:cls + '-save'
			});
			this.saveas = new monoql.menu.item({
				text:'Save As',
				iconCls:cls + '-saveas'
			});
			this.items = [this.newquery, this.open, this.save, this.saveas];
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.editmenu = function() {
	var cls = 'monoql-menu-editmenu';
	var Class = Ext.extend(monoql.menu.menu, {
		initComponent:function() {
			this.items = [{
				text:'Some Item'
			}];
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.toolsmenu = function() {
	var cls = 'monoql-menu-toolsmenu';
	var Class = Ext.extend(monoql.menu.menu, {
		initComponent:function() {
			this.items = [];
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.datamenu = function() {
	var cls = 'monoql-menu-datamenu';
	var Class = Ext.extend(monoql.menu.menu, {
		initComponent:function() {
			this.items = [{
				text:'Some Item'
			}];
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.helpmenu = function() {
	var cls = 'monoql-menu-helpmenu';
	var Class = Ext.extend(monoql.menu.menu, {
		initComponent:function() {
			this.items = [{
				text:'Some Item'
			}];
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.nodemenu = function() {
	var cls = 'monoql-menu-nodemenu';
	var Class = Ext.extend(monoql.menu.menu, {
		initComponent: function() {
			this.refresh = new monoql.menu.item({
				text:'Refresh',
				iconCls:'monoql-menu-item-refresh-icon'
			});
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.groupnodemenu = function() {
	var cls = 'monoql-menu-groupnodemenu';
	var Class = Ext.extend(monoql.menu.nodemenu, {
		initComponent:function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
			this.add([this.refresh]);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.backupgroupnodemenu = function() {
	var cls = 'monoql-menu-backupgroupnodemenu';
	var Class = Ext.extend(monoql.menu.nodemenu, {
		initComponent:function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
			this.add([this.refresh]);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.backupnodemenu = function() {
	var cls = 'monoql-menu-backupnodemenu';
	var Class = Ext.extend(monoql.menu.nodemenu, {
		initComponent:function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
			this.add([this.refresh]);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.connectiongroupnodemenu = function() {
	var cls = 'monoql-menu-connectiongroupnodemenu';
	var Class = Ext.extend(monoql.menu.nodemenu, {
		initComponent:function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
			this.add([this.refresh]);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.connectionnodemenu = function() {
	var cls = 'monoql-menu-connectionnodemenu';
	var Class = Ext.extend(monoql.menu.nodemenu, {
		initComponent:function() {
			this.modify = new monoql.menu.item({
				text:'Modify',
				iconCls:'monoql-menu-item-modifyconnection-icon'
			});
			this.remove = new monoql.menu.item({
				text:'Remove',
				iconCls:'monoql-menu-item-removeconnection-icon'
			});
			this.query = new monoql.menu.item({
				text:'New Query',
				iconCls:'monoql-menu-item-query-icon'
			});
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
			this.add([this.query, this.modify, this.remove, this.refresh]);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.databasenodemenu = function() {
	var cls = 'monoql-menu-databasenodemenu';
	var Class = Ext.extend(monoql.menu.nodemenu, {
		initComponent:function() {
			this.query = new monoql.menu.item({
				text:'New Query',
				iconCls:'monoql-menu-item-query-icon'
			});
			this.createtable = new monoql.menu.item({
				text:'Create Table',
				iconCls:'monoql-menu-item-createtable-icon'
			});
			this.dropalltables = new monoql.menu.item({
				text:'Drop All Tables',
				iconCls:'monoql-menu-item-dropalltables-icon'
			});
			this.emptyalltables = new monoql.menu.item({
				text:'Empty All Tables',
				iconCls:'monoql-menu-item-emptyalltables-icon'
			});
			this.drop = new monoql.menu.item({
				text:'Drop Database',
				iconCls:'monoql-menu-item-dropdatabase-icon'
			});
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
			this.add([this.query, this.createtable, this.emptyalltables, this.dropalltables, this.drop, this.refresh]);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.functiongroupnodemenu = function() {
	var cls = 'monoql-menu-functiongroupnodemenu';
	var Class = Ext.extend(monoql.menu.nodemenu, {
		initComponent:function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
			this.add([this.refresh]);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.functionnodemenu = function() {
	var cls = 'monoql-menu-functionnodemenu';
	var Class = Ext.extend(monoql.menu.nodemenu, {
		initComponent:function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
			this.add([this.refresh]);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.scriptgroupnodemenu = function() {
	var cls = 'monoql-menu-scriptgroupnodemenu';
	var Class = Ext.extend(monoql.menu.nodemenu, {
		initComponent:function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
			this.add([this.refresh]);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.scriptnodemenu = function() {
	var cls = 'monoql-menu-scriptnodemenu';
	var Class = Ext.extend(monoql.menu.nodemenu, {
		initComponent:function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
			this.add([this.refresh]);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.sprocgroupnodemenu = function() {
	var cls = 'monoql-menu-sprocgroupnodemenu';
	var Class = Ext.extend(monoql.menu.nodemenu, {
		initComponent:function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
			this.add([this.refresh]);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.sprocnodemenu = function() {
	var cls = 'monoql-menu-sprocnodemenu';
	var Class = Ext.extend(monoql.menu.nodemenu, {
		initComponent:function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
			this.add([this.refresh]);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.tablegroupnodemenu = function() {
	var cls = 'monoql-menu-tablegroupnodemenu';
	var Class = Ext.extend(monoql.menu.nodemenu, {
		initComponent:function() {
			this.query = new monoql.menu.item({
				text:'New Query',
				iconCls:'monoql-menu-item-query-icon'
			});
			this.create = new monoql.menu.item({
				text:'Create Table',
				iconCls:'monoql-menu-item-createtable-icon'
			});
			this.dropall = new monoql.menu.item({
				text:'Drop All Tables',
				iconCls:'monoql-menu-item-dropalltables-icon'
			});
			this.emptyall = new monoql.menu.item({
				text:'Empty All Tables',
				iconCls:'monoql-menu-item-emptyalltables-icon'
			});
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
			this.add([this.query, this.create, this.emptyall, this.dropall, this.refresh]);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.tablenodemenu = function() {
	var cls = 'monoql-menu-tablenodemenu';
	var Class = Ext.extend(monoql.menu.nodemenu, {
		initComponent:function() {
			this.query = new monoql.menu.item({
				text:'New Query',
				iconCls:'monoql-menu-item-query-icon'
			});
			this.open = new monoql.menu.item({
				text:'View Data',
				iconCls:'monoql-menu-item-tabledata-icon'
			});
			this.modify = new monoql.menu.item({
				text:'Modify',
				iconCls:'monoql-menu-item-modifytable-icon'
			});
			this.empty = new monoql.menu.item({
				text:'Empty',
				iconCls:'monoql-menu-item-emptytable-icon'
			});
			this.drop = new monoql.menu.item({
				text:'Drop',
				iconCls:'monoql-menu-item-droptable-icon'
			});
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
			this.add([this.query, this.open, this.modify, this.empty, this.drop, this.refresh]);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.columnnodemenu = function() {
	var cls = 'monoql-menu-columnnodemenu';
	var Class = Ext.extend(monoql.menu.nodemenu, {
		initComponent:function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
			this.add([this.refresh]);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.triggergroupnodemenu = function() {
	var cls = 'monoql-menu-triggergroupnodemenu';
	var Class = Ext.extend(monoql.menu.nodemenu, {
		initComponent:function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
			this.add([this.refresh]);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.triggernodemenu = function() {
	var cls = 'monoql-menu-triggernodemenu';
	var Class = Ext.extend(monoql.menu.nodemenu, {
		initComponent:function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
			this.add([this.refresh]);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.usergroupnodemenu = function() {
	var cls = 'monoql-menu-usergroupnodemenu';
	var Class = Ext.extend(monoql.menu.nodemenu, {
		initComponent:function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
			this.add([this.refresh]);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.usernodemenu = function() {
	var cls = 'monoql-menu-usernodemenu';
	var Class = Ext.extend(monoql.menu.nodemenu, {
		initComponent:function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
			this.add([this.refresh]);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.viewgroupnodemenu = function() {
	var cls = 'monoql-menu-viewgroupnodemenu';
	var Class = Ext.extend(monoql.menu.nodemenu, {
		initComponent:function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
			this.add([this.refresh]);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.menu');
monoql.menu.viewnodemenu = function() {
	var cls = 'monoql-menu-viewnodemenu';
	var Class = Ext.extend(monoql.menu.nodemenu, {
		initComponent:function() {
			this.open = new monoql.menu.item({
				text:'View Data',
				iconCls:'monoql-menu-item-viewdata-icon'
			});
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
			this.add([this.open, this.refresh]);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.button');
monoql.button.button = function() {
	var cls = 'monoql-button-button';
	var Class = Ext.extend(Ext.Button, {
		initComponent: function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.button');
monoql.button.openfilebutton = function() {
	var cls = 'monoql-button-openfilebutton';
	var Class = Ext.extend(monoql.button.button, {
		iconCls:cls + '-icon',
		tooltip:'Open a query file',
		initComponent: function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.button');
monoql.button.savefilebutton = function() {
	var cls = 'monoql-button-savefilebutton';
	var Class = Ext.extend(monoql.button.button, {
		iconCls:cls + '-icon',
		disabled:true,
		tooltip:'Save active query to file',
		initComponent: function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.button');
monoql.button.runquerybutton = function() {
	var cls = 'monoql-button-runquerybutton';
	var Class = Ext.extend(monoql.button.button, {
		iconCls:cls + '-icon',
		disabled:true,
		tooltip:'Execute active query',
		initComponent: function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.button');
monoql.button.cancelquerybutton = function() {
	var cls = 'monoql-button-cancelquerybutton';
	var Class = Ext.extend(monoql.button.button, {
		iconCls:cls + '-icon',
		disabled:true,
		tooltip:'Cancel active query',
		initComponent: function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.button');
monoql.button.addquerytabbutton = function() {
	var cls = 'monoql-button-addquerytabbutton';
	
	var Menu = Ext.extend(monoql.menu.menu, {
		initComponent:function() {
			this.on({
				scope:this,
				beforeshow:this.onAddQueryTabButtonMenuBeforeShow,
				afterrender:this.onAddQueryTabButtonMenuAfterRender,
				itemclick:this.onAddQueryTabButtonMenuItemClick
			});
			Menu.superclass.initComponent.call(this);
			this.addClass(cls + '-menu');
		},
		onAddQueryTabButtonMenuItemClick:function(item, e) {
			if (item.connection) {
				ui.tabs.addQueryTab(item.connection);
			}
		},
		onAddQueryTabButtonMenuBeforeShow:function(menu) {
			return this.items.getCount()>0;
		},
		onAddQueryTabButtonMenuAfterRender:function(menu) {
			this.addItemsFromConnectionStore(ui.connectionstore.getRange());
			ui.connectionstore.on({
				scope:this,
				add:this.onConnectionStoreAdd,
				remove:this.onConnectionStoreRemove,
				update:this.onConnectionStoreUpdate
			});
		},
		addItemsFromConnectionStore:function(records) {
			Ext.each(records, function(item, i, items) {
				this.add(new monoql.menu.item({
					connection:item,
					text:item.get('name'),
					iconCls:cls + '-menu-connectionitem-icon'
				}));
			}, this);
		},
		getItemByConnection:function(connection) {
			var menuItem;
			this.items.each(function(item, i, length) {
				if (item.connection.id===connection.id) {
					menuItem = item;
					return false;
				}
			});
			return menuItem;
		},
		onConnectionStoreAdd:function(store, records, index) {
			this.addItemsFromConnectionStore(records);
		},
		onConnectionStoreRemove:function(store, record, index) {
			this.items.each(function(item, index, length) {
				if (item.connection===record) {
					this.remove(item);
				}
			}, this);
		},
		onConnectionStoreUpdate:function(store, record, index) {
			this.getItemByConnection(record).setText(record.get('name'));
		}
	});
	
	var Class = Ext.extend(monoql.button.button, {
		iconCls:cls + '-icon',
		tooltip:'Add a new query tab',
		menu:new Menu(),
		initComponent: function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.button');
monoql.button.resultstogridbutton = function() {
	var cls = 'monoql-button-resultstogridbutton';
	var Class = Ext.extend(monoql.button.button, {
		iconCls:cls + '-icon',
		tooltip:'Display query results as grid',
		enableToggle:true,
		toggleGroup:'monoql-button-resultstogglegroup',
		pressed:true,
		initComponent: function() {
			this.on('click', this.onResultsToGridButtonClick, this);
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		},
		onResultsToGridButtonClick:function(button, e) {
			if (!this.pressed) {
				this.toggle(true);
			}
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.button');
monoql.button.resultstotextbutton = function() {
	var cls = 'monoql-button-resultstotextbutton';
	var Class = Ext.extend(monoql.button.button, {
		iconCls:cls + '-icon',
		tooltip:'Display query results as text',
		enableToggle:true,
		toggleGroup:'monoql-button-resultstogglegroup',
		initComponent: function() {
			this.on('click', this.onResultsToTextButtonClick, this);
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		},
		onResultsToTextButtonClick:function(button, e) {
			if (!this.pressed) {
				this.toggle(true);
			}
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.button');
monoql.button.resultstofilebutton = function() {
	var cls = 'monoql-button-resultstofilebutton';
	var Class = Ext.extend(monoql.button.button, {
		iconCls:cls + '-icon',
		tooltip:'Save query results to file',
		enableToggle:true,
		toggleGroup:'monoql-button-resultstogglegroup',
		initComponent: function() {
			this.on('click', this.onResultsToFileButtonClick, this);
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		},
		onResultsToFileButtonClick:function(button, e) {
			if (!this.pressed) {
				this.toggle(true);
			}
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.data');
monoql.data.connectionrecord = function() {
	var Class = Ext.data.Record.create([
		{name:'id', type:'int'},
		{name:'name', type:'string'},
		{name:'type', type:'string'},
		{name:'host', type:'string'},
		{name:'username', type:'string'},
		{name:'password', type:'string'},
		{name:'port', type:'int'},
		{name:'defaultDatabase', type:'string', mapping:'default_database'},
		{name:'mdate', type:'date'},
		{name:'cdate', type:'date'},
		{name:'deleted', type:'bool'},
		{name:'databases'}
	]);
	return Class;
}();Ext.ns('monoql.data');
monoql.data.connectionstore = function() {	
	var Reader = Ext.extend(Ext.data.JsonReader, {
		constructor:function(meta, recordType) {
			meta = Ext.apply({
				root:'records'
			}, meta);
			Reader.superclass.constructor.call(this, meta, recordType);
		}
	});
	
	var Writer = Ext.extend(Ext.data.JsonWriter, {
		constructor:function(meta, recordType) {
			meta = Ext.apply({
				encode:false,
				listful:true,
				writeAllFields:true
			}, meta);
			Writer.superclass.constructor.call(this, meta, recordType);
		}
	});
	
	var Proxy = Ext.extend(Ext.data.DirectProxy, {
		constructor:function(config) {
			var config = Ext.apply({
				api:{
					read:monoql.direct.Connection.get,
					create:monoql.direct.Connection.create,
					update:monoql.direct.Connection.save,
					destroy:monoql.direct.Connection.delete
				},
				paramOrder:['args']
			}, config);
			Proxy.superclass.constructor.call(this, config);
		}
	});

	var Class = Ext.extend(Ext.data.Store, {
		constructor:function(config) {
			config = Ext.apply({
				proxy:new Proxy(),
				reader:new Reader({}, monoql.data.connectionrecord),
				writer:new Writer({}, monoql.data.connectionrecord),
				baseParams:{
					args:{}
				}
			}, config);
			Class.superclass.constructor.call(this, config);
		}
	});
	return Class;
}();Ext.ns('monoql.data');
monoql.data.tablegridproxy = Ext.extend(Ext.data.DirectProxy, {
	constructor:function(config) {
		var config = Ext.apply({
			api:{
				read:monoql.direct.TableGrid.load
			},
			paramOrder:['table', 'connectionId', 'limit', 'start', 'sort', 'dir', 'database']
		}, config);
		monoql.data.tablegridproxy.superclass.constructor.call(this, config);
	}
});

monoql.data.tablegridrecord = Ext.data.Record.create([
	// Fields will defined at runtime by the column list for the recordset returned by the query
]);

monoql.data.tablegridreader = Ext.extend(Ext.ux.grid.livegrid.JsonReader, {
	constructor:function(meta, recordType) {
		meta = Ext.apply({
			idProperty:'__id__',
			root:'rows',
			totalProperty:'total',
			successProperty:'success',
			messageProperty:'message',
			fields:monoql.data.tablegridrecord
		}, meta);
		monoql.data.tablegridreader.superclass.constructor.call(this, recordType);
	}
});

monoql.data.tablegridstore = function() {
	var Class = Ext.extend(Ext.ux.grid.livegrid.Store, {
		constructor:function(config) {
			config = Ext.apply({
				bufferSize:100,
				autoDestroy:true,
				autoLoad:false,
				remoteSort:true,
				sortInfo:{field:null, direction:null},
				proxy:new monoql.data.tablegridproxy({store:this}),
				reader:new monoql.data.tablegridreader({store:this}),
				baseParams:{
					start:0,
					limit:100,
					sort:null,
					dir:null
				}
			}, config);
			Class.superclass.constructor.call(this, config);
		}
	});
	return Class;
}();Ext.ns('monoql.data');
monoql.data.resultgridproxy = function() {
	var Class = Ext.extend(Ext.data.DirectProxy, {
		constructor:function(config) {
			var config = Ext.apply({
				api:{
					read:monoql.direct.ResultGrid.load
				},
				paramOrder:['query', 'connectionId', 'limit', 'start', 'database']
			}, config);
			Class.superclass.constructor.call(this, config);
		}
	});
	return Class;
}();Ext.ns('monoql.data');
monoql.data.resultgridrecord = function() {
	var Class = Ext.data.Record.create([
		// Fields will defined at runtime by the column list for the recordset returned by the query
	]);
	return Class;
}();Ext.ns('monoql.data');
monoql.data.resultgridreader = function() {
	var Class = Ext.extend(Ext.ux.grid.livegrid.JsonReader, {
		constructor:function(meta, recordType) {
			meta = Ext.apply({
				idProperty:'__id__',
				root:'rows',
				totalProperty:'total',
				successProperty:'success',
				messageProperty:'message',
				fields:monoql.data.resultgridrecord
			}, meta);
			Class.superclass.constructor.call(this, recordType);
		}
	});
	return Class;
}();Ext.ns('monoql.data');
monoql.data.resultgridstore = function() {
	var Class = Ext.extend(Ext.ux.grid.livegrid.Store, {
		constructor:function(config) {
			config = Ext.apply({
				bufferSize:300,
				autoDestroy:true,
				autoLoad:false,
				proxy:new monoql.data.resultgridproxy({store:this}),
				reader:new monoql.data.resultgridreader({store:this}),
				baseParams:{
					query:null,
					connectionId:null,
					start:0,
					limit:100
				}
			}, config);
			Class.superclass.constructor.call(this, config);
		}
	});
	return Class;
}();Ext.ns('monoql.form');
monoql.form.textbox = function() {
	var cls = 'monoql-form-textbox';
	var Class = Ext.extend(Ext.form.TextField, {
		initComponent: function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();

Ext.apply(Ext.form.TextField.prototype, {
	getSelectedText:function() {
		var selection = this.getSelection();
		return selection ? selection.text : null;
	},
	getSelection:function() {
		var domElement = this.getEl().dom; 
		if (Ext.isIE){ 
			var sel = document.selection;
			var range = sel.createRange();
			if (range.parentElement()!=domElement) return null;
			var bookmark = range.getBookmark();
			var selection = domElement.createTextRange();
			selection.moveToBookmark(bookmark);
			var before = domElement.createTextRange();
			before.collapse(true);
			before.setEndPoint("EndToStart", selection);
			var after = domElement.createTextRange();
			after.setEndPoint("StartToEnd", selection);
			return {
				selectionStart:before.text.length,
				selectionEnd:before.text.length + selection.text.length,
				beforeText:before.text,
				text:selection.text,
				afterText:after.text
			};
		} else {
			if (Ext.isNumber(domElement.selectionEnd) && Ext.isNumber(domElement.selectionStart)) {
				if (domElement.selectionEnd > domElement.selectionStart){ 
					return {
						selectionStart:domElement.selectionStart,
						selectionEnd:domElement.selectionEnd,
						beforeText:domElement.value.substr(0, domElement.selectionStart),
						text:domElement.value.substr(domElement.selectionStart, domElement.selectionEnd - domElement.selectionStart),
						afterText:domElement.value.substr(domElement.selectionEnd)
					};
				} 
			}
		}
		return null;
	}
});Ext.ns('monoql.form');
monoql.form.combobox = function() {
	var cls = 'monoql-form-combobox';
	var Class = Ext.extend(Ext.form.ComboBox, {
		initComponent:function() {
			this.addListener('render', this.onComboBoxRender, this, {single:true});
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		},
		onComboBoxRender:function(combo) {
			combo.el.addListener('focus', this.onComboBoxElementFocus, combo.el, {combo:combo});
		},
		onComboBoxElementFocus:function(event, target, options) {
			if (!options.combo.editable && target.blur) {
				target.blur();
			}
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.form');
monoql.form.connectioncombobox = function() {
	var cls = 'monoql-form-connectioncombobox';
	var Class = Ext.extend(monoql.form.combobox, {
		emptyText:'Set Active Connection...',
		forceSelection:true,
		editable:false,
		displayField:'name',
		valueField:'id',
		hiddenName:'activeConnection',
		mode:'local',
		triggerAction:'all',
		lazyInit:false,
		initComponent: function() {
			this.store = ui.connectionstore;
			this.store.on('update', this.onConnectionComboBoxStoreUpdate, this);
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		},
		onConnectionComboBoxStoreUpdate:function(store, record, index) {
			if (parseInt(this.getValue())===parseInt(record.id)) {
				this.setRawValue(record.get(this.displayField));
			}
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.form');
monoql.form.databasecombobox = function() {
	var cls = 'monoql-form-databasecombobox';
	
	var Store = Ext.extend(Ext.data.Store, {
		constructor: function(config) {
			config = Ext.apply({
				proxy:new Ext.data.DirectProxy({
					api:{
						read:monoql.direct.Connection.getDatabases
					},
					paramsAsHash:true
				}),
				reader:new Ext.data.JsonReader({
					root:'records',
					fields:['id', 'name']
				})
			}, config);
			Store.superclass.constructor.call(this, config);
		}
	});
	
	var Class = Ext.extend(monoql.form.combobox, {
		emptyText:'Set Active Database...',
		forceSelection:true,
		editable:false,
		displayField:'name',
		valueField:'id',
		hiddenName:'activeDatabase',
		mode:'remote',
		triggerAction:'all',
		initComponent: function() {
			this.store = new Store();
			this.store.on('beforeload', this.onDatabaseComboBoxStoreBeforeLoad, this);
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		},
		onDatabaseComboBoxStoreBeforeLoad:function(store, options) {
			store.baseParams.connectionId = ui.toolbar.connectioncombobox.getValue();
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.form');
monoql.form.form = function() {
	var cls = 'monoql-form-form';
	var Class = Ext.extend(Ext.form.FormPanel, {
		defaults:{
			xtype:'textfield',
			anchor:'-8'
		},
		initComponent: function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.form');
monoql.form.floatingform = function() {
	var cls = 'monoql-form-floatingform';
	var Class = Ext.extend(monoql.form.form, {
		floating:true,
		autoHeight:true,
		width:600,
		labelAlign:'top',
		frame:true,
		initComponent: function() {
			this.tools = [{
				id:'close',
				handler:this.onCloseToolClick,
				scope:this
			}];
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		},
		onCloseToolClick:function() {
			this.hide();
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.form');
monoql.form.queryform = function() {
	var cls = 'monoql-form-queryform';
	var Class = Ext.extend(monoql.form.form, {
		defaults:{},
		bodyStyle:{
			'border-top-width':'0px',
			'border-left-width':'0px',
			'border-right-width':'0px'
		},
		initComponent: function() {
			this.addEvents('beforequery', 'query', 'queryresult', 'cancelquery');
			this.querytextarea = new Ext.form.TextArea({
				name:'queries',
				hideLabel:true,
				anchor:'0 0'
			});
			this.queryfield = new Ext.form.Hidden({
				name:'query'
			});
			this.querytextarea.on('render', this.onQueryTextAreaRender, this);
			this.tab.on('activate', this.onQueryTabActivate, this);
			this.items = [this.querytextarea, this.queryfield];
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		},
		onQueryTabActivate:function(tab) {
			this.querytextarea.focus();
		},
		onQueryTextAreaRender:function(textarea) {
			this.keyMap = new Ext.KeyMap(this.el, [{
				key:Ext.EventObject.ENTER,
				ctrl:true,
				handler:this.onQueryFormCtrlEnter,
				stopEvent:true,
				scope:this
			},{
				key:Ext.EventObject.F9,
				ctrl:false,
				handler:this.onQueryFormF9,
				stopEvent:true,
				scope:this
			}]);
		},
		onQueryFormCtrlEnter:function(key, e) {
			this.executeQuery();
		},
		onQueryFormF9:function(key, e) {
			this.executeQuery();
		},
		executeQuery:function() {
			var query = this.querytextarea.getSelectedText() || this.querytextarea.getValue();
			if (this.fireEvent('beforequery', this, query, this.tab.connection) !== false) {
				if (query.trim()) {
					var store = this.tab.resulttabset.resulttab.grid.getStore();
					// Apply params to the baseParams so the livegrid toolbar will pick them up, because
					// it is not remembering params
					store.load({
						baseParams:Ext.apply(store.baseParams, {
							query:query,
							connectionId:this.tab.connection.id,
							database:this.tab.database
						})
					});
					this.fireEvent('query', this, query, this.tab.connection);
					this.tab.resulttabset.resulttab.grid.getStore().on('load', this.onResultGridStoreLoad, this, {single:true});
				}
			}
		},
		onResultGridStoreLoad:function(store, records, options) {
			// A cancelled query just sets the cancelled property of the tab to true
			// since there is no way in Ext to abort a DirectProxy request -- so the
			// response will arrive but get ignored
			if (this.tab.cancelled) {
				this.tab.cancelled = false;
			} else {
				var query = options.params.query,
					connection = ui.connectionstore.getById(options.params.connectionId)
				this.fireEvent('queryresult', this, query, connection, records);
			}
		},
		cancelQuery:function() {
			this.fireEvent('cancelquery', this, this.tab.connection);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.form');
monoql.form.addquerytabform = function() {
	var cls = 'monoql-form-addquerytabform';
	
	var OpenTabButton = Ext.extend(monoql.button.button, {
		text:'Open Tab',
		initComponent:function() {
			OpenTabButton.superclass.initComponent.call(this);
		}
	});
	
	var Class = Ext.extend(monoql.form.floatingform, {
		title:'Add a new query tab',
		width:200,
		hidden:true,
		renderTo:Ext.getBody(),
		initComponent: function() {
			this.opentabbutton = new OpenTabButton({
				disabled:true
			});
			this.connectioncombobox = new monoql.form.connectioncombobox({
				fieldLabel:'Choose a connection'
			});
			this.connectioncombobox.on('select', this.onConnectionComboBoxSelect, this);
			this.items = [this.connectioncombobox];
			this.buttons = [this.opentabbutton];
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		},
		onConnectionComboBoxSelect:function(combo, record, index) {
			var value = combo.getValue(),
				valid = Ext.isNumber(parseInt(value)) && value>0
			this.opentabbutton.setDisabled(!valid);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.form');
monoql.form.connectionform = function() {
	var cls = 'monoql-form-connectionform';
	
	var SaveButton = Ext.extend(monoql.button.button, {
		text:'Save',
		formBind:true,
		initComponent:function() {
			SaveButton.superclass.initComponent.call(this);
			this.addClass(cls + "-savebutton");
		}
	});
	
	var DatabaseTypeComboBox = Ext.extend(monoql.form.combobox, {
		triggerAction:'all',
		displayField:'text',
		valueField:'type',
		forceSelection:true,
		allowBlank:false,
		mode:'local',
		fieldLabel:'Type',
		hiddenName:'type',
		value:'mysql',
		editable:true,
		initComponent:function() {
			this.store = new Ext.data.JsonStore({
				fields:['type', 'text'],
				root:'records',
				data:{"records":[
					{"type":"mysql", "text":"MySQL"},
					{"type":"sqlite", "text":"SQLite"}
				]}
			});
			DatabaseTypeComboBox.superclass.initComponent.call(this);
			this.addClass(cls + "-databasetypecombobox");
		}
	});
	
	var Class = Ext.extend(monoql.form.floatingform, {
		newTitle:'Add a new connection',
		editTitle:'Edit Connection',
		labelAlign:'left',
		width:300,
		monitorValid:true,
		hidden:true,
		renderTo:Ext.getBody(),
		constructor: function(config) {
			var config = Ext.apply({
				api:{
					load:monoql.direct.Connection.getById,
					submit:monoql.direct.Connection.formCreate
				},
				paramOrder:['id']
			}, config || {});
			Class.superclass.constructor.call(this, config);
		},
		initComponent: function() {
			this.savebutton = new SaveButton({
				form:this
			});
			this.databaseTypeComboBox = new DatabaseTypeComboBox(); 
			this.items = [{
				xtype:'hidden',
				name:'id'
			},{
				xtype:'hidden',
				name:'name'
			},this.databaseTypeComboBox,{
				fieldLabel:'Host',
				name:'host',
				allowBlank:false
			},{
				fieldLabel:'Username',
				name:'username',
				allowBlank:false
			},{
				fieldLabel:'Password',
				inputType:'password',
				name:'password'
			},{
				fieldLabel:'Default Database',
				name:'defaultDatabase'
			},{
				fieldLabel:'Port',
				name:'port'
			}];
			this.buttons = [this.savebutton];
			this.savebutton.on('click', this.onSaveButtonClick, this);
			this.on({
				scope:this,
				beforeshow:this.onConnectionFormBeforeShow,
				show:this.onConnectionFormShow,
				hide:this.onConnectionFormHide
			});
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		},
		onConnectionFormBeforeShow:function(form) {
			var title = this.getForm().findField('id').getValue()>0 ? this.editTitle : this.newTitle;
			this.setTitle(title);
		},
		onConnectionFormShow:function(form) {
			this.getForm().findField('host').focus();
		},
		onConnectionFormHide:function(form) {
			this.getForm().reset();
		},
		onSaveButtonClick:function(button, e) {
			this.savebutton.setDisabled(true);
			var conn,
				values = this.getForm().getFieldValues(),
				name = (values.username || 'username') + '@' + (values.host || 'Unknown') + ' [' + (values.type || 'Unknown') + ']',
				id = parseInt(values.id);
			this.getForm().findField('name').setValue(name);
			values = this.getForm().getFieldValues();
			if (id > 0) {
				conn = ui.connectionstore.getById(id);
				this.getForm().updateRecord(conn);
			} else {
				conn = new monoql.data.connectionrecord(values);
				ui.connectionstore.add(conn);
			}
			this.hide();
			this.savebutton.setDisabled(false);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.grid');
monoql.grid.resultgridcolumnmodel = function() {
	var Class = Ext.extend(Ext.grid.ColumnModel, {
		constructor:function(config) {
			Ext.apply(this, {
				defaults:{
					menuDisabled:true
				}
				// The column model will be configured at runtime by listening
				// for the metachange event on the grid store
			}, config);
			Class.superclass.constructor.call(this, config);
			this.grid.store.on('metachange', this.onGridStoreMetaChange, this);
		},
		onGridStoreMetaChange:function(store, meta) {
			var columns = [];
			Ext.each(meta.fields, function(item, index, items) {
				// Add every field except the internal row id
				if (item.name !== "__id__") {
					columns.push({header:item.name, dataIndex:item.name});
				}
			});
			// Only takes an array, not config object... ext bug?
			this.setConfig(columns);
		}
	});
	return Class;
}();Ext.ns('monoql.grid');
monoql.grid.resultgridselectionmodel = function() {
	var Class = Ext.extend(Ext.ux.grid.livegrid.RowSelectionModel, {
		constructor:function(config) {
			config = Ext.apply({
			}, config);
			Class.superclass.constructor.call(this, config);
		}
	});
	return Class;
}();Ext.ns('monoql.grid');
monoql.grid.resultgridview = function() {
	var Class = Ext.extend(Ext.ux.grid.livegrid.GridView, {
		constructor:function(config) {
			config = Ext.apply({
				nearLimit:100,
				loadMask:{
					msg:'Loading rows...'
				}
			}, config);
			Class.superclass.constructor.call(this, config);
		}
	});
	return Class;
}();Ext.ns('monoql.grid');
monoql.grid.grid = function() {
	var cls = 'monoql-grid-grid';
	var Class = Ext.extend(Ext.grid.EditorGridPanel, {
		initComponent: function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.grid');
monoql.grid.livegrid = function() {
	var cls = 'monoql-grid-livegrid';
	var Class = Ext.extend(Ext.ux.grid.livegrid.GridPanel, {
		initComponent: function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.grid');
monoql.grid.tablegridcolumnmodel = Ext.extend(Ext.grid.ColumnModel, {
	constructor:function(config) {
		Ext.apply(this, {
			defaults:{
				sortable:true
			}
		}, config);
		monoql.grid.tablegridcolumnmodel.superclass.constructor.call(this, config);
		this.grid.store.on('metachange', this.onGridStoreMetaChange, this);
	},
	onGridStoreMetaChange:function(store, meta) {
		var columns = [];
		Ext.each(meta.fields, function(item, index, items) {
			if (item.name !== "__id__") {
				columns.push({header:item.name, dataIndex:item.name});
			}
		});
		this.setConfig(columns);
	}
});

monoql.grid.tablegridselectionmodel = Ext.extend(Ext.ux.grid.livegrid.RowSelectionModel, {
	constructor:function(config) {
		config = Ext.apply({
		}, config);
		monoql.grid.tablegridselectionmodel.superclass.constructor.call(this, config);
	}
});

monoql.grid.tablegridview = Ext.extend(Ext.ux.grid.livegrid.GridView, {
	constructor:function(config) {
		config = Ext.apply({
			nearLimit:20,
			loadMask:{
				msg:'Loading rows...'
			}
		}, config);
		monoql.grid.tablegridview.superclass.constructor.call(this, config);
	}
});
	
monoql.grid.tablegrid = function() {
	var cls = 'monoql-grid-tablegrid';
	var Class = Ext.extend(monoql.grid.livegrid, {
		border:false,
		stripeRows:true,
		initComponent: function() {
			this.store = new monoql.data.tablegridstore({grid:this});
			Ext.apply(this, {
				colModel:new monoql.grid.tablegridcolumnmodel({grid:this}),
				selModel:new monoql.grid.tablegridselectionmodel({grid:this}),
				view:new monoql.grid.tablegridview({grid:this})
			});
			Ext.apply(this, {
				bbar:new monoql.bar.tablegridpagingtoolbar({grid:this})
			});
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.grid');
monoql.grid.resultgrid = function() {
	var cls = 'monoql-grid-resultgrid';
	var Class = Ext.extend(monoql.grid.livegrid, {
		border:false,
		stripeRows:true,
		initComponent: function() {
			this.store = new monoql.data.resultgridstore({grid:this});
			Ext.apply(this, {
				colModel:new monoql.grid.resultgridcolumnmodel({grid:this}),
				selModel:new monoql.grid.resultgridselectionmodel({grid:this}),
				view:new monoql.grid.resultgridview({grid:this})
			});
			Ext.apply(this, {
				bbar:new monoql.bar.resultgridpagingtoolbar({grid:this})
			});
			this.on('render', this.onResultGridRender, this);
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		},
		onResultGridRender:function(grid) {
			this.getQueryTab().queryform.on('query', this.onQueryFormQuery, this);
		},
		onQueryFormQuery:function(queryform, query, connection) {
			this.getStore().removeAll();
		},
		getQueryTab:function() {
			return this.findParentByType(monoql.tab.querytab);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.panel');
monoql.panel.viewport = function() {
	var cls = 'monoql-panel-viewport';
	var Class = Ext.extend(Ext.Viewport, {
		layout:'border',
		border:false,
		initComponent: function() {
			this.toolbar = new monoql.bar.maintoolbar({
				region:'north'
			});
			this.tabs = new monoql.tab.maintabset({
				region:'center'
			});
			this.tree = new monoql.tree.connectiontree({
				region:'west',
				split:true
			});
			this.connectionform = new monoql.form.connectionform({
				hidden:true
			});
			this.addquerytabform = new monoql.form.addquerytabform({
				hidden:true
			});
			this.items = [this.toolbar, this.tree, this.tabs];
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.tab');
monoql.tab.tab = function() {
	var cls = 'monoql-tab-tab';
	var Class = Ext.extend(Ext.Panel, {
		initComponent: function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.tab');
monoql.tab.querytab = function() {
	var cls = 'monoql-tab-querytab';
	var Class = Ext.extend(monoql.tab.tab, {
		title:'Query',
		layout:'border',
		border:false,
		closable:true,
		connection:null,
		database:null,
		executing:false,
		cancelled:false,
		constructor:function(config) {
			this.addEvents('connectionchange', 'databasechange');
			Class.superclass.constructor.call(this, config);
		},
		initComponent: function() {
			this.updateTitle();
			this.bbar = new monoql.bar.querytabstatusbar({
				querytab:this
			});
			this.queryform = new monoql.form.queryform({
				region:'north',
				tab:this,
				height:200,
				split:true
			});
			this.resulttabset = new monoql.tab.resulttabset({
				region:'center',
				tab:this,
				split:true,
				border:false,
				bodyStyle:'border-top-width:1px;'
			});
			ui.toolbar.connectioncombobox.on('select', this.onToolBarConnectionComboBoxSelect, this);
			ui.toolbar.databasecombobox.on('select', this.onToolBarDatabaseComboBoxSelect, this);
			ui.toolbar.runquerybutton.on('click', this.onToolBarRunQueryButtonClick, this);
			ui.toolbar.cancelquerybutton.on('click', this.onToolBarCancelQueryButtonClick, this);
			this.queryform.on({
				scope:this,
				beforequery:this.onBeforeQuery,
				query:this.onQuery,
				queryresult:this.onQueryResult,
				cancelquery:this.onCancelQuery
			});
			this.on('connectionchange', this.onConnectionChange, this);
			ui.connectionstore.on('update', this.onConnectionStoreUpdate, this);
			this.items = [this.queryform, this.resulttabset];
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		},
		onBeforeQuery:function(queryform, query, connection) {
		},
		onQuery:function(queryform, query, connection) {
			this.executing = true;
		},
		onQueryResult:function(queryform, query, connection, result) {
			this.executing = false;
		},
		onCancelQuery:function(queryform, connection) {
			this.cancelled = true;
			this.executing = false;
		},
		onConnectionChange:function(tab, oldConn, newConn) {
			this.updateTitle();
			this.setDatabase();
		},
		updateTitle:function() {
			var title = 'Query' + (Ext.isNumber(this.index) ? ' ' + this.index : '');
			title = title + (this.connection ? ' [' + this.connection.get('host') + ']' : '');
			this.setTitle(title);
			return title;
		},
		isActive:function() {
			return this.ownerCt && this.ownerCt.getActiveTab()==this;
		},
		setConnection:function(connection) {
			var old = this.connection;
			this.connection = Ext.isObject(connection) ? connection : ui.connectionstore.getById(connection);
			this.fireEvent('connectionchange', this, old, this.connection);
			return this.connection;
		},
		setDatabase:function(database) {
			var old = this.database;
			this.database = database;
			this.fireEvent('databasechange', this, old, this.database);
			return this.database;
		},
		onToolBarConnectionComboBoxSelect:function(combo, record, index) {
			if (this.isActive()) {
				this.setConnection(combo.getValue());
			}
		},
		onToolBarDatabaseComboBoxSelect:function(combo, record, index) {
			if (this.isActive()) {
				this.setDatabase(combo.getValue());
			}
		},
		onToolBarRunQueryButtonClick:function(button, e) {
			if (this.isActive()) {
				this.queryform.executeQuery();
			}
		},
		onToolBarCancelQueryButtonClick:function(button, e) {
			if (this.isActive()) {
				this.queryform.cancelQuery();
			}
		},
		onConnectionStoreUpdate:function(store, record, index) {
			this.updateTitle();
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.tab');
monoql.tab.hometab = function() {
	var cls = 'monoql-tab-hometab';
	var Class = Ext.extend(Ext.Panel, {
		title:'MonoQL',
		initComponent: function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.tab');
monoql.tab.tabset = function() {
	var cls = 'monoql-tab-tabset';
	var Class = Ext.extend(Ext.TabPanel, {
		resizeTabs:true,
		tabWidth:100,
		initComponent: function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.tab');
monoql.tab.maintabset = function() {
	var cls = 'monoql-tab-maintabset';
	var queryTabCount = 0;
	var Class = Ext.extend(monoql.tab.tabset, {
		headerStyle:'border-top-width:0px;',
		tabWidth:150,
		defaults:{
			closable:true
		},
		initComponent: function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		},
		addQueryTab:function(connection, database) {
			if (connection) {
				var tab = new monoql.tab.querytab({
					index:++queryTabCount
				});
				tab.setConnection(connection);
				tab.setDatabase(database);
				this.activate(this.add(tab));
				return tab;
			}
		},
		addTableTab:function(connection, database, table) {
			if (connection) {
				var tab = new monoql.tab.tabletab({
					connection:connection,
					database:database,
					table:table
				});
				this.activate(this.add(tab));
				return tab;
			}
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.tab');
monoql.tab.tabletab = function() {
	var cls = 'monoql-tab-tabletab';
	var Class = Ext.extend(monoql.tab.tab, {
		layout:'fit',
		border:false,
		initComponent: function() {
			this.title = (this.database || 'Unknown') + '.' + (this.table || 'Unknown');
			this.grid = new monoql.grid.tablegrid({
				tab:this
			});
			this.grid.on('render', this.onTableGridRender, this);
			this.items = [this.grid];
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		},
		onTableGridRender:function(grid) {
			this.grid.getStore().load({
				params:{
					table:this.table,
					connectionId:this.connection.id,
					database:this.database
				}
			});
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.tab');
monoql.tab.resulttab = function() {
	var cls = 'monoql-tab-resulttab';
	var Class = Ext.extend(monoql.tab.tab, {
		title:'Results',
		layout:'fit',
		border:false,
		initComponent: function() {
			this.grid = new monoql.grid.resultgrid({
				tab:this
			});
			this.items = [this.grid];
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.tab');
monoql.tab.messagetab = function() {
	var cls = 'monoql-tab-messagetab';
	var Class = Ext.extend(monoql.tab.tab, {
		title:'Messages',
		layout:'fit',
		border:false,
		initComponent: function() {
			this.getQueryForm().on({
				scope:this,
				query:this.onQueryFormQuery,
				queryresult:this.onQueryFormQueryResult
			});
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		},
		onQueryFormQueryResult:function(form, query, connection, records) {
			var json = this.getResultGrid().getStore().reader.jsonData
			this.update(json.message);
			if (!json.success) {
				this.tabset.activate(this);
			}
		},
		updateMessage:function(message) {
		},
		onQueryFormQuery:function(form, query, connection) {
			if (this.rendered) {
				this.update('');
			}
		},
		getQueryForm:function() {
			return this.getQueryTab().queryform;
		},
		getResultGrid:function() {
			return this.tabset.resulttab.grid;
		},
		getQueryTab:function() {
			return this.tabset.tab;
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.tab');
monoql.tab.resulttabset = function() {
	var cls = 'monoql-tab-resulttabset';
	var Class = Ext.extend(monoql.tab.tabset, {
		activeTab:0,
		border:false,
		deferredRender:false,
		constructor:function(config) {
			Class.superclass.constructor.call(this, config);
		},
		initComponent: function() {
			this.resulttab = new monoql.tab.resulttab({tabset:this});
			this.messagetab = new monoql.tab.messagetab({tabset:this});
			this.tab.queryform.on('query', this.onQueryFormQuery, this);
			this.items = [this.resulttab, this.messagetab];
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		},
		onQueryFormQuery:function(queryform, query, connection) {
			this.activate(this.resulttab);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.tree');
monoql.tree.node = function() {
	var cls = 'monoql-tree-node';
	var Class = Ext.extend(Ext.tree.AsyncTreeNode, {
		constructor: function(attributes) {
			Class.superclass.constructor.call(this, attributes);
			this.attributes.cls = [this.attributes.cls, cls].join(" ");
			if (this.menu && this.menu.refresh) {
				this.menu.refresh.on('click', this.onMenuRefreshClick, this);
			}
			this.on('contextmenu', this.onNodeContextMenu, this);
			this.on('collapse', this.onNodeCollapse, this);
		},
		onMenuRefreshClick:function(item, event) {
			if (Ext.isFunction(this.reload)) {
				this.reload();
			}
		},
		onNodeContextMenu:function(node, event) {
			node.select();
			if (node.menu && node.menu.items) {
				node.menu.showAt(event.getXY());
			}
		},
		getConnection:function() {
			var node = this;
			while (node) {
				if (node.connection) {
					return node.connection;
				} else {
					node = node.parentNode;
				}
			}
			return null;
		},
		getDatabase:function() {
			var node = this;
			while (node) {
				if (node.attributes.database) {
					return node.attributes.database;
				} else {
					node = node.parentNode;
				}
			}
			return null;
		},
		getTable:function() {
			var node = this;
			while (node) {
				if (node.attributes.table) {
					return node.attributes.table;
				} else {
					node = node.parentNode;
				}
			}
			return null;
		},
		onNodeCollapse:function(node) {
			(function() {
				while (this.firstChild) {
					this.removeChild(this.firstChild).destroy();
				}
				this.childrenRendered = false;
				this.loaded = false;
				if (this.isHiddenRoot()) {
					this.expanded = false;
				}
				this.ui.updateExpandIcon();
			}).createDelegate(this).defer(100);
		}
	});
	Ext.tree.TreePanel.nodeTypes[cls] = Class;
	return Class;
}();Ext.ns('monoql.tree');
monoql.tree.groupnode = function() {
	var cls = 'monoql-tree-groupnode';
	var Class = Ext.extend(monoql.tree.node, {
		constructor: function(attributes) {
			Class.superclass.constructor.call(this, attributes);
			this.attributes.cls = [this.attributes.cls, cls].join(" ");
		}
	});
	Ext.tree.TreePanel.nodeTypes[cls] = Class;
	return Class;
}();Ext.ns('monoql.tree');
monoql.tree.backupgroupnode = function() {
	var cls = 'monoql-tree-backupgroupnode';
	var Class = Ext.extend(monoql.tree.groupnode, {
		constructor: function(attributes) {
			this.menu = new monoql.menu.backupgroupnodemenu({
				node:this
			});
			Class.superclass.constructor.call(this, attributes);
			this.attributes.cls = [this.attributes.cls, cls].join(" ");
		}
	});
	Ext.tree.TreePanel.nodeTypes[cls] = Class;
	return Class;
}();Ext.ns('monoql.tree');
monoql.tree.backupnode = function() {
	var cls = 'monoql-tree-backupnode';
	var Class = Ext.extend(monoql.tree.node, {
		constructor: function(attributes) {
			this.menu = new monoql.menu.backupnodemenu({
				node:this
			});
			Class.superclass.constructor.call(this, attributes);
			this.attributes.cls = [this.attributes.cls, cls].join(" ");
		}
	});
	Ext.tree.TreePanel.nodeTypes[cls] = Class;
	return Class;
}();Ext.ns('monoql.tree');
monoql.tree.connectiongroupnode = function() {
	var cls = 'monoql-tree-connectiongroupnode';
	var Class = Ext.extend(monoql.tree.groupnode, {
		constructor: function(attributes) {
			this.menu = new monoql.menu.connectiongroupnodemenu({
				node:this
			});
			Class.superclass.constructor.call(this, attributes);
			this.attributes.cls = [this.attributes.cls, cls].join(" ");
		}
	});
	Ext.tree.TreePanel.nodeTypes[cls] = Class;
	return Class;
}();Ext.ns('monoql.tree');
monoql.tree.connectionnode = function() {
	var cls = 'monoql-tree-connectionnode';
	var Class = Ext.extend(monoql.tree.node, {
		constructor: function(attributes) {
			Ext.apply(attributes, {
				iconCls:cls + '-icon'
			});
			this.menu = new monoql.menu.connectionnodemenu({
				node:this
			});
			this.menu.query.on('click', this.onMenuQueryClick, this);
			this.menu.modify.on('click', this.onMenuModifyClick, this);
			this.menu.remove.on('click', this.onMenuRemoveClick, this);
			Class.superclass.constructor.call(this, attributes);
			this.on('beforeload', this.onConnectionNodeBeforeLoad, this);
			this.attributes.cls = [this.attributes.cls, cls].join(" ");
		},
		onMenuQueryClick:function(item, e) {
			this.menu.hide();
			ui.tabs.addQueryTab(this.connection);
		},
		onMenuModifyClick:function(item, e) {
			this.menu.hide();
			ui.connectionform.getForm().setValues(this.connection.data);
			var pos = Ext.get(this.ui.getEl()).getXY();
			ui.connectionform.setPosition(pos).show();
		},
		onMenuRemoveClick:function(item, e) {
			this.menu.hide();
			ui.connectionstore.remove(this.connection);
		},
		onConnectionNodeBeforeLoad:function(node) {
			// Connection ID is always sent by tree loader for all nodes
		}
	});
	Ext.tree.TreePanel.nodeTypes[cls] = Class;
	return Class;
}();Ext.ns('monoql.tree');
monoql.tree.databasenode = function() {
	var cls = 'monoql-tree-databasenode';
	var Class = Ext.extend(monoql.tree.node, {
		constructor: function(attributes) {
			Ext.apply(attributes, {
				iconCls:cls + '-icon'
			});
			this.menu = new monoql.menu.databasenodemenu({
				node:this
			});
			this.menu.query.on('click', this.onMenuQueryClick, this);
			Class.superclass.constructor.call(this, attributes);
			this.on('beforeload', this.onDatabaseNodeBeforeLoad, this);
			this.attributes.cls = [this.attributes.cls, cls].join(" ");
		},
		onMenuQueryClick:function(item, e) {
			this.menu.hide();
			ui.tabs.addQueryTab(this.getConnection(), this.getDatabase());
		},
		onDatabaseNodeBeforeLoad:function(node) {
			Ext.apply(node.getOwnerTree().getLoader().baseParams, {
				database:node.getDatabase()
			});
		}
	});
	Ext.tree.TreePanel.nodeTypes[cls] = Class;
	return Class;
}();Ext.ns('monoql.tree');
monoql.tree.functiongroupnode = function() {
	var cls = 'monoql-tree-functiongroupnode';
	var Class = Ext.extend(monoql.tree.groupnode, {
		constructor: function(attributes) {
			this.menu = new monoql.menu.functiongroupnodemenu({
				node:this
			});
			Class.superclass.constructor.call(this, attributes);
			this.on('beforeload', this.onFunctionGroupNodeBeforeLoad, this);
			this.attributes.cls = [this.attributes.cls, cls].join(" ");
		},
		onFunctionGroupNodeBeforeLoad:function(node) {
			Ext.apply(node.getOwnerTree().getLoader().baseParams, {
				database:node.getDatabase()
			});
		}
	});
	Ext.tree.TreePanel.nodeTypes[cls] = Class;
	return Class;
}();Ext.ns('monoql.tree');
monoql.tree.functionnode = function() {
	var cls = 'monoql-tree-functionnode';
	var Class = Ext.extend(monoql.tree.node, {
		constructor: function(attributes) {
			Ext.apply(attributes, {
				iconCls:cls + '-icon'
			});
			this.menu = new monoql.menu.functionnodemenu({
				node:this
			});
			Class.superclass.constructor.call(this, attributes);
			this.attributes.cls = [this.attributes.cls, cls].join(" ");
		}
	});
	Ext.tree.TreePanel.nodeTypes[cls] = Class;
	return Class;
}();Ext.ns('monoql.tree');
monoql.tree.scriptgroupnode = function() {
	var cls = 'monoql-tree-scriptgroupnode';
	var Class = Ext.extend(monoql.tree.groupnode, {
		constructor: function(attributes) {
			this.menu = new monoql.menu.scriptgroupnodemenu({
				node:this
			});
			Class.superclass.constructor.call(this, attributes);
			this.attributes.cls = [this.attributes.cls, cls].join(" ");
		}
	});
	Ext.tree.TreePanel.nodeTypes[cls] = Class;
	return Class;
}();Ext.ns('monoql.tree');
monoql.tree.scriptnode = function() {
	var cls = 'monoql-tree-scriptnode';
	var Class = Ext.extend(monoql.tree.node, {
		constructor: function(attributes) {
			this.menu = new monoql.menu.scriptnodemenu({
				node:this
			});
			Class.superclass.constructor.call(this, attributes);
			this.attributes.cls = [this.attributes.cls, cls].join(" ");
		}
	});
	Ext.tree.TreePanel.nodeTypes[cls] = Class;
	return Class;
}();Ext.ns('monoql.tree');
monoql.tree.sprocgroupnode = function() {
	var cls = 'monoql-tree-sprocgroupnode';
	var Class = Ext.extend(monoql.tree.groupnode, {
		constructor: function(attributes) {
			this.menu = new monoql.menu.sprocgroupnodemenu({
				node:this
			});
			Class.superclass.constructor.call(this, attributes);
			this.on('beforeload', this.onSprocGroupNodeBeforeLoad, this);
			this.attributes.cls = [this.attributes.cls, cls].join(" ");
		},
		onSprocGroupNodeBeforeLoad:function(node) {
			Ext.apply(node.getOwnerTree().getLoader().baseParams, {
				database:node.getDatabase()
			});
		}
	});
	Ext.tree.TreePanel.nodeTypes[cls] = Class;
	return Class;
}();Ext.ns('monoql.tree');
monoql.tree.sprocnode = function() {
	var cls = 'monoql-tree-sprocnode';
	var Class = Ext.extend(monoql.tree.node, {
		constructor: function(attributes) {
			Ext.apply(attributes, {
				iconCls:cls + '-icon'
			});
			this.menu = new monoql.menu.sprocnodemenu({
				node:this
			});
			Class.superclass.constructor.call(this, attributes);
			this.attributes.cls = [this.attributes.cls, cls].join(" ");
		}
	});
	Ext.tree.TreePanel.nodeTypes[cls] = Class;
	return Class;
}();Ext.ns('monoql.tree');
monoql.tree.tablegroupnode = function() {
	var cls = 'monoql-tree-tablegroupnode';
	var Class = Ext.extend(monoql.tree.groupnode, {
		constructor: function(attributes) {
			this.menu = new monoql.menu.tablegroupnodemenu({
				node:this
			});
			this.menu.query.on('click', this.onMenuQueryClick, this);
			Class.superclass.constructor.call(this, attributes);
			this.on('beforeload', this.onTableGroupNodeBeforeLoad, this);
			this.attributes.cls = [this.attributes.cls, cls].join(" ");
		},
		onMenuQueryClick:function(item, e) {
			this.menu.hide();
			ui.tabs.addQueryTab(this.getConnection(), this.getDatabase());
		},
		onTableGroupNodeBeforeLoad:function(node) {
			Ext.apply(node.getOwnerTree().getLoader().baseParams, {
				database:node.getDatabase()
			});
		}
	});
	Ext.tree.TreePanel.nodeTypes[cls] = Class;
	return Class;
}();Ext.ns('monoql.tree');
monoql.tree.tablenode = function() {
	var cls = 'monoql-tree-tablenode';
	var Class = Ext.extend(monoql.tree.node, {
		constructor: function(attributes) {
			Ext.apply(attributes, {
				iconCls:cls + '-icon'
			});
			this.menu = new monoql.menu.tablenodemenu({
				node:this
			});
			this.menu.open.on('click', this.onMenuOpenClick, this);
			this.menu.query.on('click', this.onMenuQueryClick, this);
			Class.superclass.constructor.call(this, attributes);
			this.on('beforeload', this.onTableNodeBeforeLoad, this);
			this.attributes.cls = [this.attributes.cls, cls].join(" ");
		},
		onMenuQueryClick:function(item, e) {
			this.menu.hide();
			ui.tabs.addQueryTab(this.getConnection(), this.getDatabase());
		},
		onTableNodeBeforeLoad:function(node) {
			Ext.apply(node.getOwnerTree().getLoader().baseParams, {
				table:node.getTable(),
				database:node.getDatabase()
			});
		},
		onMenuOpenClick:function(item, e) {
			this.menu.hide();
			ui.tabs.addTableTab(this.getConnection(), this.getDatabase(), this.getTable());
		}
	});
	Ext.tree.TreePanel.nodeTypes[cls] = Class;
	return Class;
}();Ext.ns('monoql.tree');
monoql.tree.columnnode = function() {
	var cls = 'monoql-tree-columnnode';
	var Class = Ext.extend(monoql.tree.node, {
		constructor: function(attributes) {
			Ext.apply(attributes, {
				iconCls:cls + '-icon'
			});
			this.menu = new monoql.menu.columnnodemenu({
				node:this
			});
			Class.superclass.constructor.call(this, attributes);
			this.attributes.cls = [this.attributes.cls, cls].join(" ");
		}
	});
	Ext.tree.TreePanel.nodeTypes[cls] = Class;
	return Class;
}();Ext.ns('monoql.tree');
monoql.tree.triggergroupnode = function() {
	var cls = 'monoql-tree-triggergroupnode';
	var Class = Ext.extend(monoql.tree.groupnode, {
		constructor:function(attributes) {
			this.menu = new monoql.menu.triggergroupnodemenu({
				node:this
			});
			Class.superclass.constructor.call(this, attributes);
			this.on('beforeload', this.onTriggerGroupNodeBeforeLoad, this);
			this.attributes.cls = [this.attributes.cls, cls].join(" ");
		},
		onTriggerGroupNodeBeforeLoad:function(node) {
			Ext.apply(node.getOwnerTree().getLoader().baseParams, {
				database:node.getDatabase()
			});
		}
	});
	Ext.tree.TreePanel.nodeTypes[cls] = Class;
	return Class;
}();Ext.ns('monoql.tree');
monoql.tree.triggernode = function() {
	var cls = 'monoql-tree-triggernode';
	var Class = Ext.extend(monoql.tree.node, {
		constructor: function(attributes) {
			Ext.apply(attributes, {
				iconCls:cls + '-icon'
			});
			this.menu = new monoql.menu.triggernodemenu({
				node:this
			});
			Class.superclass.constructor.call(this, attributes);
			this.attributes.cls = [this.attributes.cls, cls].join(" ");
		}
	});
	Ext.tree.TreePanel.nodeTypes[cls] = Class;
	return Class;
}();Ext.ns('monoql.tree');
monoql.tree.usergroupnode = function() {
	var cls = 'monoql-tree-usergroupnode';
	var Class = Ext.extend(monoql.tree.groupnode, {
		constructor: function(attributes) {
			this.menu = new monoql.menu.usergroupnodemenu({
				node:this
			});
			Class.superclass.constructor.call(this, attributes);
			this.attributes.cls = [this.attributes.cls, cls].join(" ");
		}
	});
	Ext.tree.TreePanel.nodeTypes[cls] = Class;
	return Class;
}();Ext.ns('monoql.tree');
monoql.tree.usernode = function() {
	var cls = 'monoql-tree-usernode';
	var Class = Ext.extend(monoql.tree.node, {
		constructor: function(attributes) {
			this.menu = new monoql.menu.usernodemenu({
				node:this
			});
			Class.superclass.constructor.call(this, attributes);
			this.attributes.cls = [this.attributes.cls, cls].join(" ");
		}
	});
	Ext.tree.TreePanel.nodeTypes[cls] = Class;
	return Class;
}();Ext.ns('monoql.tree');
monoql.tree.viewgroupnode = function() {
	var cls = 'monoql-tree-viewgroupnode';
	var Class = Ext.extend(monoql.tree.groupnode, {
		constructor: function(attributes) {
			this.menu = new monoql.menu.viewgroupnodemenu({
				node:this
			});
			Class.superclass.constructor.call(this, attributes);
			this.on('beforeload', this.onViewGroupNodeBeforeLoad, this);
			this.attributes.cls = [this.attributes.cls, cls].join(" ");
		},
		onViewGroupNodeBeforeLoad:function(node) {
			Ext.apply(node.getOwnerTree().getLoader().baseParams, {
				database:node.getDatabase()
			});
		}
	});
	Ext.tree.TreePanel.nodeTypes[cls] = Class;
	return Class;
}();Ext.ns('monoql.tree');
monoql.tree.viewnode = function() {
	var cls = 'monoql-tree-viewnode';
	var Class = Ext.extend(monoql.tree.node, {
		constructor: function(attributes) {
			Ext.apply(attributes, {
				iconCls:cls + '-icon'
			});
			this.menu = new monoql.menu.viewnodemenu({
				node:this
			});
			this.menu.open.on('click', this.onMenuOpenClick, this);
			Class.superclass.constructor.call(this, attributes);
			this.attributes.cls = [this.attributes.cls, cls].join(" ");
		},
		onMenuOpenClick:function(item, e) {
			this.menu.hide();
			// TODO: This should be a viewtab, not a tabletab
			ui.tabs.addTableTab(this.getConnection(), this.getDatabase(), this.getTable());
		}
	});
	Ext.tree.TreePanel.nodeTypes[cls] = Class;
	return Class;
}();Ext.ns('monoql.tree');
monoql.tree.tree = function() {
	var cls = 'monoql-tree-tree';
	var Class = Ext.extend(Ext.tree.TreePanel, {
		initComponent: function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.tree');
monoql.tree.connectiontreeloader = function() {
	var Class = Ext.extend(Ext.tree.TreeLoader, {
		constructor:function(config){
			config = Ext.apply({
				directFn:monoql.direct.ConnectionTree.getChildNodes,
				paramsAsHash:true
			}, config || {});
			Class.superclass.constructor.call(this, config);
			this.addListener('beforeload', this.onLoaderBeforeLoad, this);
		},
		onLoaderBeforeLoad:function(loader, node, callback) {
			var conn = node.getConnection();
			Ext.apply(loader.baseParams, {
				nodeType:node.attributes.nodeType,
				text:node.text,
				connectionId:conn && conn.id
			});
		}
	});
	return Class;
}();Ext.ns('monoql.tree');
monoql.tree.connectiontree = function() {
	var cls = 'monoql-tree-connectiontree';
	var Class = Ext.extend(monoql.tree.tree, {
		width:250,
		headerStyle:'border-top-width:0px;border-left-width:0px;',
		bodyStyle:'border-left-width:0px;',
		animate:false,
		autoScroll:true,
		root:{
			nodeType:'monoql-tree-connectiongroupnode',
			id:'root-connectiongroup',
			text:'Connections',
			expanded:false
		},
		rootVisible:false,
		useArrows:true,
		animCollapse:false,
		constructor:function(config) {
			var config = Ext.apply({
				collapseMode:'mini'
			}, config);
			Class.superclass.constructor.call(this, config);
		},
		initComponent: function() {
			this.store = ui.connectionstore;
			this.tbar = new monoql.bar.connectiontreetoolbar();
			this.loader = new monoql.tree.connectiontreeloader();
			this.tbar.refreshbutton.on('click', this.onToolbarRefreshButtonClick, this);
			this.store.on({
				scope:this,
				add:this.onStoreAdd,
				remove:this.onStoreRemove,
				update:this.onStoreUpdate
			});
			Class.superclass.initComponent.call(this);
			this.root.on('load', this.onConnectionTreeRootNodeLoad, this);
			this.getSelectionModel().on('selectionchange', this.getTopToolbar().refreshbutton.onConnectionTreeSelectionChange, this.getTopToolbar().refreshbutton);
			this.addClass(cls);
		},
		getNodeByConnection:function(connection) {
			var node;
			Ext.each(this.root.childNodes, function(item, i, items) {
				if (item.connection.id===connection.id) {
					node = item;
					return false;
				}
			});
			return node;
		},
		onConnectionTreeRootNodeLoad:function(node) {
			Ext.each(node.childNodes, function(item, i, items) {
				item.connection = ui.connectionstore.getById(item.attributes.connectionId);
			});
		},
		onToolbarRefreshButtonClick:function(button, event) {
			var selectedNode = this.getSelectionModel().getSelectedNode();
			if (selectedNode && selectedNode.reload) {
				selectedNode.reload();
			}
		},
		addConnectionNodeFromStore:function(parentNode, record) {
			var node = this.getLoader().createNode({
					text:record.data.name,
					nodeType:'monoql-tree-connectionnode'
				});
			node.connection = record;
			parentNode.appendChild(node);
		},
		onStoreAdd:function(store, records, index) {
			Ext.each(records, function(item, index, items) {
				this.addConnectionNodeFromStore(this.root, item);
			}, this);
		},
		onStoreRemove:function(store, record, index) {
			this.getNodeByConnection(record).remove(true);
		},
		onStoreUpdate:function(store, record, operation) {
			var node = this.getNodeByConnection(record);
			if (node) {
				node.setText(record.get('name'));
			}
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql.window');
monoql.window.window = function() {
	var cls = 'monoql-window-window';
	var Class = Ext.extend(Ext.Window, {
		initComponent: function() {
			Class.superclass.initComponent.call(this);
			this.addClass(cls);
		}
	});
	Ext.reg(cls, Class);
	return Class;
}();Ext.ns('monoql', 'ui');
Ext.QuickTips.init();
Ext.onReady(function(){
	Ext.apply(monoql, {
		webroot:'/monoql',
		url:function(path) {
			return (this.webroot + path).replace(/\/{2,}/i, '/');
		}
	});
	Ext.BLANK_IMAGE_URL = 'ext/resources/images/default/s.gif';
	ui.connectionstore = new monoql.data.connectionstore();
	ui.connectionstore.load();
	Ext.apply(ui, new monoql.panel.viewport({
		id:'viewport'
	}));
	ui.toolbar.initListeners();
});
