nfl.namespace('nfl.draft');
nfl.namespace('nfl.draft.tracker');

/* tracker data classes */
nfl.draft.tracker.data				= {};
nfl.draft.tracker.data.polling		= {'increment':'dtd','interval':15,'pe':false};
nfl.draft.tracker.data.teams		= {};
nfl.draft.tracker.data.positions	= {};
nfl.draft.tracker.data.colleges		= {};
nfl.draft.tracker.data.prospects	= {};
nfl.draft.tracker.data.picks		= {};
nfl.draft.tracker.data.draft		= {
	"round"    : 1,
	"pick"     : 1,
	"state"    : "PRE",
	"interval" : 15,
	"nextupdate" : 'dtd',
	"epicfail" : false
};
nfl.draft.tracker.data.analysisCache	= {};
nfl.draft.tracker.data.sorted			= {};

nfl.draft.tracker.data.arrays			= {};
nfl.draft.tracker.data.arrays.picks		= [];
nfl.draft.tracker.data.arrays.prospects	= [];

nfl.draft.tracker.data.dirty			= {};
nfl.draft.tracker.data.dirty.colleges	= {};
nfl.draft.tracker.data.dirty.picks		= {};
nfl.draft.tracker.data.dirty.prospects	= {};

nfl.draft.tracker.data.updatemode		= {onlydirty: true};

nfl.draft.tracker.events = {};
nfl.draft.tracker.events.analysisclick	= {};
nfl.draft.tracker.events.videoclick		= {};
nfl.draft.tracker.events.hashclick		= {};
nfl.draft.tracker.events.fire	= function(evt,memo){ document.fire(evt,memo);}
nfl.draft.tracker.events.analysisclick.fire	= function(pid,ele){ nfl.draft.tracker.events.fire('draft:tracker:analysislink:click',{'id':pid,'element':ele});}
nfl.draft.tracker.events.videoclick.fire	= function(vid){ nfl.draft.tracker.events.fire('draft:tracker:videolink:click',{'id':vid});}
nfl.draft.tracker.events.hashclick.fire		= function(hash){ nfl.draft.tracker.events.fire('draft:tracker:hashlink:click',{'hash':hash});}

/*
 * @class nfl.draft.tracker.engine
 * @namespace nfl.draft.tracker
 * @parameter Object initialization json object.
 * @author arianna.winters
 * 
 * class used to control draft data objects/polling
 */
