/*
	Author: 	Daniel Budde
	Created:	June 22, 2009
	Purpose:	Javascript representation of a query object.
*/

function Query(columns, colTypes)
{
	var QueryObj = this;
	var query = new Array();
	var columnCount = 0;
	var columnList = "";
	var columnMap = new Object();
	var columnTypes = new Array("boolean","date","function","number","object","string");




	this.AddColumn = function(columnName, columnType)
	{
		var col = Trim(String(columnName).toLowerCase());

		// If the column does no exist, add it
		if (!QueryObj.ColumnExists(col))
		{
			columnMap[col] = new Object();
			columnMap.type = "object";
			columnCount++;


			if (typeof(columnType) != "undefined" && IsValidColumnType(columnType))
			{
				columnMap.type = columnType.toLowerCase();
			}


			if (columnList.length > 0)
			{
				columnList += ",";	
			}

			columnList += col;

			for (var i = 0; i < query.length; i++)
			{
				query[i][col] = null;	
			}
		}
	}


	this.AddRow = function(rowValues)
	{
		var columns = columnList.split(",");


		if (typeof(rowValues) != "undefined")
		{
			if (TypeOf(rowValues) == "array" && rowValues.length == columnCount)
			{
				query.push(new Object());

				for (var i = 0; i < columns.length; i++)
				{
					query[query.length - 1][columns[i]] = rowValues[i];
				}
			}
			else
			{
				return false;
			}
		}
		else
		{
			query.push(new Object());

			for (var i = 0; i < columns.length; i++)
			{
				query[query.length - 1][columns[i]] = null;
			}
		}

		return true;
	}


	this.ColumnExists = function(columnName)
	{
		if (typeof(columnMap[String(columnName).toLowerCase()]) == "object")
		{
			return true;
		}
		
		return false;
	}


	this.GetColumns = function()
	{
		return columnList;	
	}


	this.GetRow = function(rowNumber)
	{
		var row = null;

		if (query.length > 0 && rowNumber >= 0 && rowNumber <= query.length - 1)
		{
			row = query[rowNumber];	
		}

		return row;
	}


	this.LoadJSONQuery = function(JSONQuery)
	{
		var colMap = new Object();
		var columnName = "";

		for (var i = 0; i < JSONQuery.COLUMNS.length; i++)
		{
			columnName = String(JSONQuery.COLUMNS[i]).toLowerCase();
			colMap[columnName] = i;
			QueryObj.AddColumn(columnName);
		}


		var columns = columnList.split(",");


		for (var i = 0; i < JSONQuery.DATA.length; i++)
		{
			QueryObj.AddRow();

			for (var j = 0; j < columns.length; j++)
			{
				QueryObj.SetField(null, columns[j], JSONQuery.DATA[i][colMap[columns[j]]]);
			}
		}
	}


	this.RecordCount = function()
	{
		return query.length;
	}


	this.SetField = function(rowNumber, columnName, value)
	{
		if (typeof(rowNumber) == "undefined" || TypeOf(rowNumber) == "null")
		{
			rowNumber = query.length - 1;	
		}

		if 
		(
		 	query.length > 0 && 
			rowNumber >= 0 && 
			rowNumber <= query.length - 1 &&
			QueryObj.ColumnExists(columnName)
		)
		{
			query[rowNumber][columnName] = value;
		}
	}


	this._OutputQuery = function()
	{
		var row = "";
		var columns = columnList.split(",");
		var output = "[COLUMNS]:\n" + columnList + "\n\n";
		
		output += "[DATA][ROWS (" + query.length + ")]:\n";


		for (var i = 0; i < query.length; i++)
		{
			row = "";

			for (var j = 0; j < columns.length; j++)
			{
				if (j > 0)
				{
					row += ",";	
				}

				row += query[i][columns[j]];
			}

			output += row + "\n";
		}

		return output;
	}




	/********************/
	/* Private Methods  */
	/********************/
	function _Init(columns, colTypes)
	{
		if (typeof(columns) != "undefined")
		{
			columns = String(columns).toLowerCase();
			columns = columns.split(",");


			if (typeof(colTypes) != "undefined")
			{
				colTypes = colTypes.split(",");
				
				if (columns.length != colTypes.length)
				{
					alert("The number of columns do not match the number of column types.  No query was loaded.");
					return;
				}

				// Validate Type
				for (var i = 0; i < colTypes.length; i++)
				{
					colTypes[i] = colTypes[i].toLowerCase();

					if (!IsValidColumnType(colTypes[i]))
					{
						alert("(" + colTypes[i] + ") is not a valid column type.");
						return;
					}
				}


				// Load columns
				for (var i = 0; i < columns.length; i++)
				{
					QueryObj.AddColumn(columns[i], colTypes[i]);	
				}
			}
			else
			{
				// Load columns
				for (var i = 0; i < columns.length; i++)
				{
					QueryObj.AddColumn(columns[i]);	
				}
			}
		}
	}


	function IsValidColumnType(columnType)
	{
		columnType = columnType.toLowerCase();

		for (var i = 0; i < columnTypes.length; i++)
		{
			if (columnType == columnTypes[i])
			{
				return true;
				break;
			}			
		}

		return false;
	}


	function Trim(astring)
	{
		return astring.replace(/^\s*/, "").replace(/\s*$/, ""); //Trim the start and end of string;
	}


	function TypeOf(value) 
	{
		var type = typeof value;

		if (type == "object") 
		{
			if (value == null) type = "null";
			else if (value.constructor == (new Array).constructor) type = "array";
			else if (value.constructor == (new Date).constructor) type = "date";
		}

		return type;
	}


	_Init(columns, colTypes);
}

Query.prototype.constructor = Query;
Query.prototype.toString = function()
{
	return this._OutputQuery();
}