// *******************
// Initialization Area
// *******************
var MajorChords = ["", "7", "maj7", "m", "m7", "dim", "dim7", "aug", "sus2", "sus4", "add9", "madd9"];
var MajorChordsInt = ["4,3", "4,3,3", "4,3,4", "3,4", "3,4,3", "3,3", "3,3,3", "4,4", "2,5", "5,2", "4,3,7", "3,11"];

var ExtendedChords = ["5", "6", "6/9", "maj9", "maj11", "maj13", "2", "m6", "m6/9", "mmaj7", "mmaj9", "m9", "m11", "m13","7/6",  "9", "9/6", "11", "13", "7sus4"]; 
var ExtendedChordsInt = ["7", "4,3,2", "4,5,5", "4,7,3", "7,4,6", "4,7,10", "2,2,3", "3,4,2", "3,6,5", "3,4,4", "3,8,3", "3,7,4", "3,7,7", "3,7,11", "4,5,1", "4,6,4", "9,1,4", "7,3,7", "7,3,11", "5,2,3"];

var ObscureChords = ["-5", "maj7+5","m7-5", "7-9", "7+9", "7-5", "7+5", "9-5", "9+5", "11-9", "13-9", "13+11", "7/13", "-9+5", "-9+11", "-9-5", "+11"]; 
var ObscureChordsInt = ["4,2", "4,4,3", "3,3,4", "4,6,3", "4,6,5", "4,2,4", "4,4,2", "6,4,4", "8,2,4", "10,3,4", "10,3,8", "10,8,3", "4,6,11", "8,2,3", "10,3,5", "6,4,3", "10,4,4"];

var AllMajorChords = new Array(144);
var AllExtendedChords = new Array(240);
var AllObscureChords = new Array(204);

NoteList = ["A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"];

var bLock1 = "FALSE";
var bLock2 = "FALSE";
var bLock3 = "FALSE";

var bMelodyStringChange = "FALSE";

var strValue = "<font size=\"3\"><b>o</b></font>";	// Fret placement indicator
var strBlank = "<font size=\"3\"><b>&nbsp</b></font>";	// Fret placement indicator


// Establish fret indices that are distance from open string offset
Fret_Indices = new Array(0, 2, 3, 4, 5, 7, 9, 10, 11, 0, 2, 3, 4, 5, 7, 9, 10, 11, 0, 2, 3, 4, 5);
var Bass_List = new Array("", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "");
var Middle_List = new Array("", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "");
var Melody_List = new Array("", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "");
var Mode_List = new Array("", "m", "dim", "aug", "7", "maj7");

List1 = new Array(20);
List2 = new Array(20);
List3 = new Array(20);

// Initialize open tuning offsets to NoteList[]
var nOpenBassString = 5;
var nOpenMiddleString = 0;
var nOpenMelodyString = 5;


var nMelodyIndex = 0;
var nMiddleIndex = 0;
var nBassIndex = 0;



// *******************
// Functions
// *******************

function init()
{
	var i;
	var j;
	var index;
	var string = new String(10);
	var OutputString = new String(10);
	var pattern = /\w+/g;
	var NoteIndex;

	// Populate AllMajorChords(). Beginning with 'A' and repeating for all root notes.
	index = 0;
	for(i=0; i<12; i++)
	{
		// Get each set of major chord intervals
		for(j=0; j<MajorChords.length; j++)
		{
			string = MajorChordsInt[j];

			// Parse each interval - pattern "n[n],n[n],n[n]" -> n1 n2 n3
			NoteIndex = i+0;
			OutputString = NoteIndex + " ";
			var token = pattern.exec(string);
			while(token != null)
			{
				NoteIndex += parseInt(token[0]);
				NoteIndex %= 12;
				OutputString += NoteIndex + " ";
				token = pattern.exec(string);
			}
			AllMajorChords[index] = OutputString;
			++index;
		}
	}
			
	// Populate AllExtendedChords(). Beginning with 'A' and repeating for all root notes.
	index = 0;
	for(i=0; i<12; i++)
	{
		// Get each set of major chord intervals
		for(j=0; j<ExtendedChords.length; j++)
		{
			string = ExtendedChordsInt[j];

			// Parse each interval - pattern "n[n],n[n],n[n]" -> n1 n2 n3
			NoteIndex = i+0;
			OutputString = NoteIndex + " ";
			var token = pattern.exec(string);
			while(token != null)
			{
				NoteIndex += parseInt(token[0]);
				NoteIndex %= 12;
				OutputString += NoteIndex + " ";
				token = pattern.exec(string);
			}
			AllExtendedChords[index] = OutputString;
			++index;
		}
	}		
			
	// Populate AllObscureChords(). Beginning with 'A' and repeating for all root notes.
	index = 0;
	for(i=0; i<12; i++)
	{
		// Get each set of major chord intervals
		for(j=0; j<ObscureChords.length; j++)
		{
			string = ObscureChordsInt[j];

			// Parse each interval - pattern "n[n],n[n],n[n]" -> n1 n2 n3
			NoteIndex = i+0;
			OutputString = NoteIndex + " ";
			var token = pattern.exec(string);
			while(token != null)
			{
				NoteIndex += parseInt(token[0]);
				NoteIndex %= 12;
				OutputString += NoteIndex + " ";
				token = pattern.exec(string);
			}
			AllObscureChords[index] = OutputString;
			++index;
		}
	}		
	Fret_Array_Update();

}

