
var CM = (function(){ // begining namespace CM
// private

return {
// public

/////////////////////////////////////////////////////////////////////////////////////////////
// VARIABLES

	root_number: {
		"undefined": 0,
		"C": 1,
		"C#": 2, "Db": 2,
		"D": 3,
		"D#": 4, "Eb": 4,
		"E": 5,
		"F": 6,
		"F#": 7, "Gb": 7,
		"G": 8,
		"G#": 9, "Ab": 9,
		"A": 10,
		"Bb": 11, "A#": 11,
		"B": 12,
	},
	
	root_symbol: new Array('undefined',
		'C','C#','D','D#','E','F','F#','G','G#','A','Bb','B',
		'C','C#','D','D#','E','F','F#','G','G#','A','Bb','B'),

/////////////////////////////////////////////////////////////////////////////////////////////
// UTILS

translate: function (root)
{
	if (root.length == 1) { return root; }
	
	switch (root)
	{
		case 'C#': return 'Ciss';
		case 'D#': return 'Diss';
		case 'F#': return 'Fiss';
		case 'G#': return 'Giss';
		case 'A#': return 'Aiss';
		default: return root;
	}
},

getRandom: function (i)
{
    return Math.floor(Math.random()*i);
},

parseChords: function (chordstring)
{
	var c_arr = chordstring.split('-');
	var list = new CM.Chordlist("noname");
	var arlen = c_arr.length;
	for (var j = 0; j < arlen; ++j) //each chord in string
	{
		var a_root = c_arr[j].charAt(0);
		var a_chordtype = '';
		var a_chord = new CM.Chord(a_root, a_chordtype);
		var chlen = c_arr[j].length;
		var i = 0;
		for (; i < chlen; ++i) //each char in chord
		{
			if (i == 1 && c_arr[j].charAt(1) == 'b')
			{
				a_root = a_root.concat(c_arr[j].charAt(1));
				a_chord.set_root(CM.root_number[a_root], a_root);
			}
			else if (i == 1 && c_arr[j].charAt(1) == 'i')
			{
				a_root = a_root.concat('#');
				a_chord.set_root(CM.root_number[a_root], a_root);
				i += 2;
			}
			else if (i >= 1)
			{
				a_chordtype = a_chordtype.concat(c_arr[j].charAt(i))
			}
		}
		a_chord.set_chord(a_chordtype);
		list.push(a_chord);
	}
	return list;
},

parse: function (code)
{
	var c_arr = code.split('-');
	var list = new Array();
	var arlen = c_arr.length;
	for (var j = 0; j < arlen; ++j)
	{
		var a_chord = new CM.Chord(CM.root_symbol[0],'');
		switch (c_arr[j].length)
		{
			case 1:
				switch (c_arr[j])
				{
					case 'i':
						a_chord.set_chord('m');
					case 'I':
						a_chord.set_root(1,'C');
						break;
					case 'v':
						a_chord.set_chord('m');
					case 'V':
						a_chord.set_root(8,'G');
						break;
				}
				break;
			case 2:
				if (c_arr[j].charAt(1) == '7')
				{
					a_chord.set_chord('7');
					switch (c_arr[j].charAt(0))
					{
						case 'i':
							a_chord.set_chord('m7');
						case 'I':
							a_chord.set_root(1,'C');
							break;
						case 'v':
							a_chord.set_chord('m7');
						case 'V':
							a_chord.set_root(8,'G');
							break;
					}
				}
				else
				{
					switch (c_arr[j])
					{
						case 'ii':
							a_chord.set_chord('m');
						case 'II':
							a_chord.set_root(3,'D');
							break;
						case 'iv':
							a_chord.set_chord('m');
						case 'IV':
							a_chord.set_root(6,'F');
							break;
						case 'vi':
							a_chord.set_chord('m');
						case 'VI':
							a_chord.set_root(10,'A');
							break;
					}
				}
				break;
			case 3:
				switch (c_arr[j])
				{
					case 'iii':
						a_chord.set_chord('m');
					case 'III':
						a_chord.set_root(5,'E');
						break;
				}
				break;
		}
		list.push(a_chord);
	}
	return list;
},

/////////////////////////////////////////////////////////////////////////////////////////////
// CLASS: CHORD

Chord: function (root_name,chord_name,make_copy)
// class describing a chord
{
	// variables
	this.root_nr = CM.root_number[root_name];
	this.root_name = root_name;
	this.chord_name = chord_name;
	this.tones = new Array();
	this.wrapped_tones;
	
	// methods
	this.fill_wrapped_tones = function()
	{
		this.wrapped_tones = new Array();
		var arlen = this.tones.length;
		for (var j = 0; j < arlen; ++j)
			this.wrapped_tones.push(((this.tones[j] - 1) % 12) + 1);
	};

	this.fill_tones = function()
	{
		this.tones = new Array();
		this.tones.push(this.root_nr);
		
		switch (this.chord_name)
		{
			case '':
				this.tones.push(this.root_nr+4);
				this.tones.push(this.root_nr+7);
				break;
			case 'm':
				this.tones.push(this.root_nr+3);
				this.tones.push(this.root_nr+7);
				break;          
			case 'sus4':
				this.tones.push(this.root_nr+5);
				this.tones.push(this.root_nr+7);
				break;
			case '7':
				this.tones.push(this.root_nr+4);
				this.tones.push(this.root_nr+7);
				this.tones.push(this.root_nr+10);
				break;
			case 'm7':
				this.tones.push(this.root_nr+3);
				this.tones.push(this.root_nr+7);
				this.tones.push(this.root_nr+10);
				break;
			case 'maj7':
				this.tones.push(this.root_nr+4);
				this.tones.push(this.root_nr+7);
				this.tones.push(this.root_nr+11);
				break;
			case 'dim7':
				this.tones.push(this.root_nr+3);
				this.tones.push(this.root_nr+6);
				this.tones.push(this.root_nr+9);
				break;
			case 'sus2':
				this.tones.push(this.root_nr+2);
				this.tones.push(this.root_nr+7);
				break;
			case 'dim':
				this.tones.push(this.root_nr+3);
				this.tones.push(this.root_nr+6);
				break;
			case 'aug':
				this.tones.push(this.root_nr+4);
				this.tones.push(this.root_nr+8);
				break;
			case '2':
				this.tones.push(this.root_nr+2);
				this.tones.push(this.root_nr+4);
				this.tones.push(this.root_nr+7);
				break;
			case '6':
				this.tones.push(this.root_nr+4);
				this.tones.push(this.root_nr+7);
				this.tones.push(this.root_nr+9);
				break;
		}
		this.fill_wrapped_tones();
	};
	
	this.transpose = function(step)
	{
		this.root_nr = ((this.root_nr+11+step) % 12)+1;
		this.root_name = CM.root_symbol[this.root_nr];
		this.fill_tones();
	};
	
	// setters
	this.set_root = function(new_root_nr, new_root_name)
	{
		if (this.root_name == new_root_name) return;
		
		this.root_nr = ((new_root_nr-1) % 12)+1;
		this.root_name = new_root_name;
		this.fill_tones();
	};

	this.set_chord = function(new_chord_name)
	{
		if (this.chord_name == new_chord_name) return;
		
		this.chord_name = new_chord_name;
		this.fill_tones();
	};
	
	this.str = function()
	{
		return this.root_name + this.chord_name;
	};
	
	this.is_undefined = function()
	{
		return this.root_name == "undefined";
	};
	
	// clone
	this.clone = function()
	{
		var nc = new CM.Chord(this.root_name,this.chord_name,1);
		nc.tones = this.tones.slice();
		nc.wrapped_tones = this.wrapped_tones.slice();
		return nc;
	};
	
	// constructor
	if (!make_copy)
		this.fill_tones();
},

/////////////////////////////////////////////////////////////////////////////////////////////
// CLASS: CHORDLIST

Chordlist: function (name, code)
// class describing a list of chords
{
	// variables
	this.list = new Array();
	this.name = name;
	this.current_index = -1;
	
	// setters
	this.add = function(item, index)
	{
		this.list.splice(index,0,item);
		this.current_index = -1;
	};
	
	this.append = this.push = function(item)
	{
		this.list.push(item);
		this.current_index = -1;
	};
	
	this.remove = function(index)
	{
		this.list.splice(index,1);
		this.current_index = -1;
	};
	
	this.switch_items = function(index)
	{
		var temp = this.list[index-1].clone();
		this.list[index-1] = this.list[index].clone();
		this.list[index] = temp;
		this.current_index = -1;
	};
	
	this.step_one = function()
	{
		if (this.list.length < 1) 
			return new CM.Chord("undefined",'');
		this.current_index = (this.current_index + 1) % this.list.length;
		return this.list[this.current_index].clone();
	};

	this.step_random = function()
	{
		if (this.list.length < 1) 
			return new CM.Chord("undefined",'');
		this.current_index += CM.getRandom(this.list.length-1)+1;
		this.current_index = this.current_index % this.list.length;
		return this.list[this.current_index].clone();
	};

	this.make_from_code = function(code)
	{
		if (code == '') return;
		this.list = new Array();
		this.current_index = -1;

		if (code == 'c') return;
		
		var rootnr = 1;
		// fill list
		if (code.charAt(0) == 'C')
		{
			switch (code.charAt(code.length-1))
			{
				case 'b':
					this.list.push(new CM.Chord(CM.root_symbol[rootnr],''));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr+7],''));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr+9],'m'));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr+5],''));
					break;
				case 'x':
					this.list.push(new CM.Chord(CM.root_symbol[rootnr],''));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr+5],''));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr+7],''));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr+9],'m'));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr+4],'7'));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr+2],'m'));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr+4],'m'));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr+7],'7'));
					break;
				case 'm':
					this.list.push(new CM.Chord(CM.root_symbol[rootnr],''));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr+5],''));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr+2],'m'));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr+7],''));
					break;
				case 'n':
					this.list.push(new CM.Chord(CM.root_symbol[rootnr],''));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr+7],''));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr+9],'m'));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr+4],'m'));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr+5],''));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr],''));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr+5],''));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr+7],''));
					break;
				case 'o':
					this.list.push(new CM.Chord(CM.root_symbol[rootnr],'7'));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr+5],'7'));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr],'7'));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr],'7'));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr+5],'7'));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr+5],'7'));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr],'7'));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr],'7'));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr+7],'7'));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr+5],'7'));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr],'7'));
					this.list.push(new CM.Chord(CM.root_symbol[rootnr+7],'7'));
					break;
			}
		}
		else if (code.charAt(0) == 'L')
		{
			switch (code.length)
			{
				case 3:
					for (var i = 1; i <= 12; ++i) { this.list.push(new CM.Chord(CM.root_symbol[i],'sus2')); }
					for (var i = 1; i <= 12; ++i) { this.list.push(new CM.Chord(CM.root_symbol[i],'dim')); }
					for (var i = 1; i <= 12; ++i) { this.list.push(new CM.Chord(CM.root_symbol[i],'aug')); }
					for (var i = 1; i <= 12; ++i) { this.list.push(new CM.Chord(CM.root_symbol[i],'2')); }
					for (var i = 1; i <= 12; ++i) { this.list.push(new CM.Chord(CM.root_symbol[i],'6')); }
				case 2:
					for (var i = 1; i <= 12; ++i) { this.list.push(new CM.Chord(CM.root_symbol[i],'m7')); }
					for (var i = 1; i <= 12; ++i) { this.list.push(new CM.Chord(CM.root_symbol[i],'maj7')); }
					for (var i = 1; i <= 12; ++i) { this.list.push(new CM.Chord(CM.root_symbol[i],'dim7')); }
					for (var i = 1; i <= 12; ++i) { this.list.push(new CM.Chord(CM.root_symbol[i],'sus4')); }
				case 1:
					for (var i = 1; i <= 12; ++i) { this.list.push(new CM.Chord(CM.root_symbol[i],'')); }
					for (var i = 1; i <= 12; ++i) { this.list.push(new CM.Chord(CM.root_symbol[i],'m')); }
					for (var i = 1; i <= 12; ++i) { this.list.push(new CM.Chord(CM.root_symbol[i],'7')); }
			}
		}
		else // custom code
		{
			this.list = CM.parse(code);
		}
	};
	
	this.transpose = function(step)
	{
		var arlen = this.list.length;
		for (var i = 0; i < arlen; ++i)
		{
			this.list[i].transpose(step);
		}
	};
	
	// clone
	this.clone = function()
	{
		
	};
	
	this.get_html = function()
	{
		var s = '\n';
		var arlen = this.list.length;
		for (var i = 0; i < arlen; ++i)
		{
			s += "<option>" + this.list[i].root_name + this.list[i].chord_name + "</option>";
		}
		return s + "\n<option> \n </option>\n";
	};
	
	this.get_liststring = function()
	{
		var s = "";
		var arlen = this.list.length;
		if (arlen > 0)
		{
			s += CM.translate(this.list[0].root_name) + this.list[0].chord_name;
		}
		for (var i = 0; i < arlen; ++i)
		{
			if (i == 0) continue;
			s += "-" + CM.translate(this.list[i].root_name) + this.list[i].chord_name;
		}
		return s;
	};

	// constructor
	if (code) this.make_from_code(code);
},



}
})(); // ending namespace CM


