//constants
var STATUS_RUNNING = 1;
var STATUS_STOPPED = 2;
var EXERCISE_TYPE_INTERVALS = 1;
var EXERCISE_TYPE_CHORDS = 2;
var EXERCISE_TYPE_MELODIES = 4;
var EXERCISE_TYPE_RSECTION = 8;
var SEQUENCE_TYPE_MELODIC = 1;
var SEQUENCE_TYPE_HARMONIC = 2;
var SEQUENCE_TYPE_RANDOM = 4;
var DIRECTION_ASCENDING = 1;
var DIRECTION_DESCENDING = 2;
var DIRECTION_RANDOM = 4;
var DIRECTION_CIRCLE_4_UP = 8;
var DIRECTION_CIRCLE_5_UP = 16;
var DIRECTION_CIRCLE_4_UP_HALF = 32;
var DIRECTION_CIRCLE_5_UP_HALF = 64;
var DIRECTION_CIRCLE_4_RANDOM_3 = 128;
var DIRECTION_CIRCLE_4_RANDOM_6 = 256;
var DIRECTION_CIRCLE_4_RANDOM_12 = 512;
var PLAY_MODE_MANUAL = 1;
var PLAY_MODE_AUTO = 2;
var PLAY_MODE_SING = 4;
var MELODY_NOTE_TYPE_NOTE = 1;
var MELODY_NOTE_TYPE_SCALE_MAJOR = 2;
var MELODY_NOTE_TYPE_SCALE_MINOR = 8;
var MELODY_NOTE_TYPE_SCALE_MAJOR_PENTATONIC = 16;
var MELODY_NOTE_TYPE_SCALE_MINOR_PENTATONIC = 32;
var MELODY_NOTE_TYPE_SCALE_BLUES = 64;
var MELODY_NOTE_TYPE_SCALE_WHOLETONE = 128;
var MELODY_NOTE_TYPE_SCALE_CHROMATIC = 256;
var MELODY_NOTE_TYPE_LICK_JAZZ = 512;
var MELODY_NOTE_TYPE_LICK_SONG = 1024;
var CALLANDRESPONSE_TYPE_LICK_JAZZ = 512;
var CALLANDRESPONSE_TYPE_LICK_SONG = 1024;
var PROGRESSION_TYPE_MAJOR_7 = 1;
var PROGRESSION_TYPE_DOMINANT_7 = 2;
var PROGRESSION_TYPE_MINOR_7 = 4;
var PROGRESSION_TYPE_HALF_DIMINISHED_7 = 8;
var PROGRESSION_TYPE_DIMINISHED_7 = 16;
var PROGRESSION_TYPE_BLUES_MAJOR = 64;
var PROGRESSION_TYPE_BLUES_MINOR = 128;
var PROGRESSION_TYPE_251_MAJOR = 256;
var PROGRESSION_TYPE_251_MINOR = 512;
var PROGRESSION_TYPE_RHYTHMCHANGES = 1024;  
var PROGRESSION_TYPE_CHEROKEE = 4096;  
var INSTRUMENT_PIANO = 1;
var INSTRUMENT_BASS = 2;
var INSTRUMENT_RIDE = 4;
var INSTRUMENT_HIHAT = 8;
var CADENCE_TYPE_FOLLOW_KEY = 'FOLLOW_KEY';

var ERROR_NO_OPTIONS_SELECTED = 12;

var isKeyboardActivated = false;

var sequencerTimeout;
var sequencerTimeoutInterval = 1000;
var status = STATUS_STOPPED;
var activePanel = null;

var bPlayed = false;
var bPreventTabChange = false;

var appletTestCount = 0;
function startAppletTest() {    
    setTimeout('testApplet()', 2500);
}

var repeatBtnName = "repeat";
var playBtnName = "play";

var isMac = false;
if (navigator.appVersion.toLowerCase().indexOf('mac') != -1) {
	isMac = true;
}

function setMidiDefault() {
	if (isMac && false) {
		document.getElementById('useQuickTime').selectedIndex = 1;
	} else {
		document.getElementById('useQuickTime_div').style.display = 'none';
	}
}

function testApplet() {
    var isActive = false;

    try {
        if (document.EarTrainer.isActive()) {
            document.getElementById('loadingDiv').style.display = 'none';
            document.getElementById('tabContainer').style.visibility = 'visible';
            isActive = true;
            sliderInit();
            init();
        }
    } catch (exception) { }

    if (!isActive) {
        if (appletTestCount < 50) { //limit the number of attempts
            ++appletTestCount;
            startAppletTest();
        } else {
            document.getElementById('loadingDiv').style.display = 'none';
            document.getElementById('loadingFailedDiv').style.display = 'block';
            document.getElementById('loadingFailedDiv').style.visibility = 'visible';
        }
    }
}
 
function init() {

	setMidiDefault();

    setModulationIntervals();
    setModulationDirection();
    //setModulationRepeat();
    setIntervals();
    setChords();
    setMelodyNoteLength();
    setMelodyLickMeasureLength();
    setMelodyNotes();
    setRSectionKeys();
    setRSectionProgressionTypes();
    setRSectionInstruments();
    setRSectionMeasureCount();
    setRSectionRandomizedBeatCount();
    setTempo();
    setNoteSize_Melodic();
    setNoteSize_Harmonic();
    setNoteSustain();
    setIntervalDirection();
    setIntervalSequenceType();
    setInstrument();
    setKeyOffset();
    setCadenceType();
    setPlayMode();
    setAutoPlayRepeat();
    setShowFirstNote();
    setDelayResults();
    setRootNote();
    setExerciseTypes();
    setCallAndResponseNoteCount();
    setCallAndResponseMeasureLength();
    //setAutoPlayWait();
    //setResultsWait();
    //setDoAutoTiming();
    setModulationWithRest();
    setKeyboardActivation();
    
    if (isMac) {
		setUseQuickTime();
	}
}

function setPreventTabChange(bValue) {
    bPreventTabChange = bValue;
}