function Fret_Array_Update()
{
	for(i=0; i<23; i++)
	{
		nBassIndex = (nOpenBassString + Fret_Indices[i])%12;
		nMiddleIndex = (nOpenMiddleString + Fret_Indices[i])%12;
		nMelodyIndex = (nOpenMelodyString + Fret_Indices[i])%12;
		Bass_List[i] = NoteList[nBassIndex];
		Middle_List[i] = NoteList[nMiddleIndex];
		Melody_List[i] = NoteList[nMelodyIndex];
	}
}

function Display_Chord()
{
	var nNote = parseInt(Chord_Select.value);
	var nModeMaj = parseInt(Mode_Select_Major.value);
	var nModeExt = parseInt(Mode_Select_Extended.value);
	var nModeObs = parseInt(Mode_Select_Obscure.value);
	var note_sequence = "";
	Note1.value = "";
	Note2.value = "";
	Note3.value = "";
	Note4.value = "";

	Reset_Fretboard1();

	nOpenBassString = (parseInt(Bass_Select_Menu.value)+36)% 12;
	nOpenMiddleString = (parseInt(Middle_Select_Menu.value)+36)% 12;
	nOpenMelodyString = (parseInt(Melody_Select_Menu.value)+36)% 12;
	Fret_Array_Update();
			
	if(nModeMaj >= 0)
	{
		Mode_Select_Extended.value = -1;
		Mode_Select_Obscure.value = -1;
		note_sequence = MajorChordsInt[nModeMaj];
		Display_Notes(nNote, note_sequence);
	}
	else
	{
		if(nModeExt >= 0)
		{	
			Mode_Select_Obscure.value = -1;
			note_sequence = ExtendedChordsInt[nModeExt];
			Display_Notes(nNote, note_sequence);
		}
		else
		{
			note_sequence = ObscureChordsInt[nModeObs];
			Display_Notes(nNote, note_sequence);
		}
	}

	var Value = Note1.value;
	var strFormat = "<b><font color=\"#CC3300\" size=\"2\"><i>" + Value + "</i></font></b>";
	Table1_Update(strFormat, Value);
	// Display Note 2 on all three strings
	Value = Note2.value;
	strFormat = "<b><font color=\"#339933\" size=\"2\">" + Value + "</font></b>";
	Table1_Update(strFormat, Value);

	// Display Note 3 on all three strings
	Value = Note3.value;
	strFormat = "<b><font color=\"#3366CC\" size=\"2\">" + Value + "</font></b>";
	Table1_Update(strFormat, Value);

	// Display Note 4 on all three strings
	if(Note4.value != "")
	{
		Value = Note4.value;
		strFormat = "<b><font color=\"#9900FF\" size=\"2\">" + Value + "</font></b>";
		Table1_Update(strFormat, Value);
	}

	strText = "<font size=\"2\">Root = </font><b><font color=\"#CC3300\" size=\"2\"><i>" + Note1.value + "</i></font></b>, "
		+ "<font size=\"2\">2nd Note = </font><b><font color=\"#339933\" size=\"2\">" + Note2.value + "</font></b>, "
		+ "<font size=\"2\">3rd Note = </font><b><font color=\"#3366CC\" size=\"2\">" + Note3.value + "</font></b>";
	if(Note4.value != "")
		strText += ", <font size=\"2\">4th Note= </font><b><font color=\"#9900FF\" size=\"2\">" + Note4.value + "</font></b>";
		
	var x=document.getElementById('TableOne').rows[4].cells;
	x[0].innerHTML=strText;

}