nfl.draft.tracker.engine	= Class.create({
	initialize:function(json,options){
		console.info('initializing nfl.draft.tracker.engine');		
		/* utility objects */
		this.polling						= nfl.draft.tracker.data.polling;
		this.initializing					= true;
		this.jsonQueue						= [];
		this.options						= (typeof this.options !== 'null')?this.options:{};
		this.publishEvents					= true;
		this.boundHandlers					= {};
		
		document.observe('draft:tracker:data:updating',this.onUpdating.bind(this));
		document.observe('draft:tracker:data:updated',this.onUpdate.bind(this));
		document.observe('draft:tracker:data:changed',this.onChange.bind(this));
		document.observe('draft:tracker:engine:start',this.start.bind(this));
		document.observe('draft:tracker:engine:stop',this.stop.bind(this));
		document.observe('draft:tracker:data:analysis:get',this.getAnalysis.bind(this));
		document.observe('draft:tracker:data:analysis:updated',this.onAnalysisUpdate.bind(this));
		/* load json into data references */
		if(json){
			if(nfl.draft.tracker.data !== json){ 
				nfl.draft.tracker.data.updatemode.onlydirty = false;
				console.log('nfl.draft.tracker.engine.initialize: changed update mode to all.');
				this.boundHandlers.onWritten = this.onWritten.bindAsEventListener(this);
				document.observe('draft:tracker:data:written',this.boundHandlers.onWritten);
			}
			if(nfl.draft.tracker.data.draft.state === 'PRE' || nfl.draft.tracker.data.draft.state === 'POST'){this.initializing = false;}
			//console.info('json.draft = "'+Object.toJSON(json.draft)+'" type = '+ typeof json.draft);
			this.set(json,false);
			this.publishEvents	= true;
		}else{
			/* start polling, grab the gtd first */
			this.initializing = false;
			this.start();
		}
	},
	onWritten: function(event){
		document.stopObserving('draft:tracker:data:written', arguments.callee);
		document.stopObserving('draft:tracker:data:written', this.boundHandlers.onWritten);

		console.log('nfl.draft.tracker.engine.initialize: do initial dtd request? '+this.initializing+', nfl.draft.tracker.data.draft.state = '+nfl.draft.tracker.data.draft.state);
		if(this.initializing){
			nfl.draft.tracker.data.updatemode.onlydirty = true;
			this.initializing	 = false;
			/* we wait till here to get the gtd because we want to wait untill the current object write is done first */
			this.get();
		}
	},
	start:function(){
		if(this.polling.interval > 0){
			console.log('nfl.draft.tracker.engine.start');
			this.get();
			this.polling.pe	= new PeriodicalExecuter(this.get.bind(this),this.polling.interval);
			document.fire('draft:tracker:engine:started');
		}else{
			console.warn('nfl.draft.tracker.engine.start: this.polling.interval = '+this.polling.interval);
		}
	},
	stop:function(){
		if(this.polling.pe){
			console.log('nfl.draft.tracker.engine.stop');
			this.polling.pe.stop();
			this.polling.pe	= false;
			document.fire('draft:tracker:engine:stopped');
		}else{
			console.warn('nfl.draft.tracker.engine.stop: no periodical executer present.');
		}
	},
	clear:function(){
		console.log('nfl.draft.tracker.engine.clear');
		nfl.draft.tracker.data.teams		= {};
		nfl.draft.tracker.data.positions	= {};
		nfl.draft.tracker.data.colleges		= {};
		nfl.draft.tracker.data.prospects	= {};
		nfl.draft.tracker.data.picks		= {};
	},
	restart:function(interval){
		console.log('nfl.draft.tracker.engine.restart');
		this.polling.interval = interval;
		this.stop();
		if(this.polling.interval > 0){this.start();}
	},
	get:function(){
		//console.log('nfl.draft.tracker.engine.get');
		
		document.fire('draft:tracker:data:updating');
		/* request increment file */
		var path	= '/liveupdate/draft/2009/draft.'+ this.polling.increment +'.json?random='+ this.getCacheBustInt();
		var request	= new Ajax.Request(path,{
			method:'get',
			evalScripts:true,
			evalJSON: "force",
			onSuccess:function(XHR){
				var json	= false;
				if(typeof XHR.responseJSON != "undefined"){
					json	= XHR.responseJSON;
				}else{
					json	= eval('(' + XHR.responseText + ')');
				}
				document.fire('draft:tracker:data:updated',json);
			},
			onFailure:function(){
				document.fire('draft:tracker:data:updated',{error:true});
			}
		});
	},
	getAnalysis:function(event){
		var personId	= event.memo.id;
		document.fire('draft:tracker:data:updating');
		var path	= '/draft/2009/json/playerAnalysis?playerId='+personId+'&random='+ this.getCacheBustInt();
		var request	= new Ajax.Request(path,{
			method:'get',
			evalScripts:true,
			evalJSON: "force",
			onSuccess:function(XHR){
				var json	= false;
				if(typeof XHR.responseJSON != "undefined"){
					json	= XHR.responseJSON;
				}else{
					json	= eval('(' + XHR.responseText + ')');
				}
				json.personId	= personId;
				document.fire('draft:tracker:data:analysis:updated',json);
			},
			onFailure:function(){
				document.fire('draft:tracker:data:updated',{error:true});
			}
		});		
	},
	getCacheBustInt:function(){
		var time, d;
		d = new Date();
		d.setSeconds(Math.floor(d.getUTCSeconds() / 10) * 10);
		d.setMilliseconds(0);
		time = d.getTime();
		return time
	},
	set:function(json,ignoreInterval){
		//console.log('nfl.draft.tracker.engine.set: '+ Object.toJSON(json)+'\n\rthis.initializing='+this.initializing);
		//console.log('nfl.draft.tracker.engine.set: this.initializing='+this.initializing +', nfl.draft.tracker.data.updatemode.onlydirty = '+nfl.draft.tracker.data.updatemode.onlydirty);
		var isDirty	= false;
		if(typeof json.draft !== 'undefined'){
			/* draft */
			if(nfl.draft.tracker.data.draft !== json.draft){
				if(json.draft.epicfail){
					/* uh roh! */
					//console.log('all hell broke loose, ice caps are melting, polar bears are eating people.'); 
					//window.location.reload();
				}
				if(!this.initializing){
					if(nfl.draft.tracker.data.draft.nextUpdate !== json.draft.nextUpdate){
						this.polling.increment	= json.draft.nextUpdate;
					}
					if(nfl.draft.tracker.data.draft.interval !== json.draft.interval && json.draft.interval !== null && Object.isNumber(json.draft.interval)){
						/* change polling interval */
						if(json.draft.interval > 0){ this.restart(json.draft.interval); }else{ this.stop(); }
					}
				}
				for(key in json.draft){
					if(nfl.draft.tracker.data.draft[key] !== json.draft[key]){isDirty = true;}
					nfl.draft.tracker.data.draft[key]	= json.draft[key];
				}
			}
		}
		if(!nfl.draft.tracker.data.updatemode.onlydirty){
			if(json.colleges){
				nfl.draft.tracker.data.colleges			= json.colleges;
				nfl.draft.tracker.data.dirty.colleges	= nfl.draft.tracker.data.colleges;
				document.fire('draft:tracker:data:colleges:changed',nfl.draft.tracker.data.colleges);
			}
			if(json.prospects){
				nfl.draft.tracker.data.prospects		= json.prospects;
				nfl.draft.tracker.data.dirty.prospects	= nfl.draft.tracker.data.prospects;
			}
			if(json.picks){
				nfl.draft.tracker.data.picks			= json.picks;
				nfl.draft.tracker.data.dirty.picks		= nfl.draft.tracker.data.picks;
				//nfl.draft.tracker.data.array.picks		= nfl.draft.tracker.data.array.picks
			}
			//console.log('nfl.draft.tracker.engine.set: all data. this.publishEvents? '+this.publishEvents);
			if(this.publishEvents){document.fire('draft:tracker:data:changed');}
			return
		}
		if(json.colleges){
			//console.log('nfl.draft.tracker.engine.set: looping through json.colleges');
			/* loop through colleges, update if necessary */
			var collegesIsDirty	= false;
			for(key in json.colleges){
				//console.log('nfl.draft.tracker.engine.set.colleges.loop: '+key);
				if(nfl.draft.tracker.data.colleges[key] !== json.colleges[key]){
					//console.log('nfl.draft.tracker.engine.set.colleges.loop: '+key+' is dirty');
					isDirty = true; collegesIsDirty = true;
					nfl.draft.tracker.data.dirty.colleges[key]	= key;
				}
				nfl.draft.tracker.data.colleges[key]	= json.colleges[key];
			}
			if(collegesIsDirty){
				document.fire('draft:tracker:data:colleges:changed',nfl.draft.tracker.data.colleges);
			}
		}
		if(json.prospects){
			//console.log('nfl.draft.tracker.engine.set: looping through json.prospects');
			/* loop through prospects, update if necessary */
			for(key in json.prospects){
				//console.log('nfl.draft.tracker.engine.set.prospects.loop: '+key);
				if(nfl.draft.tracker.data.prospects[key] !== json.prospects[key]){
					//console.log('nfl.draft.tracker.engine.set.prospects.loop: '+key+' is dirty');
					isDirty = true;
					nfl.draft.tracker.data.dirty.prospects[key]	= key;
					if(json.prospects[key].pick !== null){
						//person has been picked, mark pick as dirty also
						//console.log('onAnalysisUpdate: person has already been picked, find him in picks.. typeof pick value is '+(typeof json.prospects[key].pick));
						var pkey = json.prospects[key].pick;
						if(typeof pkey === 'object' && pkey !== null){pkey = pkey.id};
						if(typeof nfl.draft.tracker.data.picks[pkey] !== 'undefined'){
							nfl.draft.tracker.data.dirty.picks[pkey]	= pkey;
						}
					}
				}
				nfl.draft.tracker.data.prospects[key]	= json.prospects[key];
			}
		}
		if(json.picks){
			//console.log('nfl.draft.tracker.engine.set: looping through json.picks');
			/* loop through prospects, update if necessary */
			for(key in json.picks){
				//console.log('nfl.draft.tracker.engine.set.picks.loop: '+key);
				if(nfl.draft.tracker.data.picks[key] !== json.picks[key]){
					//console.log('nfl.draft.tracker.engine.set.picks.loop: '+key+' is dirty');
					isDirty = true;
					nfl.draft.tracker.data.dirty.picks[key]	= key;
				}
				nfl.draft.tracker.data.picks[key]	= json.picks[key];
			}
		}
		if(isDirty){
			console.log('nfl.draft.tracker.engine.set: data is dirty, fire data changed event? '+this.publishEvents);
			if(this.publishEvents){document.fire('draft:tracker:data:changed');}
		}else{
			console.log('nfl.draft.tracker.engine.set: data is clean.');
		}
	},
	onChange: function(event){
		/* redraw current bound object */
	},
	onUpdating: function(event){
		
	},
	onAnalysisUpdate: function(event){
		//{"pickAnalysis":"added pick analysis notes @ 1647"};
		var personId		= event.memo.personId;
		var pickAnalysis	= event.memo.pickAnalysis;
		if(nfl.draft.tracker.data.prospects){
			if(nfl.draft.tracker.data.prospects[personId] !== null){
				nfl.draft.tracker.data.prospects[personId].pickAnalysis = pickAnalysis;
				nfl.draft.tracker.data.dirty.prospects[personId]	= personId;
				if(nfl.draft.tracker.data.prospects[personId].pick !== null){
					/* person has been picked, mark pick as dirty also */
					console.log('onAnalysisUpdate: person has already been picked, find him in picks.. typeof pick value is '+(typeof nfl.draft.tracker.data.prospects[personId].pick));
					var pkey = nfl.draft.tracker.data.prospects[personId].pick;
					if(typeof pkey === 'object' && pkey !== null){pkey = pkey.id};
					if(typeof nfl.draft.tracker.data.picks[pkey] !== 'undefined'){
						nfl.draft.tracker.data.dirty.picks[pkey]	= pkey;
					}
				}
				document.fire('draft:tracker:data:changed',{'action':'analysis'});
			}
		}
	},
	onUpdate: function(event){
		var json	= event.memo;
		//console.log('nfl.draft.tracker.engine.onUpdate');
		/* update occured */
		if(nfl.draft.tracker.data.draft.epicfail){
			/* all hell broke loose, ice caps are melting, polar bears are eating people */
			//window.location.reload();
		}
		if(!json.error && !json.empty){
			//console.log('nfl.draft.tracker.engine.onUpdate: '+ json.toString());
			this.set(json);
			if(!this.initializing){
				if((nfl.draft.tracker.data.draft.state === 'IN' || nfl.draft.tracker.data.draft.state === 'ACTIVE') && !this.polling.pe){
					//make sure poller is running
					this.start();
				}
				if((nfl.draft.tracker.data.draft.state === 'PRE' || nfl.draft.tracker.data.draft.state === 'POST') && this.polling.pe){
					this.stop();
				}	
			}
		}else{
			console.warn('nfl.draft.tracker.engine.onUpdate: NO DATA!');
		}
	}
});