function showHideTab(tabNumber, divNameToHide) {

    if (bPreventTabChange) {
        bPreventTabChange = false; //reset it
        return divNameToHide; //return same 'old' tab
    } else {

        if (divNameToHide != null) {
            //hide
            document.getElementById(divNameToHide).style.display = 'none';
            document.getElementById(divNameToHide + 'Title').style.background = '#888 url(tabs_back.gif) repeat-x';
            document.getElementById(divNameToHide + 'Title').style.color = '#fff';
        }
        
        var divNameToShow = 'tab_' + tabNumber;
        
        //show
        document.getElementById(divNameToShow).style.display = 'block';
        document.getElementById(divNameToShow + 'Title').style.background = '#fff';
        document.getElementById(divNameToShow + 'Title').style.color = '#888';

		activePanel = divNameToShow;
		setTabWarning(tabNumber);

        return activePanel;
    }

} //showHideTab


function playStop() {
    document.EarTrainer.playStop();       
}

function playNext() {

    setPlayMode(); //make sure we set the real playmode

    var errorCode = document.EarTrainer.playNext();

    if (errorCode == 0) {
        bPlayed = true;
    } else {
        bPlayed = false;
    }
    checkAppletStatus();
}

function playRepeat(sequenceType) {
    document.EarTrainer.setPlayMode(PLAY_MODE_MANUAL); //set playmode to manual
    document.EarTrainer.playRepeat(sequenceType);
    checkAppletStatus();
}

function playExample(exerciseType, example) {
	var inversions = "";
	if (exerciseType == EXERCISE_TYPE_CHORDS) {
		inversions = getChord_inversions();
	}

	document.EarTrainer.playExample(Number(exerciseType), example, inversions);
}

function checkAppletStatus() {
    status = document.EarTrainer.getStatus();

    if (status == STATUS_RUNNING) {
        sequencerTimeout = setTimeout('checkAppletStatus()', sequencerTimeoutInterval);    
        document.getElementById('playStop').src = "btn_stop.gif";
    } else if (status == STATUS_STOPPED) {
        document.getElementById('playStop').src = "btn_stop_off.gif";
    }

    if (bPlayed) {
        document.getElementById('playRepeatHarmonic').src = "btn_" + repeatBtnName + "_harmonic.gif";
        document.getElementById('playRepeatMelodic').src = "btn_" + repeatBtnName + "_melodic.gif";
    } else {
        document.getElementById('playRepeatHarmonic').src = "btn_" + repeatBtnName + "_harmonic_off.gif";
        document.getElementById('playRepeatMelodic').src = "btn_" + repeatBtnName + "_melodic_off.gif";
    }
}

function setPlayMode() {
    document.EarTrainer.setPlayMode(document.getElementById('playMode').value);

    if (Number(document.getElementById('playMode').value) == PLAY_MODE_SING) {
        repeatBtnName = "play";
        playBtnName = "sing";
        document.getElementById('playNext').src = "btn_next.gif";
    } else {
        repeatBtnName = "repeat";
        playBtnName = "play";
        document.getElementById('playNext').src = "btn_play.gif";
    }

    checkAppletStatus(); //forces the button changes
}

function setAutoPlayWait() {
    document.EarTrainer.setAutoPlayWait(document.getElementById('autoPlayWait').value);
}

function setAutoPlayRepeat() {
    document.EarTrainer.setAutoPlayRepeat(Number(document.getElementById('autoPlayRepeat').value));
}

function setResultsWait() {
    document.EarTrainer.setResultsWait(document.getElementById('resultsWait').value);
}

function setShowFirstNote() {
    if (document.getElementById('showFirstNote').checked) {
        document.EarTrainer.setShowFirstNote(true);
    } else {
        document.EarTrainer.setShowFirstNote(false);
    }
}

function setDelayResults() {
    if (document.getElementById('delayResults').checked) {
        document.EarTrainer.setDelayResults(true);
    } else {
        document.EarTrainer.setDelayResults(false);
    }
}

function setDoAutoTiming() {
    if (document.getElementById('doAutoTiming').value == "true") {
        document.EarTrainer.setDoAutoTiming(true);
    } else {
        document.EarTrainer.setDoAutoTiming(false);
        setResultsWait();
        setAutoPlayWait();
    }
}

function setKeyOffset() {
    document.EarTrainer.setKeyOffsetAndOctave(document.getElementById('keyOffset').value);
}

function setCadenceType() {
    document.EarTrainer.setCadenceType(document.getElementById('cadenceType').value);
}

function setUseQuickTime() {
	/*
	if (document.getElementById('useQuickTime').value == "true") {
		document.EarTrainer.setUseQuickTime(true);
	} else {
		document.EarTrainer.setUseQuickTime(false);
	}
	*/
}

function setTempo() {
    //document.EarTrainer.setTempo(document.getElementById('tempo').value);
    document.EarTrainer.setTempo(slider_value);
}

function setNoteSize_Melodic() {
    document.EarTrainer.setNoteSize(SEQUENCE_TYPE_MELODIC, Number(document.getElementById('noteSize_melodic').value));
}

function setNoteSize_Harmonic() {
    document.EarTrainer.setNoteSize(SEQUENCE_TYPE_HARMONIC, Number(document.getElementById('noteSize_harmonic').value));
}

function setNoteSustain() {
    document.EarTrainer.setNoteSustain(Number(document.getElementById('noteSustain').value));
}

function setRootNote() {
    document.EarTrainer.setRootNote(EXERCISE_TYPE_INTERVALS, document.getElementById('interval_rootNote').value);
    document.EarTrainer.setRootNote(EXERCISE_TYPE_CHORDS, document.getElementById('chord_rootNote').value);
}

function setIntervalDirection() {
    document.EarTrainer.setDirection(EXERCISE_TYPE_INTERVALS, Number(document.getElementById('interval_direction').value)); 
}

function setIntervalSequenceType() {
    document.EarTrainer.setSequenceType(EXERCISE_TYPE_INTERVALS, Number(document.getElementById('interval_sequenceType').value)); 
}

function setChordDirection() {
    document.EarTrainer.setDirection(EXERCISE_TYPE_CHORDS, Number(document.getElementById('chord_direction').value)); 
}

function setChordSequenceType() {
    document.EarTrainer.setSequenceType(EXERCISE_TYPE_CHORDS, Number(document.getElementById('chord_sequenceType').value)); 
}