function Display_Unknown_Chord(nMode)
{
	var Index1 = Chord_Select_Major.selectedIndex;
	var Index2 = Chord_Select_Extended.selectedIndex;
	var Index3 = Chord_Select_Obscure.selectedIndex;
	switch(nMode)
	{
		case 1: ChordString = Chord_Select_Major.options[Index1].text;
				break;
		case 2: ChordString = Chord_Select_Extended.options[Index2].text;
				break;
		case 3: ChordString = Chord_Select_Obscure.options[Index3].text;
				break;
	}

	var Note = ChordString.charAt(0);
	var Chord = "";
	if(ChordString.charAt(1) == "#")
	{
		Note += "#";
		Chord = ChordString.substring(2);
	}
	else
		Chord = ChordString.substring(1);

	var nNote;

	// Get Note Index from NoteList
	for(i=0; i<NoteList.length; i++)
	{
		if(NoteList[i] == Note)
			nNote = i;
	}

	// Get chord index
	var note_sequence = "";
	switch(nMode)
	{
		case 1: for(i=0; i<MajorChords.length; i++)
				{
					if(MajorChords[i] == Chord)
					{
						note_sequence = MajorChordsInt[i];
					}
				}
				break;
		case 2: for(i=0; i<ExtendedChords.length; i++)
				{
					if(ExtendedChords[i] == Chord)
					{
						note_sequence = ExtendedChordsInt[i];
					}
				}
				break;
		case 3: for(i=0; i<ObscureChords.length; i++)
				{
					if(ObscureChords[i] == Chord)
					{
						note_sequence = ObscureChordsInt[i];
					}
				}
				break;
	}

	Note1.value = "";
	Note2.value = "";
	Note3.value = "";
	Note4.value = "";

	Reset_Fretboard1();

	nOpenBassString = (parseInt(Bass_Select_Menu.value)+36)% 12;
	nOpenMiddleString = (parseInt(Middle_Select_Menu.value)+36)% 12;
	nOpenMelodyString = (parseInt(Melody_Select_Menu.value)+36)% 12;
	Fret_Array_Update();
			
	Display_Notes(nNote, note_sequence);

	var Value = Note1.value;
	var strFormat = "<b><font color=\"#CC3300\" size=\"2\"><i>" + Value + "</i></font></b>";
	Table1_Update(strFormat, Value);
	// Display Note 2 on all three strings
	Value = Note2.value;
	strFormat = "<b><font color=\"#339933\" size=\"2\">" + Value + "</font></b>";
	Table1_Update(strFormat, Value);

	// Display Note 3 on all three strings
	Value = Note3.value;
	strFormat = "<b><font color=\"#3366CC\" size=\"2\">" + Value + "</font></b>";
	Table1_Update(strFormat, Value);

	// Display Note 4 on all three strings
	if(Note4.value != "")
	{
		Value = Note4.value;
		strFormat = "<b><font color=\"#9900FF\" size=\"2\">" + Value + "</font></b>";
		Table1_Update(strFormat, Value);
	}

	strText = "<font size=\"2\">Root = </font><b><font color=\"#CC3300\" size=\"2\"><i>" + Note1.value + "</i></font></b>, "
		+ "<font size=\"2\">2nd Note = </font><b><font color=\"#339933\" size=\"2\">" + Note2.value + "</font></b>, "
		+ "<font size=\"2\">3rd Note = </font><b><font color=\"#3366CC\" size=\"2\">" + Note3.value + "</font></b>";
	if(Note4.value != "")
		strText += ", <font size=\"2\">4th Note= </font><b><font color=\"#9900FF\" size=\"2\">" + Note4.value + "</font></b>";
		
	var x=document.getElementById('TableOne').rows[4].cells;
	x[0].innerHTML=strText;

}

