
// constructor
Instrument = function(config)
{

	this.notes = [ "A","Bb","B","C","C#","D","Eb","E","F","F#","G","G#" ];

	if (typeof(config)!='object') {
		this.config = new Object();
	}
	else {
		this.config = config;
	}
	var default_config = 	{					
							tuning : ['E','A','D','G','B','E'], // standard guitar
							highlight_notes : [],
							num_frets : 16, // the number of frets to show							
							container_id : null,
							container : null,
							chart_container : null,
							document : window.document,
							table_class : 'guitar',
							vert_table_class : 'guitar_vert',
							string_class : 'string'
							};
	// setup config
	for (var i in default_config) {
		if (typeof this.config[i] == 'undefined'){
			this.config[i] = default_config[i];
		}
	}
	
	if (this.config.container && this.config.container!=null) {
		if (typeof this.config.container == 'string') {
			this.container = this.config.document.getElementById(this.config.container);
		}
		else {
			this.container = this.config.container;
		}
	}
	else {
		this.container = this.config.document.getElementById(this.config.container_id);
	}
	if (this.config.chart_container!=null) {
		if (typeof this.config.chart_container == 'string') {
			this.chart_container = this.config.document.getElementById(this.config.chart_container);
		}
		else {
			this.chart_container = this.config.chart_container;
		}
	}
};