function setMelodyNoteLength() {
    document.EarTrainer.setMelodyNoteLength(Number(document.getElementById('melody_noteLength').value)); 
}

function setMelodyLickMeasureLength() {
    document.EarTrainer.setMelodyLickMeasureLength(Number(document.getElementById('melody_lickMeasureLength').value)); 
}

function setCallAndResponseNoteCount() {
	var noteCount = Number(document.getElementById('callAndResponse_noteCount').value);
	
	setAvailableRSectionProgressions();
	
	toggleRSectionRandomizedBeatCountDisplay();
	setRSectionProgressionTypes();
    document.EarTrainer.setCallAndResponseNoteCount(noteCount); 
}

function setAvailableRSectionProgressions() {
	var callAndResponseNoteCount = Number(document.getElementById('callAndResponse_noteCount').value);
	var randomizedBeatCount = Number(document.getElementById('rsection_randomizedBeatCount').value);
	
	var startIndex = 6; //starting index for stuff we need to show/hide
	if (callAndResponseNoteCount == CALLANDRESPONSE_TYPE_LICK_JAZZ) {
		//hide all progressions.  we'll show the valid ones down below
		startIndex = 4;
		
		document.getElementById('rsection_progression_all').checked = false;
	} else if (randomizedBeatCount > 0) {
		startIndex = 8;
	}
	
	//show/hide progressions
	for (var i = 1; i <= 11; i++) {
		
		var display = 'block';
		if ((callAndResponseNoteCount > 0 || randomizedBeatCount) && i >= startIndex) {
			display = 'none';
		}
		
        document.getElementById('rsection_progression_div_' + i).style.display = display;
        
        if (display == 'none') {  
			//if we're hiding any options, hide the All option too
			document.getElementById('rsection_progression_all').checked = false;
			document.getElementById('rsection_progression_' + i).checked = false;  
		}
    }
    
    document.getElementById('callAndResponse_note').style.display = 'none';
	document.getElementById('callAndResponse_jazzLicksNote').style.display = 'none';
	document.getElementById('randomizedBeatCount_note').style.display = 'none';
    
    //show/hide "all" option and show/hide callAndResponse note
    document.getElementById('rsection_progression_div_all').style.display = display;
    if (callAndResponseNoteCount == CALLANDRESPONSE_TYPE_LICK_JAZZ) {
		
		if (!document.getElementById('rsection_progression_1').checked
			&& !document.getElementById('rsection_progression_2').checked
			&& !document.getElementById('rsection_progression_3').checked) {
		
			//check dom7 if nothing was checked after hiding
			document.getElementById('rsection_progression_2').checked = true;
		}
    
		document.getElementById('rsection_progression_div_1').style.display = 'block'; //maj7
		document.getElementById('rsection_progression_div_2').style.display = 'block'; //dom7
		document.getElementById('rsection_progression_div_3').style.display = 'block'; //min7
		
		document.getElementById('callAndResponse_jazzLicksNote').style.display = 'block';
	} else if (callAndResponseNoteCount > 0) {
		document.getElementById('callAndResponse_note').style.display = 'block';
	} else if (randomizedBeatCount > 0) {
		document.getElementById('randomizedBeatCount_note').style.display = 'block';
	}
}

function setCallAndResponseMeasureLength() {
    document.EarTrainer.setCallAndResponseMeasureLength(Number(document.getElementById('callAndResponse_measureLength').value)); 
}

function setRSectionMeasureCount() {
    document.EarTrainer.setRSectionMeasureCount(Number(document.getElementById('rsection_measureCount').value)); 
}

function setRSectionRandomizedBeatCount() {
	var value = Number(document.getElementById('rsection_randomizedBeatCount').value);
    document.EarTrainer.setRSectionRandomizedBeatCount(value);
    setAvailableRSectionProgressions();
    toggleCallAndResponseDisplay();
}

function toggleRSectionRandomizedBeatCountDisplay() {
	var hide = false;
	for (var i = 8; i <= 11; i++) {
		if (document.getElementById('rsection_progression_' + i).checked) {
			  hide = true;
		}
    }

	if (hide || document.getElementById('callAndResponse_noteCount').selectedIndex > 0) {
		document.getElementById('rsection_randomizedBeatCount_div').style.display = 'none';
		document.getElementById('rsection_randomizedBeatCount').selectedIndex = 0;
		document.EarTrainer.setRSectionRandomizedBeatCount(0);
	} else {
		document.getElementById('rsection_randomizedBeatCount_div').style.display = 'block';
	}
}

function toggleCallAndResponseDisplay() {
	var hide = false;
	for (var i = 6; i <= 11; i++) {
		if (document.getElementById('rsection_progression_' + i).checked) {
			  hide = true;
		}
    }

	if (hide || document.getElementById('rsection_randomizedBeatCount').selectedIndex > 0) {
		document.getElementById('callAndResponse_div').style.display = 'none';
		document.getElementById('callAndResponse_div').selectedIndex = 0;
		document.EarTrainer.setCallAndResponseNoteCount(0);
	} else {
		document.getElementById('callAndResponse_div').style.display = 'block';
	}
}

function setModulationDirection() {

	var direction = Number(document.getElementById('modulation_direction').value);

    document.EarTrainer.setModulationDirection(direction); 
    
	if ((direction & (DIRECTION_CIRCLE_4_UP + DIRECTION_CIRCLE_5_UP 
						+ DIRECTION_CIRCLE_4_UP_HALF + DIRECTION_CIRCLE_5_UP_HALF
						+ DIRECTION_CIRCLE_4_RANDOM_3 + DIRECTION_CIRCLE_4_RANDOM_6 + DIRECTION_CIRCLE_4_RANDOM_12
						)) > 0) {
		document.getElementById('modulation_options').style.display = 'none';
	} else {
		document.getElementById('modulation_options').style.display = 'block';
	}
}

function setModulationWithRest() {
    if (document.getElementById('modulation_withRest').checked) {
        document.EarTrainer.setModulationWithRest(true);
    } else {
        document.EarTrainer.setModulationWithRest(false);
    }
}

/*
function setModulationRepeat() {
    document.EarTrainer.setModulationRepeat(document.getElementById('modulationRepeat').value);
}
*/