// Look up Notes in chord and return
function Display_Notes(nNote, note_sequence)
{
	var pattern = /\w+/g;
	var nCounter =  1;

	var NoteIndex = nNote + 0;
	OutputString = NoteList[NoteIndex] + " ";

	// Display Note 1 on all three strings
	Note1.value = NoteList[NoteIndex];

	++nCounter;
	var token = pattern.exec(note_sequence);
 
	while(token != null)
	{
		NoteIndex += parseInt(token[0]);
		NoteIndex %= 12;
		switch(nCounter)
		{
			case 2: Note2.value = NoteList[NoteIndex];
					break;
			case 3: Note3.value = NoteList[NoteIndex];
					break;
			case 4: Note4.value = NoteList[NoteIndex];
					break;
			default: break;
		}
		token = pattern.exec(note_sequence);
		++nCounter;
	}
}


function Reset_Fretboard1()
{
	for(j=1; j<=3; j++)
	{	
		var x=document.getElementById('TableOne').rows[j].cells;
		for(i=0;i<23;i++)
		{
			var strContent = "&nbsp\;";
			x[i].innerHTML=strContent;
		}
	}
}

function Table1_Update(strFormat, Value)
{
	for(i=0; i<23; i++)
	{
		var x=document.getElementById('TableOne').rows[1].cells;
		if(Bass_List[i] == Value)
		{
			x[i].innerHTML=strFormat;
       }
		x=document.getElementById('TableOne').rows[2].cells;
		if(Middle_List[i] == Value)
		{
			x[i].innerHTML=strFormat;
       }
		x=document.getElementById('TableOne').rows[3].cells;
		if(Melody_List[i] == Value)
		{
			x[i].innerHTML=strFormat;
       }
	}
}