// object
Instrument.prototype = 
{
		
	// creates a horizontal fret board table
	renderFretBoardHorizontal : function()
	{
		// for each string create a row
		var strings_table = this.config.document.createElement('table');
		strings_table.setAttribute('cellPadding','0');
		strings_table.setAttribute('cellSpacing','0');		
		strings_table.className = this.config.table_class;
		var tbody = this.config.document.createElement('tbody');

		if (!this.config.left_handed) {
			for (var i=this.config.tuning.length-1; i>=0; i--) {
				tbody.appendChild(
						this.getStringTR(this.config.tuning[i],i)
				);
			}
		}
		else {
			for (var i=0; i<this.config.tuning.length; i++) {
				tbody.appendChild(
						this.getStringTR(this.config.tuning[i],i)
				);
			}
		}
		strings_table.appendChild(tbody);
		
		// and render
		if (this.container!=null) {
			this.container.innerHTML = '';
			this.container.appendChild(strings_table);
		}
	},
	
	// creates a vertical fret board table
	renderFretBoardVertical : function()
	{
		var strings_table = this.config.document.createElement('table');
		strings_table.setAttribute('cellPadding','0');
		strings_table.setAttribute('cellSpacing','0');
		strings_table.className = this.config.vert_table_class;
		var tbody = this.config.document.createElement('tbody');

		// for each fret, create a table row		
		for (var j=0; j<this.config.num_frets+1; j++) {
			tbody.appendChild(
					this.getFretTR(j)
			);
		}
		strings_table.appendChild(tbody);
		
		// and render
		if (this.container!=null) {
			this.container.innerHTML = '';
			this.container.appendChild(strings_table);
		}
	},
	
	getStringTR : function(note,string)
	{
		var string_tr =  this.config.document.createElement('tr');
		string_tr.className = this.config.string_class;
		// for each fret, create a table cell
		for (var j=0; j<this.config.num_frets+1; j++) {
			string_tr.appendChild(
					this.getStringTD(note,string,j)
			);
		}
		return string_tr;
	},	
	
	getFretTR : function(fret,show_fret_marker)
	{
		if (typeof show_fret_marker == 'undefined') {
			var show_fret_marker = true;
		}
		var fret_tr = this.config.document.createElement('tr');
		fret_tr.className = 'fret';
		if (this.config.left_handed) {
			for (var i=this.config.tuning.length-1; i>=0; i--) {
				// for each string, create a new cell
				fret_tr.appendChild(
						this.getStringTD(this.config.tuning[i],i,fret)
				);
			}
		}
		else {
			for (var i=0; i<this.config.tuning.length; i++) {
				// for each string, create a new cell
				fret_tr.appendChild(
						this.getStringTD(this.config.tuning[i],i,fret)
				);
			}
		}
		if (show_fret_marker) {
			var fret_marker = this.config.document.createElement('td');
			fret_marker.innerHTML = 'fret ' + fret;
			fret_marker.className = 'fretmarker marker_' + fret;
			fret_tr.appendChild(fret_marker);
		}
		return fret_tr;
	},
	
	getStringTD : function(note,string,fret)
	{
		var note_td = this.config.document.createElement('td');
		// get the note that this is, which should be the tuning of this string plus j+1
		var note_index = this.noteAddition( note,fret,true );
		var note_name = this.notes[note_index];
		note_td.innerHTML = '<span class="noteName">' + note_name + '</span>';
		if (this.position) {
			// get the fingering
			if (typeof this.fingering[string]!='undefined') {
				if (typeof this.fingering[string][fret]!='undefined') {
					note_td.innerHTML += '<span class="noteFinger">' + 
											this.fingering[string][fret] + 
											'</span>';
				}
			}
		}
		// set the class
		var className = 'string' + string + ' fret fret' + fret + ' note' + note_index;
		if ( (this.position && this.isHighlightedPosition(string,fret)) ||
			 (!this.position && this.isHighlightedNote(note_name))
		) {
			className += ' highlight' + ' note'+note_index+'_highlight';
			if ( fret==0 ) {
				className += ' rootnote';
			}
		}
		if (string==(this.config.tuning.length-1)) {
			className += ' string_last';
		}
		note_td.className = className;
		return note_td;
	},
	
	// creates a vertical fret board table
	renderChordChart : function()
	{
		if (this.position) {
			var chart_table = this.config.document.createElement('table');
			chart_table.setAttribute('cellPadding','0');
			chart_table.setAttribute('cellSpacing','0');
			chart_table.className = this.config.chord_chart_class;
			var tbody = this.config.document.createElement('tbody');
	
			// find out the start and end fret
			var start_fret = end_fret = false;
			for (var i=0; i<this.position.length; i++) {
				if (typeof end_fret=='undefined' || this.position[i]>end_fret) {
					end_fret = this.position[i];
				}
				if (typeof start_fret=='undefined' || this.position[i]<start_fret) {
					start_fret = this.position[i];
				}
			}
			end_fret++;
			start_fret--;
			if (end_fret > this.config.num_frets) {
				end_fret = this.config.num_frets;
			}
			if (start_fret < 0) {
				start_fret = 0;
			}
			if (end_fret < 4) {
				end_fret = 4;
			}
			
			// for each fret, create a table row	
			for (var j=start_fret; j<=end_fret; j++) {
				tbody.appendChild(
						this.getFretTR(j,true)
				);
			}
			chart_table.appendChild(tbody);
			
			// and render
			if (this.chart_container!=null) {
				this.chart_container.innerHTML = '<h3>' + this.chord.name + '</h3>';
				this.chart_container.appendChild(chart_table);
			}
			this.chart_container.style.display = '';
		}
		else {
			this.chart_container.innerHTML = '';
			this.chart_container.style.display = 'none';
		}
	},
	
	isHighlightedNote : function (note)
	{
		for (var i=0; i<this.highlight_notes.length; i++)
		{
			if (this.highlight_notes[i]==note)
				return true;
		}
		return false;
	},
	
	isHighlightedPosition : function(string,fret)
	{
		if (this.position==false) {
			return false;
		}
		else {
			if (typeof this.position[string]=='undefined') {
				return false;
			}
			else {
				return this.position[string]==fret;
			}
		}
	},
	
	noteAddition : function (note, amount, return_index)
	{
		if (typeof return_index == 'undefined') return_index = false;
		// get starting index
		for (var i=0; i<this.notes.length; i++)
		{
			if (note==this.notes[i])
				currentIndex = i;
		}
		var toBeIndex = currentIndex + amount;
        
        if (toBeIndex < 0)
		{
			toBeIndex = toBeIndex + this.notes.length;
		} 
		else if ( toBeIndex > (this.notes.length-1) )
		{
			while ( toBeIndex > (this.notes.length-1) )
			{
				toBeIndex = toBeIndex - this.notes.length;
			}
		}
        return (return_index) ? toBeIndex : this.notes[toBeIndex];
	},
	
	array_search : function(needle,haystack)
	{
		for( var i=0; i<haystack.length; i++)
			if (haystack[i]==needle)
				return i;
		return -1;
	}

}