function setInstrument() {
    document.EarTrainer.setInstrument(Number(document.getElementById('instrument').value));
}

function setKeyboardActivation() {
    if (document.getElementById('keyboard_activation').value == "true") {
        isKeyboardActivated = true;
    } else {
		isKeyboardActivated = false;
    }
    
    document.EarTrainer.setKeyboardActivation(isKeyboardActivated);
}


function setTabWarning(tabNumber) {
	//alert('tabName=' + tabName + ', activePanel=' + activePanel);

	//if this is also the active tab, set the background
	if (activePanel == ('tab_' + tabNumber) && tabNumber != 5) {
	
		if (document.getElementById('exerciseType_' + tabNumber).checked) {
			document.getElementById('tab_' + tabNumber + 'Title').style.background = '#fff';
			document.getElementById('tab_' + tabNumber + 'Title').style.color = '#888';
			//document.getElementById('tab_' + tabNumber).style.padding = '15px 10px 10px 11px;';
		} else {
			document.getElementById('tab_' + tabNumber + 'Title').style.background = '#75B9D1';
			document.getElementById('tab_' + tabNumber + 'Title').style.color = '#fff';
			//document.getElementById('tab_' + tabNumber).style.padding = '15 10px 10px 11px;';
		}
	}
}

function setExerciseTypes() {
    var exerciseTypes = 0;
    for (var i = 1; i <= 4; i++) {
    
		if (('tab_' + i) == activePanel) {
			setTabWarning(i);
		}
        
        if (document.getElementById('exerciseType_' + i).checked) {
            exerciseTypes += Number(document.getElementById('exerciseType_' + i).value);

            document.getElementById('exerciseTypeWarning_' + i).style.display = 'none';
        } else {
            document.getElementById('exerciseTypeWarning_' + i).style.display = 'block';
        }
    }

    document.EarTrainer.setExerciseTypes(exerciseTypes);
}

function setIntervals() {
    var intervals = "";
    var addAll = false;
    var addCompound = false;

    if (document.getElementById('interval_all').checked) {
        addAll = true;                
    }
    
    if (document.getElementById('interval_compound').checked) {
        addCompound = true;                
    }

    for (var i = 1; i <= 12; i++) {
        if (addAll || document.getElementById('interval_' + i).checked) {
            //add interval to the list
            intervals = addToList(intervals, document.getElementById('interval_' + i).value);
            
            if (i < 12 && addCompound) {
				//add compound interval to the list
				intervals = addToList(intervals, Number(document.getElementById('interval_' + i).value) + 13);	
            }
        }
    }

    document.EarTrainer.setIntervals(intervals);

    return;
}

function setAllIntervals() {
    var isChecked = false;

    if (document.getElementById('interval_all').checked) {
        isChecked = true;
    }

    for (var i = 1; i <= 12; i++) {
        document.getElementById('interval_' + i).checked = isChecked;
    }

    return;
}

function setChords() {
    var chords = "";
    var addAll = false;
    var addAll2 = false;

    if (document.getElementById('chord_all').checked) {
        addAll = true;                
    }
    
    if (document.getElementById('chord2_all').checked) {
        addAll2 = true;                
    }

    for (var i = 1; i <= 9; i++) {
        if (addAll || document.getElementById('chord_' + i).checked) {
            //add chord to the list
            chords = addToList(chords, document.getElementById('chord_' + i).value);
        }
    }

	for (var i = 1; i <= 9; i++) {
        if (addAll2 || document.getElementById('chord2_' + i).checked) {
            //add chord to the list
            chords = addToList(chords, document.getElementById('chord2_' + i).value);
        }
    }

    var inversions = getChord_inversions();

    document.EarTrainer.setChords(chords, inversions);

    return;
}

function setAllChords() {
    var isChecked = false;

    if (document.getElementById('chord_all').checked) {
        isChecked = true;
    }

    for (var i = 1; i <= 9; i++) {
        document.getElementById('chord_' + i).checked = isChecked;
    }

    return;
}

function setAllChords2() {
    var isChecked = false;

    if (document.getElementById('chord2_all').checked) {
        isChecked = true;
    }

    for (var i = 1; i <= 9; i++) {
        document.getElementById('chord2_' + i).checked = isChecked;
    }

    return;
}

function getChord_inversions() {
    var chord_inversions = "";
    var addAll = false;

    if (document.getElementById('chord_inversion_all').checked) {
        addAll = true;                
    }

    for (var i = 1; i <= 5; i++) {
        if (addAll || document.getElementById('chord_inversion_' + i).checked) {
            //add chord_inversion to the list
            chord_inversions = addToList(chord_inversions, document.getElementById('chord_inversion_' + i).value);
        }
    }

    return chord_inversions;
}

function setAllChord_inversions() {
    var isChecked = false;

    if (document.getElementById('chord_inversion_all').checked) {
        isChecked = true;
    }

    for (var i = 1; i <= 5; i++) {
        document.getElementById('chord_inversion_' + i).checked = isChecked;
    }

    return;
}


function setMelodyNotes() {
    var melodyNotes = "";
    var addAll = false;

    if (document.getElementById('melody_note_all').checked) {
        addAll = true;                
    }

    for (var i = 1; i <= 12; i++) {
        if (addAll || document.getElementById('melody_note_' + i).checked) {
            //add melodyNote to the list
            melodyNotes = addToList(melodyNotes, document.getElementById('melody_note_' + i).value);
        }
    }

    var isSingleOctave = false;
    if (document.getElementById('melody_singleOctave').value == "true") {
        isSingleOctave = true;
    }

    var melodyNoteType = getMelodyNoteType();
    document.EarTrainer.setMelodyNotes(melodyNotes, Number(melodyNoteType), isSingleOctave);

	if (melodyNoteType == MELODY_NOTE_TYPE_LICK_JAZZ) {
		document.getElementById('melody_noteLength_div').style.display = 'none';
		document.getElementById('melody_lickMeasureLength_div').style.display = 'block';
		document.getElementById('melody_singleOctave_div').style.display = 'none';		
	} else if (melodyNoteType == MELODY_NOTE_TYPE_LICK_SONG) {
		document.getElementById('melody_noteLength_div').style.display = 'none';
		document.getElementById('melody_lickMeasureLength_div').style.display = 'none';
		document.getElementById('melody_singleOctave_div').style.display = 'none';	
	} else {
		document.getElementById('melody_lickMeasureLength_div').style.display = 'none';
		document.getElementById('melody_noteLength_div').style.display = 'block';
		document.getElementById('melody_singleOctave_div').style.display = 'block';
	}

    return;
}

