

function SelectPanel(rdbAdmin,databaseManager,sqlPanel)
/* object to handle creation and renaming of views */
{
	this.rdbAdmin = rdbAdmin;
	this.dbMgr = databaseManager;
	this.sqlPanel = sqlPanel;
	this.tableId = 'select-panel-result-table';
	this.pagerId = 'sel-table_pager';
	this.tableName = '';
	this.data = null;
	this.totalRowsCount = 0;
	this.limit = 30;
	this.page = 1;
	this.fieldDetails = '';	
	
	this.init_handlers = function()
	{
		var $this = this;
		// bind handlers to create button, and to form submit buttons
		var $form = $('#'+this.tableId);
		// create 'live' binding on view and table lists
		$('#table-list .browse').live('click',function() {
			return $this.liveBrowse(this);
		});
		$('#view-list .browse').live('click',function() {
			return $this.liveBrowse(this);
		});
		// add click handlers
		$('#sel-table-select-btn').bind('click',function() {
			$this.select();
			return false;
		});
		$('#sel-panel-delete-selected').bind('click',function() {
			$this.deleteSelected();
			return false;
		});
		// select/deselect all
		$('#sel-table_selitem').live('click',function() {
			if ($(this).attr('checked')) {
				$('input[id^="sel-table_selitem_"]').attr('checked','checked');
			}
			else {
				$('input[id^="sel-table_selitem_"]').attr('checked','');
			}
		});
		// hover and click handlers
		$('#'+$this.pagerId+' span[id^="pager-"]').live('click', function() {
			var pg=$(this).attr('id').substr(6,15);
			$this.page = parseInt(pg,10);
			$this.buildTable();
		});
	};

	this.liveBrowse = function(el)
	{
		var $tabname = $(el).find('a').attr('href');
		this.show($tabname);
		return false;
	};

	this.quotedTableName = function(name)
	{
		return quoteIdentifier(this.tableName);
	};
	
	this.show = function(tableName)
	{
		var $this = this;
		this.rdbAdmin.resetMessages(); 
		this.rdbAdmin.showPanel("select-panel");
		this.rdbAdmin.setHeading("Select: " + tableName);
		$('.tablehide').show();
		this.tableName = tableName;
		this.page = 1;
		
		// init some interface controls
		$('#sel-panel-limit').val('30');
		$('#sel-panel-functions').val('');
		// empty fields list in selects
		$('div[id^="sel-panel-select-div-"]').next().remove();
		$('div[id^="sel-panel-fwhere-div-"]').next().remove();
		$('div[id^="sel-panel-fsort-div-"]').next().remove();
		
		$('#sel-table-fields').empty().append('<option></option>');
		$('#sel-table-fsort').empty().append('<option></option>');
		$('#sel-table-fwhere').empty().append('<option></option>');
		
		// get fields type and other meta-info
		function callback(dtls) {
			$this.fieldDetails = dtls.fields;
			$this.select();
		}
		var schemaNTable = splitTableName(this.tableName);
		this.dbMgr.getTableDetails(schemaNTable[0],schemaNTable[1],callback,errback);
		return true;
	};
	
	this.select = function()
	{
		this.rdbAdmin.resetMessages(); 
		this.page = 1;
		return this.buildTable();
	};
	
	this.fillSelectControls = function()
	{
		var i;
		if (this.data && this.data.header) {
			if ($('#sel-table-fields').children().length <= 1) {
				for (i in this.data.header) {
					if (this.data.header.hasOwnProperty(i)) {
						$('#sel-table-fields').append('<option>'+this.data.header[i][1]+'</option>');
					}
				}
			}
			if ($('#sel-table-fsort').children().length <= 1) {
				for (i in this.data.header) {
					if (this.data.header.hasOwnProperty(i)) {
						$('#sel-table-fsort').append('<option>'+this.data.header[i][1]+'</option>');
					}
				}
			}
			if ($('#sel-table-fwhere').children().length <= 1) {
				for (i in this.data.header) {
					if (this.data.header.hasOwnProperty(i)) {
						$('#sel-table-fwhere').append('<option>'+this.data.header[i][1]+'</option>');
					}
				}
			}
		}
	};

	this.add_row = function(field)
	{
		// check if this row is the last - if isn't - return false
		if( $(field).parent().next().length !== 0) {
			return false;
		}
		var row = $(field).parent().clone();
		// change row id
		var re = /(\d+)/;
		var rid = $(row).attr('id');
		var id = re.exec(rid);
		if (id !== null) {
			id = parseInt(id[1],10) + 1;
		}
		else {
			id = 0;
		}
		rid = rid.replace(/\d+/, id);
		$(row).attr('id', rid);
		
		// clean selects in cloned row
		var selects = $(row).find('select');
		for (var i=0; i < selects.length; i+=1) {
			selects[i].name = selects[i].name.replace(/[a-z]\[[0-9]+/, '$&1');
			selects[i].selectedIndex = 0;
		}
		var inputs = $(row).find('input');
		if (inputs.length) {
			inputs[0].name = inputs[0].name.replace(/[a-z]\[[0-9]+/, '$&1');
			inputs[0].value = '';
		}
		$(field).parent().parent().append(row);
		return true;
	};

	this.unknownOnClick = function()
	{
		var elems = this.form.elements;
		for (var i=0; i < elems.length; i+=1) {
			if (elems[i].name === 'delete[]') {
				elems[i].checked = this.checked;
			}
		}
	};
	
	this.sortByColumn = function(col)
	{
		col = $(col).html();
		// set up sorting inputs
		if ($('div[id^="sel-panel-fsort-div-"] select[value="'+col+'"]').length === 0) {
			// add row with this col name
			this.add_row($('div[id^="sel-panel-fsort-div-"]:last').find('select').get(0));
			// set col name
			$($('div[id^="sel-panel-fsort-div-"]:last').find('select').get(0)).val(col);
		}
		var select = $($('div[id^="sel-panel-fsort-div-"] select[value="'+col+'"]').get(0));
		var checkbox = $(select.parent().find('input[type="checkbox"]').get(0));
		if (checkbox.attr('checked')) {
			checkbox.attr('checked', false);
		}
		else {
			checkbox.attr('checked', true);
		}
		this.select();
	};
	
	this.buildTable = function()
	{
		var $this = this;
		var table = $('#'+this.tableId);
		// build query
		var qp = this.buildQuery(false);
		var query = qp[0], args = qp[1], isFullRecord = qp[2];
		$('#sel-panel_jush-sql').html('<code>'+query+'</code>');
		// add click handler to edit query
		$('#sel-panel-sql-edit').click(function() {
			$this.sqlPanel.showQuery(query);
		});
		// querying
		function successcb(json) {
			// alert('successcb: '+json.records.rows.length);
			$this.rdbAdmin.showWorkingMessage(json.row_count[1]);
			$this.data = json.records;
			if ($this.data && $this.data.header) {
				// add select option
				$this.fillSelectControls();
				// create header of html table
				if ( isFullRecord || $this.data.header.length === 0 ) {
					$('#select-panel-new-item').show();
					$('#sel-table-delete-btn').show();
					$('<tr id="sel-table_th"><td>'+
					  '<input type="checkbox" id="sel-table_selitem" />all'+
					  '</td></tr>').appendTo(table);
				}
				else {
					$('#select-panel-new-item').hide();
					$('#sel-table-delete-btn').hide();
					$('<tr id="sel-table_th"><td>&nbsp;</td></tr>').appendTo(table);
				}
				for (var i in $this.data.header) {
					if ($this.data.header.hasOwnProperty(i)) {
						// add html table header
						$('#sel-table_th').append('<th><span class="btn" '+
								'onclick="selectPanel.sortByColumn(this)">'+
								$this.data.header[i][1]+'</span></th>');
					}
				}
				// render data
				for (i in $this.data.rows) {
					if ($this.data.rows.hasOwnProperty(i)) {
						var row = $this.data.rows[i];
						if ( isFullRecord ) {
							$('<tr id="sel-table_tr_'+i+'"><td>'+
							  '<input type="checkbox" id="sel-table_selitem_'+i+
							  '" /><span class="btn" id="sel-table_tr_edit_'+i+
							  '">edit</span></td></tr>').appendTo(table);
						}
						else {
							$('<tr id="sel-table_tr_'+i+
							  '"><td> </td></tr>').appendTo(table);					
						}
						var tabRow, cell;
						for (var j in row) {
							if (row.hasOwnProperty(j)) {
								tabRow = $('#sel-table_tr_'+i).get(0);
								cell = document.createElement("td");
								cell.appendChild(document.createTextNode(row[j]));
								tabRow.appendChild(cell);
							}
						}
					}
				}
			}
		}
		// empty the table
		table.empty();
		// send query to server
		this.dbMgr.sqlEngine.query( { 'q' : query,
									  'args' : args,
									  'callback' : successcb,
									  'errback' : errback });
		// build pager
		this.buildPager();
	};
	
	this.deleteSelected = function()
	{
		var $this = this;
		var query = [], arglist = [], dTypes = [];
		// find selected rows
		$('input[id^="sel-table_selitem_"]:checked').each(function() {
			// get selected items from this.data.rows
			var rowIndex = parseInt($(this).parents().get(1).rowIndex,10) - 1;
			var row = $this.data.rows[rowIndex];
			var head = $this.data.header;
			var q = [];
			for (var i in row) {
				if (row.hasOwnProperty(i)) {
					if (row[i] === null) {
						q.push(quoteIdentifier(head[i][1]) + " IS NULL");
					}
					else {
						q.push(quoteIdentifier(head[i][1])+'=%s');
						arglist.push(row[i]);
						dTypes.push($this.fieldDetails[i].dataType);
					}
				}
			}
			query.push("DELETE FROM " + $this.quotedTableName() +
					   " WHERE " + q.join(' AND ') + ";");
		});
		query = query.join("\n");
		function successcb(json) {
			this.buildTable(); // refresh page
		} 
		// send query to server
		this.dbMgr.sqlEngine.query(	{ 'q' : query,
								      'args' : arglist,
									  'argtypes' : dTypes,
									  'callback' : successcb,
									  'errback' : errback });
	};
	
	this.buildPager = function()
	{
		var $this = this;
		// fetch total rows count
		var qres = this.buildQuery(true); // records count
		var query = qres[0], args = qres[1];
		// build is called for both success and failure
		function build() {
			var btn, i;
			$('#'+$this.pagerId).empty();
			$('#sel-table_total-rows_count').empty().append(parseInt($this.totalRowsCount,10));
			// if our item count or per-page total is zero there is no need to continue
			if ($this.totalRowsCount === 0) {
				$this.totalRowsCount = 1;
			}
			// calculate page count
			var page_count = Math.ceil( parseFloat(parseInt($this.totalRowsCount,10) / parseInt($this.limit,10)) );
			// current page - $this.page
			// Calculate the start and end numbers. These determine
			// which number to start and end the digit links with
			var num_links = 2; // Number of "digit" links to show before/after the currently viewed page
			var start = (($this.page - num_links) > 0) ? $this.page - (num_links - 1) : 1;
			var end = ((parseInt($this.page,10) + parseInt(num_links,10)) < parseInt(page_count,10)) ?
			            parseInt($this.page,10) + parseInt(num_links,10) : page_count;
			// Render the "First" link
			if  ($this.page > (num_links + 1)) {
				btn = '<span class="txtbtn" id="pager-~p~" >&lsaquo; First</span>';
				btn = btn.replace('~p~',1);
				$('#'+$this.pagerId).append(btn);
			}
			// Render the "previous" link
			if  ($this.page !== 1) {
				i = $this.page - $this.limit;
				if (i === 0) {
					i = '';
				}
				btn = '<span class="txtbtn" id="pager-~p~">&lt;</span>';
				btn = btn.replace('~p~',parseInt($this.page,10)-1);
				$('#'+$this.pagerId).append(btn);
			}
			// Write the digit links
			for (var loop = start-1; loop <= end; loop+=1) {
				i = (loop * $this.limit) - $this.limit;
				if (i >= 0) {
					if ($this.page === loop) {
						btn = '<b><span id="pager-~p~">~p~</span></b>';
						btn = btn.replace(/~p~/g,loop);
						$('#'+$this.pagerId).append(btn); // Current page
					} else {
						var n = (i === 0) ? '' : i;
						btn = '<span class="txtbtn" id="pager-~p~">~p~</span>';
						btn = btn.replace(/~p~/g,loop);
						$('#'+$this.pagerId).append(btn);
					}
				}
			}
			// Render the "next" link
			if ($this.page < page_count) {
				btn = '<span class="txtbtn" id="pager-~p~">&gt;</span>';
				btn = btn.replace('~p~',parseInt($this.page,10)+1);
				$('#'+$this.pagerId).append(btn);
			}
			// Render the "Last" link
			if ((parseInt($this.page,10) + parseInt(num_links,10)) < parseInt(page_count,10)) {
				btn = '<span class="txtbtn" id="pager-~p~">Last &rsaquo;</span>';
				btn = btn.replace('~p~',parseInt(page_count,10));
				$('#'+$this.pagerId).append(btn);
			}
		}			
		function successcb(json) {
			$this.totalRowsCount = json.records.rows[0];
			build();
		}
		function errorcb(json) {
			$this.totalRowsCount = 0; // $this.data.rows.length;
			build();
		}
		// send query to server
		this.dbMgr.sqlEngine.query(	{ 'q' : query,
								      'args' : args,
									  'callback' : successcb,
									  'errback' : errorcb });
	};
	
	this.buildQuery = function(isCount)
	{
		var query = '';
		var limit = '';
		var limitArgs = [];
		this.limit = $('#sel-panel-limit').val();
		
		// if we have limit
		if (this.limit !== '') {
			var offsetlim = [(this.page-1)*this.limit, this.limit];
			limit = ' OFFSET '+offsetlim[0]+' LIMIT '+offsetlim[1];
		}
		else {
			limit = '';
		}

		// build what-to-select statement
		var what = [], i, whatArgs = [], isFullRecord = true,
		    field, func;
		var sels = $('div[id^="sel-panel-select-div-"]');
		for (i=0;i<sels.length;i+=1) {
			func = $($(sels[i]).find('select')[0]).val();
			field = $($(sels[i]).find('select')[1]).val();
			if ( field !== '' ) {
				isFullRecord = false;
			}
			if ((func !== '') && (field !== '')) {
				if (func === 'unix_timestamp') {
					what.push('extract(epoch FROM '+field+')');
					//whatArgs.push(field);
				}
				else {
					what.push(func+'('+field+')');
					//whatArgs.push(field);
				}
			}
			else if (field !== '') {
				what.push(field);
				//whatArgs.push(field);
			}
		}
		if (what.length === 0) {
			what = '*';
		}
		else {
			what = what.join(', ');
		}
		
		// 'searching' - where statement
		var where = [], whereArgs = [], val;
		sels = $('div[id^="sel-panel-fwhere-div-"]');
		for (i=0;i<sels.length;i+=1) {
			field = $($(sels[i]).find('select')[0]).val();
			var statement = $($(sels[i]).find('select')[1]).val();
			val = $($(sels[i]).find('input')).val();
			
			if (field !== '') {
				// should we quote a value?
				var ftype = this.getFieldTypeByName(field);
				switch (ftype) {
					case 'int':
					case 'bigint':
					case 'integer':
					case 'number':
					case 'serial':
					case 'bigserial':
					case 'float':
					case 'double':
					case 'decimal':
					case 'numeric':
					case 'smallint':
					case 'real':
					case 'serial':
					case 'boolean':
						where.push(quoteIdentifier(field)+' '+statement+' %s');
						val = val.replace(/%/g,'%%');
						whereArgs.push(val);
						break;
					default:
						//where.push(field+' '+statement+' \'%s\'');
						where.push(quoteIdentifier(field)+' '+statement+' %s');
						val = val.replace(/%/g,'%%');
						whereArgs.push(val);
						break;
				}
			}
		}
		if (where.length === 0) {
			where = '';
		}
		else {
			where = " WHERE " + where.join(' AND ')+" ";
		}
		
		// ordering and sorting
		var orderby = [];
		sels = $('div[id^="sel-panel-fsort-div-"]');
		for (i=0;i<sels.length;i+=1) {
			field = $($(sels[i]).find('select')[0]).val();
			val = $($(sels[i]).find('input')).attr('checked') ? 'DESC' : 'ASC';
			if (field !== '') {
				orderby.push(quoteIdentifier(field)+' '+val);
			}
		}
		if (orderby.length === 0) {
			orderby = '';
		}
		else {
			orderby = " ORDER BY " + orderby.join(', ') + " ";
		}
		var args;
		if (isCount) {
			query = "SELECT COUNT(*) FROM " + this.quotedTableName() + where;
			args = whereArgs;
		} else {
			query = "SELECT "+what+" FROM " + this.quotedTableName() +
					where + orderby + limit;
			args = whatArgs.concat(whereArgs,limitArgs);
		}
		return [query, args, isFullRecord]; 
	};
	
	this.getFieldTypeByName = function(name)
	{
		for (var i in this.fieldDetails) {
			if (this.fieldDetails.hasOwnProperty(i)) {
				if (this.fieldDetails[i].columnName === name) {
					return this.fieldDetails[i].dataType;
				}
			}
		}
		return false;
	};
	
	this.truncate = function()
	{
		// **** reform truncate
		var $this = this;
		if (!confirm('Are you sure?')) {
			return;
		}
		function callback(json) {
			$this.rdbAdmin.showWorkingMessage(json.status[1]);
			$this.show(this.tableName);
		}
		this.dbMgr.truncate(this.tableName,callback,errback);
	};
	
}