/* -- Object for colors -- */

function Couleurs() {	
	switch (arguments.length) {
	case 1:
		if ("number"==typeof(arguments[0])) {
			if (10==arguments[0]) {
				this.get = d3.scale.category10();
			}
			else if (20==arguments[0]) {
				this.get = d3.scale.category20();
			}
			else {
				var domain = [], quantity = 0, colors = colorbrewer, 
					setID, colorID, color;
				var sets = ["BrBG", "PiYG", "PRGn", "PuOr", "RdBu", "RdYlBu", "RdYlGn"];
				
				while (quantity < arguments[0]) {
					setID = 	Math.floor(Math.random()*7);
					colorID = Math.floor(Math.random()*11);
					color = Couleurs.fn.d3Color(
							colors[sets[setID]][11][colorID]);
					
					var available = true;
					for (var i = 0; i < quantity; i++) {
						if (Math.abs(Couleurs.fn.hue(domain[i])
								- Couleurs.fn.hue(color)) < 0.1) {
							available = false;
						}
					}
					
					if (Couleurs.fn.brightness(color) < 0.9 && available) {
						domain.push(color);
						++quantity;
					}
				}
				
				// Transform into hexadecimal colors
				for (var index in domain) {
					domain[index] = domain[index].toString();
				}
				this.get = d3.scale.ordinal().range(domain);
			}
		}
		else if (Array==arguments[0].constructor) {
			var inputs = [];
			for (var i in arguments[0]) {
				inputs.push(i);
			}
			this.get = d3.scale.ordinal()
				.domain(inputs)
				.range(arguments[0]);
		}
		else {
			throw "Wrong arguments";
		}
		break;
		
	case 3:
		this.range = d3.interpolateRgb(arguments[0], arguments[1]);
		this.levels = arguments[2];
		this.get = this.getFromInterpolation;
		break;

	default:
		throw "Wrong number of arguments";
	}
}

Couleurs.fn = Couleurs.prototype = {
	constructor: Couleurs,

	d3Color: function(rgbString) {
		return d3.rgb(rgbString);
	},
	
	brightness: function(color) {
		return (color.r + color.r + color.b + color.g + color.g + color.g)/(6*255);
	},
	
	hue: function(color) {
		return Math.sqrt(3) * (color.g - color.b)
			/(color.r + color.r - color.g - color.b);
	},
	
	getFromInterpolation: function(index) {
		if (index<1) {
			return this.range(index);
		}
		else {
			index = (0==index%this.levels)? this.levels: index%this.levels; 
			return this.range((index - 1)/(this.levels - 1));
		}
	}
};