function setAllMelodyNotes() {
    var isChecked = false;

    if (document.getElementById('melody_note_all').checked) {
        isChecked = true;
    }

    for (var i = 1; i <= 12; i++) {
        document.getElementById('melody_note_' + i).checked = isChecked;
    }

    return;
}

function getMelodyNoteType() {
    return document.getElementById('melody_noteType').value;
}


function setModulationIntervals() {
    var modulationIntervals = "";
    var addAll = false;

    if (document.getElementById('modulation_interval_all').checked) {
        addAll = true;                
    }

    for (var i = 1; i <= 6; i++) {
        if (addAll || document.getElementById('modulation_interval_' + i).checked) {
            //add modulationInterval to the list
            modulationIntervals = addToList(modulationIntervals, i);
        }
    }

    document.EarTrainer.setModulationIntervals(modulationIntervals);

    return;
}

function setAllModulationIntervals() {
    var isChecked = false;

    if (document.getElementById('modulation_interval_all').checked) {
        isChecked = true;
    }

    for (var i = 1; i <= 6; i++) {
        document.getElementById('modulation_interval_' + i).checked = isChecked;
    }

    return;
}

function setRSectionKeys() {

    var rsectionKeys = "";
    var addAll = false;

    if (document.getElementById('rsection_key_all').checked) {
        addAll = true;                
    }

    for (var i = 1; i <= 12; i++) {
        if (addAll || document.getElementById('rsection_key_' + i).checked) {
            //add key to the list
            rsectionKeys = addToList(rsectionKeys, document.getElementById('rsection_key_' + i).value);
        }
    }

    document.EarTrainer.setRSectionKeys(rsectionKeys);

    return;
}

function setAllRSectionKeys() {
    var isChecked = false;

    if (document.getElementById('rsection_key_all').checked) {
        isChecked = true;
    }

    for (var i = 1; i <= 12; i++) {
        document.getElementById('rsection_key_' + i).checked = isChecked;
    }

    return;
}

function setRSectionProgressionTypes() {

    var rsectionProgressions = "";
    var addAll = false;
    var showCallAndResponseDiv = true;
    var showRandomizedBeatCountDiv = true;

    if (document.getElementById('rsection_progression_all').checked) {
        addAll = true;                
    }

    for (var i = 1; i <= 11; i++) {
        if (addAll || document.getElementById('rsection_progression_' + i).checked) {
            //add progression to the list
            rsectionProgressions = addToList(rsectionProgressions, document.getElementById('rsection_progression_' + i).value);
        }
    }
    
    toggleRSectionRandomizedBeatCountDisplay();
    toggleCallAndResponseDisplay();

    document.EarTrainer.setRSectionProgressionTypes(rsectionProgressions);

    return;
}

function setAllRSectionProgressionTypes() {
    var isChecked = false;

    if (document.getElementById('rsection_progression_all').checked) {
        isChecked = true;
    }

    for (var i = 1; i <= 11; i++) {
        document.getElementById('rsection_progression_' + i).checked = isChecked;
    }

    return;
}


function setRSectionInstruments() {

    var rsectionInstruments = 0;
    var addAll = false;

    if (document.getElementById('rsection_instrument_all').checked) {
        addAll = true;                
    }

    for (var i = 1; i <= 4; i++) {
        if (addAll || document.getElementById('rsection_instrument_' + i).checked) {
            rsectionInstruments += Number(document.getElementById('rsection_instrument_' + i).value);
        }
    }

    document.EarTrainer.setRSectionInstruments(rsectionInstruments);

    return;
}

function setAllRSectionInstruments() {
    var isChecked = false;

    if (document.getElementById('rsection_instrument_all').checked) {
        isChecked = true;
    }

    for (var i = 1; i <= 4; i++) {
        document.getElementById('rsection_instrument_' + i).checked = isChecked;
    }

    return;
}


//------------------------------------------------------------------------------
// UI FUNCTIONS - Functions that change values in the main HTML UI
//------------------------------------------------------------------------------

function setActivePanel_UI(tabNumber) {

	activePanel = showHideTab(tabNumber, activePanel);
	
	//uncheck all tabs
	document.getElementById('exerciseType_1').checked = false;
	document.getElementById('exerciseType_2').checked = false;
	document.getElementById('exerciseType_3').checked = false;
	document.getElementById('exerciseType_4').checked = false;
	
	//check the active tab
	document.getElementById('exerciseType_' + tabNumber).checked = true;
	
	setExerciseTypes();
}

function setTempo_UI(bpm) {
	slider_value = bpm;
	updateTempoDisplay();
	updateSliderPosition();	
	setTempo();
}

function setPlayMode_UI(index) {
	document.getElementById('playMode').selectedIndex = index;
	setPlayMode();
}

function setAllIntervals_UI() {
	document.getElementById('interval_all').checked = true;
	setAllIntervals();
	setIntervals();
}

function setIntervalDirection_UI(index) {
	document.getElementById('interval_direction').selectedIndex = index;
	setIntervalDirection();
}

function setIntervalSequenceType_UI(index) {
	document.getElementById('interval_sequenceType').selectedIndex = index;
	setIntervalSequenceType();
}

function setIntervalRootNote_UI(index) {
	document.getElementById('interval_rootNote').selectedIndex = index;
	setRootNote();
}

function setAllChords_UI() {
	document.getElementById('chord_all').checked = true;
	setAllChords();
	setChords();
}

function setChordDirection_UI(index) {
	document.getElementById('chord_direction').selectedIndex = index;
	setChordDirection();
}

function setChordSequenceType_UI(index) {
	document.getElementById('chord_sequenceType').selectedIndex = index;
	setChordSequenceType();
}