function FindChords()
{
	var strChord = "";
	var Select1 = parseInt(Note_Select1.value);
	var Select2 = parseInt(Note_Select2.value);
	var Select3 = parseInt(Note_Select3.value);
	var Select4 = parseInt(Note_Select4.value);
	var KeyIndex = Select1;
	var SearchIndex;

	// Clear Select lists
	for(i=Chord_Select_Major.options.length; i >= 0; i--)
		Chord_Select_Major.options[i] = null;
	for(i=Chord_Select_Extended.options.length; i >= 0; i--)
		Chord_Select_Extended.options[i] = null;
	for(i=Chord_Select_Obscure.options.length; i >= 0; i--)
		Chord_Select_Obscure.options[i] = null;

	// Initialize Select lists
	Chord_Select_Major[0] = new Option("---","---");
	Chord_Select_Extended[0] = new Option("---","---");
	Chord_Select_Obscure[0] = new Option("---","---");


	// Display all major chords
	var nBlockIndex = AllMajorChords.length/12;	
	var n=0;
	for(i=0; i<AllMajorChords.length;i++)
	{
		SearchIndex = (i + Select1*MajorChords.length)%AllMajorChords.length;
		ChordString = AllMajorChords[SearchIndex];
		if(Select1 >= 0 && Select2 < 0 && Select3 < 0 && Select4 < 0)
		{
			if( IsPresent(Select1, ChordString ) == "TRUE")
			{
				var Note = Math.floor(SearchIndex/MajorChords.length);
				strChord = NoteList[Note] + MajorChords[i%MajorChords.length];
				Chord_Select_Major[n++] = new Option(strChord, strChord);
			}
		}
		if(Select1 >= 0 && Select2 >= 0 && Select3 < 0 && Select4 < 0)
		{
			if( IsPresent2(Select1, Select2, ChordString) == "TRUE")
			{
				var Note = Math.floor(SearchIndex/MajorChords.length);
				strChord = NoteList[Note] + MajorChords[i%MajorChords.length];
				Chord_Select_Major[n++] = new Option(strChord, strChord);
			}
		}
		if(Select1 >= 0 && Select2 >= 0 && Select3 >= 0 && Select4 < 0)
		{
			if( IsPresent3(Select1, Select2, Select3, ChordString) == "TRUE")
			{
				var Note = Math.floor(SearchIndex/MajorChords.length);
				strChord = NoteList[Note] + MajorChords[i%MajorChords.length];
				Chord_Select_Major[n++] = new Option(strChord, strChord);
			}
		}
		if(Select1 >= 0 && Select2 >= 0 && Select3 >= 0 && Select4 >= 0)
		{
			if( IsPresent4(Select1, Select2, Select3, Select4, ChordString) == "TRUE")
			{
				var Note = Math.floor(SearchIndex/MajorChords.length);
				strChord = NoteList[Note] + MajorChords[i%MajorChords.length];
				Chord_Select_Major[n++] = new Option(strChord, strChord);
			}
		}
	}

	// Display all extended chords
	nBlockIndex = AllExtendedChords.length/12;	
	n=0;
	for(i=0; i<AllExtendedChords.length;i++)
	{
		SearchIndex = (i + Select1*ExtendedChords.length)%AllExtendedChords.length;
		ChordString = AllExtendedChords[SearchIndex];
		if(Select1 >= 0 && Select2 < 0 && Select3 < 0 && Select4 < 0)
		{
			if( IsPresent(Select1, ChordString) == "TRUE")
			{
				var Note = Math.floor(SearchIndex/ExtendedChords.length);
				strChord = NoteList[Note] + ExtendedChords[i%ExtendedChords.length];
				Chord_Select_Extended[n++] = new Option(strChord, strChord);
			}
		}
		if(Select1 >= 0 && Select2 >= 0 && Select3 < 0 && Select4 < 0)
		{
			if( IsPresent2(Select1, Select2, ChordString) == "TRUE")
			{
				var Note = Math.floor(SearchIndex/ExtendedChords.length);
				strChord = NoteList[Note] + ExtendedChords[i%ExtendedChords.length];
				Chord_Select_Extended[n++] = new Option(strChord, strChord);
			}
		}
		if(Select1 >= 0 && Select2 >= 0 && Select3 >= 0 && Select4 < 0)
		{
			if( IsPresent3(Select1, Select2, Select3, ChordString) == "TRUE")
			{
				var Note = Math.floor(SearchIndex/ExtendedChords.length);
				strChord = NoteList[Note] + ExtendedChords[i%ExtendedChords.length];
				Chord_Select_Extended[n++] = new Option(strChord, strChord);
			}
		}
		if(Select1 >= 0 && Select2 >= 0 && Select3 >= 0 && Select4 >= 0)
		{
			if( IsPresent4(Select1, Select2, Select3, Select4, ChordString) == "TRUE")
			{
				var Note = Math.floor(SearchIndex/ExtendedChords.length);
				strChord = NoteList[Note] + ExtendedChords[i%ExtendedChords.length];
				Chord_Select_Extended[n++] = new Option(strChord, strChord);
			}
		}
	}

	// Display all obscure chords
	nBlockIndex = AllExtendedChords.length/12;	
	n=0;
	for(i=0; i<AllObscureChords.length;i++)
	{
		SearchIndex = (i + Select1*ObscureChords.length)%AllObscureChords.length;
		ChordString = AllObscureChords[SearchIndex];
		if(Select1 >= 0 && Select2 < 0 && Select3 < 0 && Select4 < 0)
		{
			if( IsPresent(Select1, ChordString) == "TRUE")
			{
				var Note = Math.floor(SearchIndex/ObscureChords.length);
				strChord = NoteList[Note] + ObscureChords[i%ObscureChords.length];
				Chord_Select_Obscure[n++] = new Option(strChord, strChord);
			}
		}
		if(Select1 >= 0 && Select2 >= 0 && Select3 < 0 && Select4 < 0)
		{
			if( IsPresent2(Select1, Select2, ChordString) == "TRUE")
			{
				var Note = Math.floor(SearchIndex/ObscureChords.length);
				strChord = NoteList[Note] + ObscureChords[i%ObscureChords.length];
				Chord_Select_Obscure[n++] = new Option(strChord, strChord);
			}
		}
		if(Select1 >= 0 && Select2 >= 0 && Select3 >= 0 && Select4 < 0)
		{
			if( IsPresent3(Select1, Select2, Select3, ChordString) == "TRUE")
			{
				var Note = Math.floor(SearchIndex/ObscureChords.length);
				strChord = NoteList[Note] + ObscureChords[i%ObscureChords.length];
				Chord_Select_Obscure[n++] = new Option(strChord, strChord);
			}
		}
		if(Select1 >= 0 && Select2 >= 0 && Select3 >= 0 && Select4 >= 0)
		{
			if( IsPresent4(Select1, Select2, Select3, Select4, ChordString) == "TRUE")
			{
				var Note = Math.floor(SearchIndex/ObscureChords.length);
				strChord = NoteList[Note] + ObscureChords[i%ObscureChords.length];
				Chord_Select_Extended[n++] = new Option(strChord, strChord);
			}
		}
	}

}


