/**
 * Dependencies
 * - prototype.js
 */
var Datum = Class.create({
	initialize: function(type, value, note, timestampStr) {
		this.type = type;
		this.value = value;
		this.note = note;
		
		// These two are separated because timestamps are usually provided as strings.
		// For efficiency, we delay conversion of the timestamp string to actual time.
		this.timestampStr = timestampStr;
		this.timestamp = null;
		
		// this.status = status;
		// this.sources = [status];
	},
	
	toString: function() {
		return "#" 
		 + this.type 
		 + "(" 
		 + this.value 
		 + ") " 
		 + this.note
		 + "\n"
		 + this.status;
	}
});

var NumericSeries = Class.create({
	initialize: function(type) {
		this.type = type;
		
		this.data = [];
		this.maxValue = 0;
		this.minValue = Number.MAX_VALUE;
		
		this.className = "NumericSeries";
	},
	
	size: function() {
		return this.data.length;
	},
	
	push: function(datum) {
		if (isNaN(datum.value)) {
			return;
		}
		
		this.data.push(datum);
		if (datum.value > this.maxValue) {
			this.maxValue = datum.value;
		}
		if (datum.value < this.minValue) {
			this.minValue = datum.value;
		}
	},
	
	sort: function(f) {
		this.data.sort(f);
	},
	
	filterByMonth: function(month, year) {
		var values = this.data.findAll(function(v) {
			try {
				// var date = Date.parse(v.status.created_at);
				return (v.timestampStr.match(month) && v.timestampStr.match(year));
				// return (month == date.getMonth() && year == date.getFullYear());
			} catch (err) {
				alert(err);
			}
		});
		
		var data = new NumericSeries(this.type);
		values.each(function(v) {
			data.push(v);
		});
		
		return data;
	},
	
	toString: function() {
		return this.data.join(",");
	}
});

var TextualSeries = Class.create({
	initialize: function(type) {
		this.type = type;
		
		this.data = [];
		
		this.className = "TextualSeries";
	},
	
	size: function() {
		return this.data.length;
	},
	
	push: function(datum) {
		this.data.push(datum);
	},
	
	sort: function(f) {
		this.data.sort(f);
	},
	
	filterByMonth: function(month, year) {
		var values = [];
		for (var i = 0; i < this.data.length; i++) {
			var v = this.data[i];
			if (v.timestampStr.indexOf(month) > -1 && v.timestampStr.indexOf(year) > -1) {
				values.push(v);
			}
		}
		
		var data = new TextualSeries(this.type);
		values.each(function(v) {
			data.push(v);
		});
		
		return data;
	},
	
	counts: function() {
		return this.data.pluck("value").inject(
			new Hash(),
			function(acc, value) {	
				if (value) {
					var data;
					if (data = acc.get(value)) {
						acc.set(value, data + 1);
					} else {
						acc.set(value, 1);
					}
				}						
				
				return acc;
			}
		);
	},
	
	toString: function() {
		return this.data.join(",");
	}
});

function convertTextualToNumericSeries(textualData, sort) {
	var numeric = new NumericSeries(textualData.type);
	var counts = textualData.counts();

	counts.keys().each(function(key) {
		numeric.push(new Datum("mood", counts.get(key), key));
	});
	
	var alphaSort = function(a, b) {
		var x = a.note.toLowerCase();
		var y = b.note.toLowerCase();
		if (y < x) {
			return 1;
		} else if (y == x) {
			return 0;
		} else {
			return -1;
		}
	};

	if (sort == "alpha") {
		numeric.sort(alphaSort);
	} else {
		numeric.sort(function(a, b) {
			var value = b.value - a.value;
			if (value == 0) {
				return alphaSort(a, b);
			} else {
				return value;
			}
		});
	}

	return numeric;
}

// The class is responsible for displaying tag clouds.
var CloudDisplay = Class.create({
	initialize: function(containerId) {
		this.containerId = containerId;
	},
	
	render: function(title, series) {
		var html = '<div class="cloud">'
	 	 + '<h3>'
		 + title 
		 + '</h3>'
		 + '<ul>';
		
		// Return if there is no data.
		if (!series || series.size() == 0) {
			html += '<p>No data.</p>';
		} else {
			html += '<ul>';
			
			if (series.className == "TextualSeries") {
				series = convertTextualToNumericSeries(series, "alpha");
			}

			var min = series.minValue;
			var max = series.maxValue;
			var range = max - min;
			var length = series.size();
			for (var i = 0; i < length; i++) {
				var datum = series.data[i];
				var value = datum.value;

				var ratio = (range == 0) ? 0.3 : ((value - min) / range);
				var size = Math.floor(ratio * 10);
				if (size == 10) {
					size = 9;
				}

				if (series.type == "_replies") {
					var linkName = datum.note.replace("@", "");
					html += '<li class="cloud_tag size'
					 + size
					 + 'c">'
					 + '<a href="/tw/'
					 + linkName
					 + '">'
					 + datum.note
					 + '</a>'
					 + '</li> &nbsp; ';
				} else if (series.type == "_urls") {
					var url = datum.note;
					if (!datum.note.match(/^(http:\/\/|https:\/\/|ftp:\/\/)/)) {
						url = "http://" + datum.note;
					}
					html += '<li class="cloud_tag size'
					 + size
					 + 'c">'
					 + '<a href="'
					 + url
					 + '">'
					 + datum.note
					 + '</a>'
					 + '</li> &nbsp; ';
				} else {
					note = datum.note;
					if (datum.note.indexOf(" ") == -1) {
						note = datum.note;
					} else {
						note = '"' + datum.note + '"';
					}
					html += '<li class="cloud_tag size'
					 + size
					 + 'c">'
					 + note
					 + '</li> &nbsp; ';
				}
			}
			
			html += '</ul>';
		}
		
		html += '</div>';

		$(this.containerId).update(html);
	}
});

// The class is responsible for displaying bar graphs.
var BarDisplay = Class.create({
	initialize: function(containerId) {
		this.containerId = containerId;
	},
	
	render: function(title, series) {
		var html = '<div class="graph">'
		 + '<h3>'
		 + title 
		 + '</h3>';

		// Return if there is no data.
		if (!series || series.size() == 0) {
			html += '<p>No data.</p>';
		} else {
			html += '<ul>';
			
			// Return if it's textual data.
			if (series.className == "TextualSeries") {
				return;
			}

			var maxValue = series.maxValue;
			for (var i = 0; i < series.size(); i++) {
				var datum = series.data[i];

				if (datum.timestampStr != null) {
					if (datum.timestamp == null) {
						// if (/^[A-Z][a-z]{2} /.match(datum.timestampStr)) {
						// 	var str = datum.timestampStr.substring(4);
						// 	datum.timestamp = Date.parse(str);
						// } else {
							datum.timestamp = Date.parse(datum.timestampStr);	
						// }
					}
				} else {
					datum.timestamp = new Date();
				}

				html += '<li>'
				 + '<div class="bar" style="width:'
				 + (datum.value / maxValue) * 100
				 + '%">'
				 + '<div class="label">'
				 + datum.value
				 + '</div>'
				 + '</div>'
				 + '<div class="note">'
				 + datum.note
				 + ' <span class="bar_date">'
				 + datum.timestamp
				 // + datum.timestamp.toString("MMM d, 'yy @ h:mm tt")
				 + '</span>'
				 + '</div>'
				 + '</li>';
			}
			
			html += '</ul>';
		}
		
		html += '</div>';

		$(this.containerId).update(html);
	}
});