function setChordRootNote_UI(index) {
	document.getElementById('chord_rootNote').selectedIndex = index;
	setRootNote();
}

function setAllMelodyNotes_UI() {
	document.getElementById('melody_note_all').checked = true;
	setAllMelodyNotes();
	setMelodyNotes();
}

function setMelodyNoteType_UI(index) {
	document.getElementById('melody_noteType').selectedIndex = index;
	setMelodyNotes();
}

function setMelodyNoteLength_UI(index) {
	document.getElementById('melody_noteLength').selectedIndex = index;
	setMelodyNoteLength();
}

function setMelodySingleOctave_UI(value) {
	if (value == true) {
		document.getElementById('melody_singleOctave').selectedIndex = 1;
	} else {
		document.getElementById('melody_singleOctave').selectedIndex = 0;
	}
	setMelodyNotes();
}

function setModulationDirection_UI(index) {
	document.getElementById('modulation_direction').selectedIndex = index;
	setModulationDirection();
}

function setAdvancedDefaults_UI() {
	document.getElementById('modulation_direction').selectedIndex = 0;
	setModulationDirection();
	
	document.getElementById('modulation_withRest').checked = false;
	setModulationWithRest();
	
	document.getElementById('modulation_interval_all').checked = true;
	setAllModulationIntervals();
	setModulationIntervals();
	
	document.getElementById('noteSustain').selectedIndex = 3;
	setNoteSustain();
	
	document.getElementById('noteSize_melodic').selectedIndex = 2;
	setNoteSize_Melodic();
	
	document.getElementById('noteSize_harmonic').selectedIndex = 0;
	setNoteSize_Harmonic();
	
	document.getElementById('autoPlayRepeat').selectedIndex = 0;
	setAutoPlayRepeat();
}

function setInstrument_UI(index) {
	document.getElementById('instrument').selectedIndex = index;
	setInstrument();
}

document.onkeypress=handleKeyPress;
document.onkeyup=handleKeyUp;


function handleKeyPress(e) {
	if (isKeyboardActivated) {
		document.EarTrainer.onKeyDown(getKeyChar(e));
	}
}

function handleKeyUp(e) {
	if (isKeyboardActivated) {
		document.EarTrainer.onKeyUp(getKeyChar(e));
	}
}

//return the character for a keypress/keyup event
function getKeyChar(e) {
	var keyCode;
	if (!e) {
		var e = window.event;
	}
	
	if (e.keyCode) {
		keyCode = e.keyCode;
	} else if (e.which){
		keyCode = e.which;
	}
	
	return String.fromCharCode(keyCode);
}


//------------------------------------------------------------------------------
// UTILITY FUNCTIONS
//------------------------------------------------------------------------------

//builds comma delimited lists
function addToList(list, item) {
    if (list.length > 0)
        list += ",";

    list += item;   
    return list;
}

function cleanUp() {
    clearTimeout(sequencerTimeout);
}

function updateProperty(name, value) {
    setSelectedValue(name, value);
}


//sets the selected value of a SELECT box (by name) to the value passed
function setSelectedValue(name, value) {

    var obj = document.getElementById(name);

    for (var i = 0; i < obj.options.length; i++) {
        if (obj.options[i].value == value) {
            obj.options[i].selected = true;
            return;
        }
    }
}



//------------------------------------------------------------------------------
// TOOLTIP DOM STUFF
//------------------------------------------------------------------------------

//GET DOM
var isDHTML = 0;
var isID = 0;
var isAll = 0;
var isLayers = 0;
var isIE = false;
var isSafari = false;

if (document.getElementById) {isID = 1; isDHTML = 1;}
else {
if (document.all) {isAll = 1; isDHTML = 1;}
else {
browserVersion = parseInt(navigator.appVersion);
if ((navigator.appName.toLowerCase(indexOf('Netscape') != -1)) && (browserVersion == 4)) {isLayers = 1; isDHTML = 1;}
}}

var browser = navigator.userAgent.toLowerCase();
if (browser.indexOf('safari') != -1) {
	isSafari = true;
} else if (browser.indexOf('msie') != -1 && browser.indexOf("opera") == -1) {
    isIE = true;
}

function getDOM(objectID,withStyle) {
	if (withStyle == 1) {
		if (isID) { return (document.getElementById(objectID).style) ; }
		else { 
			if (isAll) { return (document.all[objectID].style); }
		else {
			if (isLayers) { return (document.layers[objectID]); }
		};}
	}
	else {
		if (isID) { return (document.getElementById(objectID)) ; }
		else { 
			if (isAll) { return (document.all[objectID]); }
		else {
			if (isLayers) { return (document.layers[objectID]); }
		};}
	}
}


//------------------------------------------------------------------------------
// TOOLTIPS
//------------------------------------------------------------------------------

function showTT(IDName, evt, inPosX) {
    showToolTip('tt_' + IDName, evt, inPosX, '1000', 'if_' + IDName);

    if (isIE) {
        showToolTip('if_' + IDName, evt, inPosX, '999', ''); //select box hack
    }    
}

function hideTT(IDName) {
    if (isIE) {
        hideToolTip('if_' + IDName);
    }

    hideToolTip('tt_' + IDName);
}

