if((typeof Prototype=='undefined') || 
   (typeof Element == 'undefined') || 
   (typeof Element.Methods=='undefined') ) 
{
   throw new Error("coldfusion.js requires including the Prototype JavaScript Framework");
}

Coldfusion = { };


//container for some coldfusion helpers relating to javascript dates\
//this could become a class at some point but for now it only has some
//'static' methods/properties in it. 
Coldfusion.Date = {};
Coldfusion.Date.monthNames = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'];
Coldfusion.Date.toCfDateTime = function (d) {
	return d.getDate() 
		+ "-" 
		+ Coldfusion.Date.monthNames[d.getMonth()].substring(0,3) 
		+ "-" 
		+ d.getFullYear() 
		+ " " 
		+ d.getHours() 
		+ ":" 
		+ d.getMinutes() 
		+ ":" 
		+ d.getSeconds();
};

//input: stringified coldfusion date/time object {ts .... }
//output: javascript date object or an 'invalid date' object
//		depending on how parsing went. I'm discarding fractional seconds from cf
// to be lazy. re-implement if you need better than seconds resolution. 
Coldfusion.Date.fromCfDateTime = function(d){
	return new Date(Date.parse(d.replace(/-/g, '/').replace(/\.\d+$/g, '')));
}

/**
 * a wrapper class around a javascript representation of a coldfusion array. 
 * Features getters, setters, an iterator, 
 * and handy methods for manipulating columns 
 * and rows. column names are always lowercased. (i don't like code which yells at me)
 **/


Coldfusion.Query = Class.create({
	initialize: function(p){
		if (!p) { //make an empty query 
			this.query = { };
			this.query.recordcount = 0;
			this.query.columnlist = []; //i refuse to use a CSV as an in-memory datastructure...
			this.query.data = { };
		} else if (
				Object.isString(p.columnlist)
				&& p.data	
				&& p.recordcount
		){ //rather likely that p is a coldfusion query-like javascript object
			this.query = Object.clone(p);
			this.query.columnlist = p.columnlist.split(/,/);
		} else if (Object.isString(p)) { //emulates cf QueryNew(columnlist) function
			this.query = { };
			this.query.recordcount = 0;
			this.query.columnlist = p.split(/,/);
			this.query.data = { };
			this.query.columnlist.each(function(columnName) {
				this.query.data[columnName] = [];
			}, this);
		}  else {
			throw new Error("input parameter to Coldfusion.Query constructor is invalid");
		} 
	},
	get: function(columnName, row) {
		row = (Object.isNumber(row) ? row : 0);
		if (!Object.isNumber(row) || row > this.query.recordcount || row < 0){
			throw new Error("Coldfusion.Query.get: Invalid row number '" + row + "'.");
			return null;
		} else if (this.query.columnlist.indexOf(columnName) == -1){
			throw new Error("Coldfusion.Query.get: Invalid column name. '" + columnName + "'.");
			return null;
		} else {
			return this.query.data[columnName][row];
		}
	},
	addColumn: function(columnName, values){
		var v = values || [];
		this.query.columnlist.push(columnName);
		this.query.data[columnName] = [];
		for(var i = 0; i < v.length && i < this.query.recordcount; i++){
			if (i >= this.query.recordcount){
				this.query.data[columName].push(null); //pad with nulls
			} else {
				this.query.data[columnName].push(v[i]);
			}
		}
	},
	addRow: function(r){
		if (!r){ //add 'empty' nulled row
			this.query.columnlist.each(function(colName) {
				this.query.data[colName].push(null);
			}, this);
		} else if (Object.isArray(r)){
			this.query.columnlist.each(function(colName, colIndex){
				if (colIndex < r.length){
					this.query.data[colName].push(r[colIndex]);
				} else { //null pad
					this.query.data[colName].push(null);
				}
			}, this);
		} else { //maybe an object with keys matching our fieldnames, sniff around for matching colNames
			this.query.columnlist.each(function(colName) {
				this.query.data[colName].push(r[colName] || null);
			}, this);
		}
		this.query.recordcount += 1;
	},
	getRow: function(i){
		if (i >= this.query.recordcount || i < 0) throw new Error("Coldfusion.Query.getRow: invalid index '" + i + "'.");
		row = {};
		this.query.columnlist.each(function (colName) {
			row[colName] = this.query.data[colName][i];
		}, this);
		return row;
	},
	
	// return array
	getColumnNames: function(){
		return (this.query.columnlist.clone());
	},
	//crappy cf list thing
	getColumnList: function(){
		return this.query.columnlist.join(",");
	},
	getColumn: function(colName){
		return (this.query.data[colName] ? (this.query.data[colName].clone()) : null );
	},
	
	_each: function(iterator) {
		for (var i = 0, length = this.query.recordcount; i < length; i++) {
			iterator(this.getRow(i));
		}
	},
	
	each: function(iterator, context) {
		var index = 0;
		iterator = iterator.bind(context);
		try {
			this._each(function(value) {
				iterator(value, index++);
			});
		} catch (e) {
			if (e != $break) throw e;
		}
		return this;
	},
	toSource: function(){
		var q = Object.clone(this.query); //you can have a copy. 
		q.columnlist = q.columnlist.join(','); //turn back into stoopid csv thing
		return q;
	}
});