/*
 * @class nfl.draft.tracker.writer
 * @namespace nfl.draft.tracker
 * @parameter Object initialization json object.
 * @parameter Object optional params object.
 * @author arianna.winters
 * 
 * class used to respond to data changes, and perform drawing/filtering of the results
 */
nfl.draft.tracker.writer	= Class.create({
	initialize:function(json,options){
		console.info('initializing nfl.draft.tracker.writer');
		this.templates			= (typeof options.templates !== 'undefined')?options.templates:{};
		this.containers			= (typeof options.containers !== 'undefined')?options.containers:{};
		this.row.templates		= this.templates;
		this.activecontainer	= (typeof options.activecontainer !== 'undefined')?options.activecontainer:null;
		this.filters			= (typeof options.filters !== 'undefined')?options.filters:{};
		
		/* create template objects from templates */
		//for(var key in this.templates){
		//	this.templates[key]	= new Template(this.templates[key]);
		//}
		/*create event binding first so they can intercept initial changes */
		document.observe('draft:tracker:data:changed',this.onDataChange.bind(this));
		document.observe('draft:tracker:view:changed',this.onViewChange.bind(this));
		document.observe('draft:tracker:filters:changed',this.onFilterChange.bind(this));
		/*initialize data engine */
		this.engine	= new nfl.draft.tracker.engine(json);
	},
	join: function(json){
		//console.warn('json = '+json+'.json type = '+(typeof json));
		if(json){
			/* update data bottom up */
			if(typeof json.hasAnalysis === 'boolean'){
				var toggleIco 	= (json.hasAnalysis)?'[+]':'';
				var expandedClass	= 'analysis-row-collapsed';
				if(typeof nfl.draft.tracker.data.analysisCache[json.personId] !== 'undefined' && nfl.draft.tracker.data.analysisCache[json.personId] !== null){ toggleIco	= '[-]'; expandedClass = 'analysis-row-expanded'; console.log('join toggle for nfl.draft.tracker.data.analysisCache['+json.personId+'] = '+nfl.draft.tracker.data.analysisCache[json.personId]);}
				json.toggle	= '<div onclick="nfl.draft.tracker.events.analysisclick.fire(\''+json.personId+'\',this)" class="analysis-link">'+toggleIco+'</div>';
				json.expandedClass	= expandedClass;
				nfl.draft.tracker.data.prospects[json.personId].toggle	= json.toggle;
				nfl.draft.tracker.data.prospects[json.personId].expandedClass	= json.expandedClass;
			}
			if(json.personId !== null && typeof json.personId !== 'undefined'){
				/* this is a prospect */
				var linkName	= (json.firstName !== '')?json.firstName+'-'+json.lastName:json.lastName;
				json.linkName	= linkName.toLowerCase().replace(/\'/g,"\\'");
				json.rowkey		= json.personId;
				json.videoLink	= '';
				if(json.height === null){json.height = "--";};
				if(json.weight === null){json.weight = "--";};
				if(typeof json.video !== 'undefined' && json.video !== null){
					//window.location = (window.location.protocol+'//'+window.location.host+'/videos?videoId='+videoId);
					json.videoLink	= '<a href="/videos?videoId='+json.video+'" target="_blank"><span class="video-link"></span></a>';
				}
				if(typeof json.college !== 'undefined' && json.college !== null){
					/* this is a prospect */
					if(typeof json.college === 'number'){
						json.college = nfl.draft.tracker.data.colleges[json.college];
					}else{
						if(typeof json.college === 'object'){
							if(typeof nfl.draft.tracker.data.colleges[json.college.id] !== 'undefined'){
								json.college = nfl.draft.tracker.data.colleges[json.college.id];
							}else{}
						}else{
							json.college	= {name:'',id:'',conf:''};
						}
					}
					json.collegeid		= '';
					json.collegeconf	= '';
					if(typeof json.college === 'object'){
						json.collegeid 		= json.college.id;
						if(typeof json.college.conf === 'string'){
							json.collegeconf	= (json.college.conf).toLowerCase().replace(' ','');
						}
					}
				}else{
					json.college	= {name:'',id:'',conf:''};
				}
				if(typeof json.posgroup === 'undefined' && typeof json.pos !== 'undefined'){
					/* this is a prospect */
					//console.info('join pos = '+json.pos+', typeof pos = '+ (typeof json.pos)+' pos group = '+ nfl.draft.tracker.data.positions[json.pos]);
					if(typeof json.pos === 'string'){
						json.posgroup = (nfl.draft.tracker.data.positions[json.pos]).toLowerCase();
					}
					/* update prospects global data while were at it */
					nfl.draft.tracker.data.prospects[json.personId].posgroup	= json.posgroup;
				}
				if((typeof json.pick === 'string' || typeof json.pick === 'number') && json.pick !== null){
					/* this is a prospect with a pick, populate pick */
					if(typeof json.pick === 'number'){ json.pick = ""+json.pick;}
					if(typeof nfl.draft.tracker.data.picks[json.pick].team === 'string'){
						nfl.draft.tracker.data.picks[json.pick].team	= nfl.draft.tracker.data.teams[nfl.draft.tracker.data.picks[json.pick].team];
					}
					json.pick	= Object.clone(nfl.draft.tracker.data.picks[json.pick]);
					nfl.draft.tracker.data.prospects[json.personId].pick	= json.pick;
				}
				nfl.draft.tracker.data.prospects[json.personId].videoLink	= json.videoLink;
				nfl.draft.tracker.data.prospects[json.personId].linkName	= json.linkName;
			}else{
				if(typeof json.round !== 'undefined'){
					/* this is a pick */
					if(typeof json.team === 'string'){
						json.team	= nfl.draft.tracker.data.teams[json.team];
						nfl.draft.tracker.data.picks[json.id].team	= json.team;
					}
					if(typeof json.player !== 'undefined' && json.player !== null){
						/* this is a pick, screw the traversal */
						//console.warn('json.player = '+json.player+'. type = '+ (typeof json.player) +'.');
						if(typeof json.player === 'string'){
							//console.warn('json.player = '+json.player+'. attempting recursive join on player.\n'+ Object.toJSON(nfl.draft.tracker.data.prospects[json.player]));
							json.player		= Object.clone(this.join(nfl.draft.tracker.data.prospects[json.player]));
							json.player.pick = json.id;
							//console.warn('post join data player data '+ Object.toJSON(json.player));
						}else{
							//console.warn('json.player.personId = '+json.player.personId+'. attempting recursive join.');
							json.player		= Object.clone(this.join(nfl.draft.tracker.data.prospects[json.player.personId]));
							json.player.pick = json.id;
						}
						//nfl.draft.tracker.data.prospects[json.player.personId]	= Object.clone(json.player);
						json.rowkey		= json.player.personId;
						json.expandedClass = json.player.expandedClass;
						//nfl.draft.tracker.data.picks[json.id]	= Object.clone(json);
					}else{
						if(typeof json.round !== 'undefined'){
							json.rowkey		= json.id;
							json.expandedClass = 'analysis-row-expanded';
							json.player		= {college:{name:'',id:'',conf:''},toggle:'',firstName:'',lastName:'',height:'',weight:'',hasAnalysis:false,pos:'',videoLink:''};
						}
					}
				}
			}
		}else{
			console.warn('wtf?!?!!?! a join with no json. type = '+(typeof json));
		}
		return json;
	},
	row: {
		matchesFilters: function(filters,json){
			//console.info('row.matchesFilters('+ Object.toJSON(json) +')');
			var appendRow = true;
			for(var f=0,flen=filters.length;f<flen;++f) {
				/* check for filter match */
				//console.info('row.matchesFilter: checking for '+ Object.toJSON(filters[f]));
				
				if(typeof json != "undefined" && json != null && typeof filters[f] != "undefined" && filters[f] != null){
					//nfl.log("filter: filtering by "+ filters[f].criteria +" on "+ filters[f].field);
					if(typeof json[filters[f].field] !== "undefined"){
						if(json[filters[f].field] !== null){
							//if(filters[f].field == "positionGroup" && filters[f].criteria.indexOf("SPECIALISTS") > -1){ alert("looking for specialists:\n\rfilters[f].criteria.indexOf(\"SPECIALISTS\") = "+filters[f].criteria.indexOf("SPECIALISTS")+"\n\r\""+filters[f].criteria+"\" == \"SPECIALISTS\"? "+(filters[f].criteria == "SPECIALISTS"));}
							if(filters[f].operator == '='){
								if(typeof json[filters[f].field] == "number" && json[filters[f].field] != filters[f].criteria){ appendRow = false; }
								if(typeof json[filters[f].field] == "string" && json[filters[f].field].toUpperCase() != filters[f].criteria.toUpperCase()){ appendRow = false; }
							}
							if(filters[f].operator == 'startsWith'){
								if(json[filters[f].field].toUpperCase().indexOf(filters[f].criteria.toUpperCase()) != 0){ appendRow = false; }
							}
							//nfl.log("tested "+ json[filters[f].field] +" against '"+ filters[f].operator +"' on "+ filters[f].criteria +" which is of type \""+ (typeof json[filters[f].field])+"\"");
						}else{
							/* field is null, automatically fail */
							//nfl.log("json["+filters[f].field+"] is null");
							appendRow = false; break;
						}
					}else{
						/* does not have property, criteria check fail */
						//nfl.log("typeof json["+ filters[f].field +"] = "+ (typeof json[filters[f].field]));
						appendRow = false; break;
					}
				}else{
					/* row has either been removed or never existed */
					appendRow = false; break;
				}
			}
			return appendRow
		},
		getTags: function(json){
			retString	= "";
			if(typeof json !== 'undefined' && json !== null){
				/* we have json */
				var isDirty		= false;
				if(typeof nfl.draft.tracker.data.dirty.prospects[json.personId] !== 'undefined' || typeof nfl.draft.tracker.data.dirty.picks[json.id] !== 'undefined'){isDirty	= true;}
				if(!isDirty && typeof json.filterclasses !== 'undefined'){
					return json.filterclasses;
				}
				if(typeof json.round !== 'undefined'){
					retString	+= ('by-round-input-'+json.round+' ');
				}
				if(typeof json.player === 'object'){
					/* we have a pick object */
					retString += this.getTags(json.player);
				}else{
					if(typeof json.lastName === 'string'){
						retString	+= ('by-name-input-'+json.lastName.substring(0,1).toLowerCase()+' ');
						var asName	= (json.lastName).toLowerCase().replace(' ','');
						for(var asc=0,asn=asName.length; asc < asn;asc++){
							retString	+= ('as-input-'+asName.substring(0,(asc+1))+' ');
						}
						if(json.college){
							retString	+= ('by-college-input-'+json.college.id+' ');
							if(json.college.conf){
								retString	+= ('by-conference-input-'+((json.college.conf).replace(' ','').replace('-','').toLowerCase())+' ');
							}
						}
						if(json.posgroup){
							retString	+= ('by-position-input-'+json.posgroup.toLowerCase()+' ');
						}
					}
				}
				if(retString !== ''){
					if(typeof json.personId !== 'undefined'){
						nfl.draft.tracker.data.prospects[json.personId].filterclasses = retString;
					}else{
						if(typeof json.round !== 'undefined'){
							nfl.draft.tracker.data.picks[json.id].filterclasses = retString;
						}
					}
				}
			}else{
				/* wtf? */
				//console.warn('getRowFilterClasses: no json('+ json +') passes in: '+(typeof json)+'. is null? '+(json === null));
			}
			return retString;
		},
		getContent: function(container,json){
			json.containerkey		= container;
			json.filterclasses 		= '';
			var pickobj				= json;
			/* mark first and last rows with classes */
			
			if(typeof json.personId !== 'undefined' && json.personId !== null && json.pick !== null){
				//console.log('getContent: obj is prospect.'+ Object.toJSON(json.pick));
				pickobj	= nfl.draft.tracker.data.picks[json.pick];
				/* prospect */
			}
			if(pickobj !== null && typeof pickobj !== 'undefined'){
				if(pickobj.id == nfl.draft.tracker.data.draft.overall){
					json.filterclasses 		= 'current';
				}
				if(pickobj.id == (nfl.draft.tracker.data.draft.overall - 1)){
					json.filterclasses 		= 'last';
				}
				//console.info('filterclasses change: '+Object.toJSON(pickobj)+' '+json.filterclasses +', overall('+nfl.draft.tracker.data.draft.overall+') = '+pickobj.id+'? '+(pickobj.id == nfl.draft.tracker.data.draft.overall));	
			}
			//json.filterclasses 		= this.getTags(json);
			return (this.templates[container](json));
		},
		remove: function(id){
			if($(id)){
				$(id).remove();
				var analysisKey	= (id.substring(0,id.lastIndexOf('-'))+'-analysis-row-'+id.substring(id.lastIndexOf('-')+1));
				if($(analysisKey)){ $(analysisKey).remove(); }
			}
		}
	},
	writeNode:function(jsonnode,options){
		var options	= (typeof options !== 'undefined')?options:{};
		var containersContent	= new Hash();
		var containers			= this.containers;
		var filters				= [];
		
		if(this.activecontainer !== null){
			/* assign active container to containers */
			containers			= {};
			containers[this.activecontainer]	= this.containers[this.activecontainer];
			filters				= this.filters[this.activecontainer];
			//console.info('nfl.draft.tracker.writer.writeNode: containers returned from activecontainer key');
		}
		if(typeof options.containers !== 'undefined'){
			containers			= options.containers;
			//console.info('nfl.draft.tracker.writer.writeNode: containers returned options.containers');
		}
		if(typeof options.filters !== 'undefined'){
			filters			= options.filters;
			//console.info('nfl.draft.tracker.writer.writeNode: filters returned from options.filters'+ Object.toJSON(filters));
		}
		
		//console.info('nfl.draft.tracker.writer.writeNode: writing to: '+Object.toJSON(containers));
		var rowClass	= 'even';
		for(var key in jsonnode){
			//index++; if(index > debugLimit){ break; }
			var nodeValue	= jsonnode[key];
			var json		= nodeValue;
			var isDirty		= false;
			if(typeof nfl.draft.tracker.data.dirty.prospects[key] !== 'undefined' || typeof nfl.draft.tracker.data.dirty.picks[key] !== 'undefined'){isDirty	= true;}
			if(isDirty){
				json = this.join(nodeValue,true);
				//console.log(key+' is dirty, '+Object.toJSON(json));
			}
			if(typeof json.rowkey !== 'undefined'){
				json.containerKeys	= [];
				if(json.personId !== null){
					rowType	= 'prospect'; /* must be a player*/
				}
				if(typeof json.round !== 'undefined'){
					rowType	= 'pick';
				}
				switch(rowType){
					case "prospect":
						if(json.pick !== null){
							/* this is a player that has been picked, allow it to write to drafted container */
							json.containerKeys	= ['drafted'];
						}else{
							json.containerKeys	= ['undrafted'];
						}
						break;
					case "pick":
						json.containerKeys	= ['picks'];
						break;
				}
				for(var c in containers){
					var container	= containers[c];
					if(typeof container !== 'undefined'){
						for(var ct=0,cl=json.containerKeys.length; ct < cl; ct++){
							if(typeof container[json.containerKeys[ct]] !== 'undefined'){
								//console.log('row write on '+container[json.containerKeys[ct]]);
								if(typeof containersContent.get(container[json.containerKeys[ct]]) === 'undefined'){
									containersContent.set(container[json.containerKeys[ct]],''); //console.info('created content key for '+container[json.containerKeys[ct]]);
								}
								//console.log('rowType: '+rowType+'; container['+ containerKeys[ct] +'] type = '+(typeof container[containerKeys[ct]]));
								if(rowType === 'prospect' || rowType === 'pick'){
									var dkey	= container[json.containerKeys[ct]];
									var dval	= containersContent.get(dkey);
									/* container contains container key */
									if(this.row.matchesFilters(filters,json)){ if(rowClass == 'odd'){rowClass = 'even'}else{rowClass = 'odd'}; json.rowclass = rowClass; containersContent.set(dkey,dval+this.row.getContent(dkey,json)); }
								}
							}else{
								//console.log(Object.toJSON(container[containerKeys[ct]])+' container['+ containerKeys[ct] +']: invalid type('+typeof container[containerKeys[ct]]+')');
							}
						}
					}
				}
			}else{
				//console.warn('nfl.draft.tracker.writer.writeNode: no rowkey for '+Object.toJSON(json));
			}
			//}catch(e){console.warn('nfl.draft.tracker.writer.writeNode: error. '+ e.lineNumber +','+errorMarker+'. '+e.message);}
		};
		/* clear out empty content containers */
		
		/* update with new content */
		containersContent.each(function(pair){
			//console.log('containersContent.each: '+pair.key+' = '+pair.value+', value type ="'+(typeof pair.value)+'"\n\r');
			if($(pair.key) && typeof pair.value !== 'undefined'){
				var updateEle	= $(pair.key);
				var updateHTML	= pair.value;
				if(updateEle.down('tbody')){ updateEle = updateEle.down('tbody');}
				//updateHTML	= (typeof updateEle.innerHTML !== 'undefined')?(updateEle.innerHTML+updateHTML):updateHTML;
				updateEle.update(updateHTML);
			};
		});
		document.fire('draft:tracker:data:node:written');
	},
	write:function(options){
		/* for write all we need an uber optimized sync AND write done */
		document.fire('draft:tracker:writer:updating');
		console.info('nfl.draft.tracker.writer.write: all data mode');
		this.writeNode(nfl.draft.tracker.data.prospects,options);
		this.writeNode(nfl.draft.tracker.data.picks,options);
		//this.writeArray(nfl.draft.tracker.data.arrays.prospects,options);
		//this.writeArray(nfl.draft.tracker.data.arrays.picks,options);
		document.fire('draft:tracker:data:written');
	},
	sync: function(options){
		console.info('nfl.draft.tracker.writer.sync');
		this.write(options);
		nfl.draft.tracker.data.dirty.prospects	= {};
		nfl.draft.tracker.data.dirty.picks		= {};
		nfl.draft.tracker.data.dirty.colleges	= {};
	},
	onFilterChange: function(event){
		if(typeof event.memo.filters !== 'undefined'){
			console.info('onFilterChange: '+ Object.toJSON(event.memo.filters));
			this.write(event.memo);
		}
	},
	onViewChange:function(event){
		//console.info('nfl.draft.tracker.writer.onViewChange');
		//console.info('nfl.draft.tracker.writer.onViewChange:'+ (typeof event.memo.filters));
		/* run some checks */
		this.sync(event.memo);
	},
	onDataChange:function(){
		//console.info('nfl.draft.tracker.writer.onDataChange');
		/* run some checks */
		this.sync();
	}
});
nfl.draft.tracker.tables	= {}
nfl.draft.tracker.tables.sort = function(table){
	var table		= $(table);
	var keyColumn	= 0;
	var sort		= [];
	var rows		= {};
	var sortMode	= 0;
	try{
	if(table.down('thead tr td.sortkey')){
		/* there is a sortkey column */
		table.select('thead tr td').each(function(ele,index){
			if(ele.hasClassName('sortkey')){ keyColumn = index; return; }
		});
	}
	var tablerows	= table.select('tbody tr');
	for(var i=0,len	= tablerows.length; i < len; i++){
		/* build index */
		var ele		= tablerows[i];
		var value	= ele.select('td')[keyColumn].innerHTML.strip();
		if(!isNaN(value)){
			value = parseInt(value); sortMode = 1;
		}
		if(sort.indexOf(value) > -1){
			value = (!isNaN(value))?(value+0.5):(value+''+sort.length);
		}
		
		sort[sort.length]	= value;
		rows[value]	= ele.getOuterHTML();
	}
	if(sortMode == 1){sort.sort(function(a,b){return a - b;});}else{sort.sort();}
	console.log('nfl.draft.tracker.tables.sort('+sortMode+'): sort array is \r'+sort);
	var newInnerHTML	= "";
	if(sort.length > 0){
		for(var i=0,len	= sort.length; i < len; i++){
			var trKey	= sort[i];
			newInnerHTML	+= (rows[trKey]+'\r');
		}
		//console.log('nfl.draft.tracker.tables.sort: #'+table.identify()+'\r'+newInnerHTML);
		if(table.down('tbody')){table = table.down('tbody');}
		//newInnerHTML	= newInnerHTML.replace('\'','\\\'');
		table.update(newInnerHTML);
		console.log('nfl.draft.tracker.tables.sort: wrote sorted table back to dom');
	}
	}catch(e){ console.warn('nfl.draft.tracker.tables.sort: error '+e.message); }
}