function showToolTip(IDName, evt, inPosX, zindex, IDName_iFrame)
{
	if (isDHTML) //browser supports DHTML 
	{
		var tipDOM = getDOM(IDName, 0);
		var tipDOMStyle = getDOM(IDName, 1);
		var posX = getXCoord(evt);
		var posY = getYCoord(evt);
		var scrollX = getXScroll();
		var scrollY = getYScroll();
		var windowWidth;
		var windowHeight;
		var tooltipWidth;
		var tooltipHeight;

		//get tooltip width
		if (tipDOM.offsetWidth != null)
			tooltipWidth = tipDOM.offsetWidth;
		else if (tipDOM.clip.width != null)
			tooltipWidth = tipDOM.clip.width;

		//get tooltip height
		if (tipDOM.offsetHeight != null)
			tooltipHeight = tipDOM.offsetHeight;
		else if (tipDOM.clip.Height != null)
			tooltipHeight = tipDOM.clip.Height;

                if (isIE && IDName_iFrame.length > 0) {
                    //set the iframe's height
                    var tipDOMStyle_iFrame = getDOM(IDName_iFrame, 1);
                    tipDOMStyle_iFrame.height = tooltipHeight - (3 * 2); //subtract padding
                }

		//getWindowWidth
		if (window.innerWidth != null)
			windowWidth = window.innerWidth;
		else if (document.body.clientWidth != null)
			windowWidth = document.body.clientWidth;
		windowWidth -= 15;


		//getWindowHeight
		if (window.innerHeight != null)
			windowHeight = window.innerHeight;
		else if (document.body.clientHeight != null)
			windowHeight = document.body.clientHeight;

		if (((windowWidth < posX + tooltipWidth + 10) && isAll ) || ((windowWidth < posX - scrollX + tooltipWidth + 10) && !isAll ))
			posX = posX - tooltipWidth - 15;
		else
			posX = posX + 15;

		if (((windowHeight < posY + tooltipHeight + 15) && isAll ) || ((windowHeight < posY - scrollY + tooltipHeight + 15) && !isAll ))
			posY = posY - tooltipHeight - 15;
		else
			posY = posY + 15;
			
			
		if (inPosX > 0)
			posX = inPosX;

		if (tipDOMStyle.left != null)
		{
			tipDOMStyle.left = posX + "px";
			tipDOMStyle.top = posY + "px";
		}
		
		if (tipDOMStyle.pixelLeft != null)
		{
			if(!(inPosX > 0))
				posX += scrollX;
			
			tipDOMStyle.pixelLeft = posX;
			tipDOMStyle.pixelTop = posY + scrollY;
		}
		
		if (tipDOMStyle.offsetLeft != null)
		{
			tipDOMStyle.offsetLeft = posX;
			tipDOMStyle.offsetTop = posY;
		}
		
		tipDOMStyle.visibility = 'visible';
		tipDOMStyle.zIndex = zindex;

	}
	else
	{
		return null;
	}
}

function hideToolTip(IDName)
{
	if (isDHTML)
	{
		var tipDOMStyle = getDOM(IDName, 1);
		tipDOMStyle.visibility = 'hidden';
		tipDOMStyle.zIndex = '-1';
	}
}

function getXCoord(evt)
{
	if (evt.x)
		return evt.x;
	else if (evt.pageX)
		return evt.pageX;
}

function getYCoord(evt)
{
	if (evt.y)
		return evt.y;
	else if (evt.pageY)
		return evt.pageY; 
}

function getXScroll()
{
	if (document.body.scrollLeft != null)
		return document.body.scrollLeft;
	else if (window.pageXOffset != null)
		return window.pageXOffset;
}

function getYScroll()
{
	if (document.body.scrollTop != null)
		return document.body.scrollTop;
	else if (window.pageYOffset != null)
		return window.pageYOffset;
}


//------------------------------------------------------------------------------
// TEMPO SLIDER
//------------------------------------------------------------------------------

//---------------------------------+
//  CARPE  S l i d e r        1.5  |
//  2006 - 01 - 03                 |
//  By Tom Hermansson Snickars and edited heavily by Rick...
//  Copyright CARPE Design         |
//  http://carpe.ambiprospect.com/ |
//  Contact for custom scripts     |
//  or implementation help.        |
//---------------------------------+

// Global vars. You don't need to make changes here to change your sliders.
// Changing the attributes in your (X)HTML file is enough.
var carpeDefaultSliderLength      = 100
var carpeSliderDefaultOrientation = 'horizontal'
var carpeSliderClassName          = 'carpe_slider'
var carpeSliderDisplayClassName   = 'carpe_slider_display'

var slider_value = 70;
var slider_min = 30;
var slider_max = 300;
var slider_valuecount = 101;
var slider_length = 150