/*
 * Input: index to particular note; A = 0
 *        index to major chords; Maj, 7th, maj7, etc.
 */
function IsPresent( nNoteIndex, ChordString)
{
	var pattern = /\w+/g;
	var token = pattern.exec(ChordString);
	if(nNoteIndex == token)
		return "TRUE";
	while (token != null)
	{
		token = pattern.exec(ChordString);
		if(nNoteIndex == token)
			return "TRUE";
	}
	return "FALSE";
}

/*
 * Input: index to particular note; A = 0
 *        index to major chords; Maj, 7th, maj7, etc.
 */
function IsPresent2( nNoteIndex1, nNoteIndex2, ChordString)
{
	var pattern = /\w+/g;
	var bFound1 = "F";
	var bFound2 = "F";
	var token = pattern.exec(ChordString);
	if(nNoteIndex1 == token)
		bFound1 = "T";
	if(nNoteIndex2 == token)
		bFound2 = "T";
	while (token != null)
	{
		token = pattern.exec(ChordString);
		if(nNoteIndex1 == token)
			bFound1 = "T";
		if(nNoteIndex2 == token)
			bFound2 = "T";
	}

	if(bFound1 == "T" && bFound2 == "T")
		return "TRUE";
	else
		return "FALSE";
}

/*
 * Input: index to particular note; A = 0
 *        index to major chords; Maj, 7th, maj7, etc.
 */
function IsPresent3( nNoteIndex1, nNoteIndex2, nNoteIndex3, ChordString)
{
	var pattern = /\w+/g;
	var bFound1 = "F";
	var bFound2 = "F";
	var bFound3 = "F";
	var token = pattern.exec(ChordString);
	if(nNoteIndex1 == token)
		bFound1 = "T";
	if(nNoteIndex2 == token)
		bFound2 = "T";
	if(nNoteIndex3 == token)
		bFound3 = "T";
	while (token != null)
	{
		token = pattern.exec(ChordString);
		if(nNoteIndex1 == token)
			bFound1 = "T";
		if(nNoteIndex2 == token)
			bFound2 = "T";
		if(nNoteIndex3 == token)
			bFound3 = "T";
	}

	if(bFound1 == "T" && bFound2 == "T" && bFound3 == "T")
		return "TRUE";
	else
		return "FALSE";
}

/*
 * Input: index to particular note; A = 0
 *        index to major chords; Maj, 7th, maj7, etc.
 */
function IsPresent4( nNoteIndex1, nNoteIndex2, nNoteIndex3, nNoteIndex4, ChordString)
{
	var pattern = /\w+/g;
	var bFound1 = "F";
	var bFound2 = "F";
	var bFound3 = "F";
	var bFound4 = "F";
	var token = pattern.exec(ChordString);
	if(nNoteIndex1 == token)
		bFound1 = "T";
	if(nNoteIndex2 == token)
		bFound2 = "T";
	if(nNoteIndex3 == token)
		bFound3 = "T";
	if(nNoteIndex4 == token)
		bFound4 = "T";
	while (token != null)
	{
		token = pattern.exec(ChordString);
		if(nNoteIndex1 == token)
			bFound1 = "T";
		if(nNoteIndex2 == token)
			bFound2 = "T";
		if(nNoteIndex3 == token)
			bFound3 = "T";
		if(nNoteIndex4 == token)
			bFound4 = "T";
	}

	if(bFound1 == "T" && bFound2 == "T" && bFound3 == "T" && bFound4 == "T")
		return "TRUE";
	else
		return "FALSE";
}