// carpeGetElementsByClass: Cross-browser function that returns
// an array with all elements that have a class attribute that
// contains className
function carpeGetElementsByClass(className)
{
	var classElements = new Array();
	var els = document.getElementsByTagName("*");
	var elsLen = els.length;
	var pattern = new RegExp("\\b" + className + "\\b");
	for (i = 0, j = 0; i < elsLen; i++) {
		if ( pattern.test(els[i].className) ) {
			classElements[j] = els[i];
			j++;
		}
	}
	return classElements;
}
// carpeLeft: Cross-browser version of "element.style.left"
// Returns or sets the horizontal position of an element.
function carpeLeft(elmnt, pos)
{
	if (!(elmnt = document.getElementById(elmnt))) return 0;
	if (elmnt.style && (typeof(elmnt.style.left) == 'string')) {
		if (typeof(pos) == 'number') elmnt.style.left = pos + 'px';
		else {
			pos = parseInt(elmnt.style.left);
			if (isNaN(pos)) pos = 0;
		}
	}
	else if (elmnt.style && elmnt.style.pixelLeft) {
		if (typeof(pos) == 'number') elmnt.style.pixelLeft = pos;
		else pos = elmnt.style.pixelLeft;
	}
	return pos;
}
// carpeTop: Cross-browser version of "element.style.top"
// Returns or sets the vertical position of an element.
function carpeTop(elmnt, pos)
{
	if (!(elmnt = document.getElementById(elmnt))) return 0;
	if (elmnt.style && (typeof(elmnt.style.top) == 'string')) {
		if (typeof(pos) == 'number') elmnt.style.top = pos + 'px';
		else {
			pos = parseInt(elmnt.style.top);
			if (isNaN(pos)) pos = 0;
		}
	}
	else if (elmnt.style && elmnt.style.pixelTop) {
		if (typeof(pos) == 'number') elmnt.style.pixelTop = pos;
		else pos = elmnt.style.pixelTop;
	}
	return pos;
}
// moveSlider: Handles slider and display while dragging
function moveSlider(evnt)
{
	var evnt = (!evnt) ? window.event : evnt; // The mousemove event
	if (mouseover) { // Only if slider is dragged
		x = slider.startOffsetX + evnt.screenX // Horizontal mouse position relative to allowed slider positions
		y = slider.startOffsetY + evnt.screenY // Horizontal mouse position relative to allowed slider positions
		if (x > slider.xMax) x = slider.xMax // Limit horizontal movement
		if (x < 0) x = 0 // Limit horizontal movement
		if (y > slider.yMax) y = slider.yMax // Limit vertical movement
		if (y < 0) y = 0 // Limit vertical movement
		carpeLeft(slider.id, x)  // move slider to new horizontal position
		carpeTop(slider.id, y) // move slider to new vertical position
		sliderVal = x + y // pixel value of slider regardless of orientation
		sliderPos = (slider.distance / slider_valuecount) * Math.round(slider_valuecount * sliderVal / slider.distance);
		v = Math.round((sliderPos * slider.scale + slider.from) * Math.pow(10, 0)) / Math.pow(10, 0); // calculate display value
		slider_value = v; // put the new value in the slider display element

                updateTempoDisplay();

		return false;
	}
	return
}
// slide: Handles the start of a slider move.
function slide(evnt)
{
	if (!evnt) evnt = window.event; // Get the mouse event causing the slider activation.
	slider = (evnt.target) ? evnt.target : evnt.srcElement; // Get the activated slider element.
	dist = parseInt(slider.getAttribute('distance')); // The allowed slider movement in pixels.
	slider.distance = dist ? dist : carpeDefaultSliderLength; // Deafault distance from global var.
	ori = slider.getAttribute('orientation'); // Slider orientation: 'horizontal' or 'vertical'.
	orientation = ((ori == 'horizontal') || (ori == 'vertical')) ? ori : carpeSliderDefaultOrientation; // Default orientation from global variable.
/*
	displayId = slider.getAttribute('display') // ID of associated display element.
	display = document.getElementById(displayId) // Get the associated display element.
	display.sliderId = slider.id // Associate the display with the correct slider.
*/
	dec = 0; // parseInt(display.getAttribute('decimals')) // Number of decimals to be displayed.
	//display.decimals = dec ? dec : 0 // Default number of decimals: 0.
	val = parseInt(slider_valuecount);  // Allowed number of values in the interval.
	slider_valuecount = val ? val : slider.distance + 1; // Default number of values: the sliding distance.
	from = parseFloat(slider_min); // Min/start value for the display.
	from = from ? from : 0; // Default min/start value: 0.
	to = parseFloat(slider_max); // Max value for the display.
	to = to ? to : slider.distance; // Default number of values: the sliding distance.
	slider.scale = (to - from) / slider.distance; // Slider-display scale [value-change per pixel of movement].
	if (orientation == 'vertical') { // Set limits and scale for vertical sliders.
		slider.from = to; // Invert for vertical sliders. "Higher is more."
		slider.xMax = 0;
		slider.yMax = slider.distance;
		slider.scale = -slider.scale; // Invert scale for vertical sliders. "Higher is more."
	}
	else { // Set limits for horizontal sliders.
		slider.from = from;
		slider.xMax = slider.distance;
		slider.yMax = 0;
	}
	slider.startOffsetX = carpeLeft(slider.id) - evnt.screenX; // Slider-mouse horizontal offset at start of slide.
	slider.startOffsetY = carpeTop(slider.id) - evnt.screenY; // Slider-mouse vertical offset at start of slide.
	mouseover = true;
	document.onmousemove = moveSlider; // Start the action if the mouse is dragged.
	document.onmouseup = sliderMouseUp; // Stop sliding.

	return false;
}
// sliderMouseUp: Handles the mouseup event after moving a slider.
// Snaps the slider position to allowed/displayed value. 
function sliderMouseUp()
{
	if (mouseover) {
		v = (slider_value) ? slider_value : 0; // Find last display value.
		pos = (v - slider.from)/(slider.scale); // Calculate slider position (regardless of orientation).
		if (slider.yMax == 0) {
			pos = (pos > slider.xMax) ? slider.xMax : pos;
			pos = (pos < 0) ? 0 : pos;
			carpeLeft(slider.id, pos + 'px'); // Snap horizontal slider to corresponding display position.
		}
		if (slider.xMax == 0) {
			pos = (pos > slider.yMax) ? slider.yMax : pos;
			pos = (pos < 0) ? 0 : pos;
			carpeTop(slider.id, pos); // Snap vertical slider to corresponding display position.
		}
		if (document.removeEventListener) { // Remove event listeners from 'document' (W3C).
			document.removeEventListener('mousemove', moveSlider, false);
			document.removeEventListener('mouseup', sliderMouseUp, false);
		}
		else if (document.detachEvent) { // Remove event listeners from 'document' (IE).
			document.detachEvent('onmousemove', moveSlider);
			document.detachEvent('onmouseup', sliderMouseUp);
		}
	}

        mouseover = false; // Stop the sliding.
        setTempo();
}
/*
function focusDisplay(evnt)
{

	if (!evnt) evnt = window.event; // Get the mouse event causing the display activation.
	display = (evnt.target) ? evnt.target : evnt.srcElement; // Get the activated display element.
	lock = display.getAttribute('typelock'); // Is the user allowed to type into the display?
	if (lock == 'on') {
		display.blur();
	}
	return;
}
*/

function updateTempoDisplay() {
    document.getElementById('tempo').innerHTML = 'Tempo: ' + slider_value + ' bpm';
}

function updateSliderPosition() {
    var sliderPos = 0;
    sliderPos = ((slider_value - slider_min) / (slider_max - slider_min)) * slider_length;
    carpeLeft('slider_tempo', sliderPos);  // move slider to new horizontal position
}


function sliderInit() // Set up the sliders and the displays.
{

	sliders = carpeGetElementsByClass(carpeSliderClassName) // Find the horizontal sliders.
	for (i = 0; i < sliders.length; i++) {
            sliders[i].onmousedown = slide; // Attach event listener.
	}

/*
        //this needs work...
        sliderContainers = carpeGetElementsByClass('carpe_horizontal_slider_track') // Find the horizontal sliders.
	for (i = 0; i < sliderContainers.length; i++) {
            sliderContainers[i].onmousedown = slide; // Attach event listener.
	}
*/

        updateTempoDisplay();
        updateSliderPosition();

/*
	displays = carpeGetElementsByClass(carpeSliderDisplayClassName) // Find the displays.
	for (i = 0; i < displays.length; i++) {
		displays[i].onfocus = focusDisplay // Attach event listener.
	}
*/
}
