/*
	Month Calendar - A Monthly Calendar with Week Numbers
	Copyright © 2005-2009 Harry Whitfield

	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License as
	published by the Free Software Foundation; either version 2 of
	the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public
	License along with this program; if not, write to the Free
	Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
	MA  02110-1301  USA
	
	Month Calendar - version 3.3
	26 May, 2009
	Copyright © 2005-2009 Harry Whitfield
	mailto:g6auc@arrl.net
*/

/*global eprint, itemSep, listSep, makeISODate1, memoFolderPath, time,
		 alarmTimer, daysInMonth, display, display_window, getMemo, lprint, main_window,
		 makeISODate3, memo, memo_info, saveMemo, updateCalendar, updateMemoAlarm, updateMemos,
		 closeMemoWindow, displayBg, gISOdate, saveMemoWindow
*/

var gDefaultFile = "G6AUC.wav";
var gSoundFile   = gDefaultFile;
var gAlarmList = "";
var gSoundFlag = false;

var gAlarmType   = "";
var gSoundPath   = "";
var gDisplayText = "";
var gEmailText   = "";
var gOpenPath    = "";
var gOpenURL     = "";

var gNextAlarm   = 0;
var gFirstAlarmTime = 0;
var gRepeatAlarm = "";
var gAdvanceAlarm = false;
var gAlarmISODate = "";

var alarmMarker = "Alarm:";

function audioForm(isoDate, fileArray, fileDefault)
{
	var objDef = [['sound', 'Sound:', 'popup', fileArray, fileDefault, 'Choose the alarm sound.'],
				  ['remove','Delete Sound', 'checkbox', [''], 0, 'Check this box to delete the selected sound.\n\nNote that the default sound (G6AUC.wav) cannot be deleted.']];

	var formfields = [];

	for (var i = 0; i < 2 ; i += 1)
	{
		formfields[i] = new FormField();
		formfields[i].name = objDef[i][0];
		formfields[i].title = objDef[i][1];
		formfields[i].type = objDef[i][2];
		formfields[i].option = objDef[i][3];
		formfields[i].defaultValue = objDef[i][4];
		formfields[i].description = objDef[i][5];
	}

	var formResults = form(formfields, 'Alarm Definition: ' + fullDateOf(isoDate), 'Set');
			
	var result = "";
	var sound, remove;

	if (formResults !== null)
	{
		sound   = formResults[0];
		remove  = formResults[1];

		result = sound + itemSep + remove;
	}
			
	for (i = 0; i < 2 ; i += 1)
	{
		delete formfields[i];
		formfields[i] = null;
	}
	formfields = null;
	return result;
}

function displayForm(isoDate, prompt)
{
	var objDef = [['display', 'Line 1:', 'text', [''], '', prompt]];

	var formfields = [];

	for (var i = 0; i < 1 ; i += 1)
	{
		formfields[i] = new FormField();
		formfields[i].name = objDef[i][0];
		formfields[i].title = objDef[i][1];
		formfields[i].type = objDef[i][2];
		formfields[i].option = objDef[i][3];
		formfields[i].defaultValue = objDef[i][4];
		formfields[i].description = objDef[i][5];
	}
	
	for (var j = i; j < 10; j += 1)
	{
		formfields[j] = new FormField();
		formfields[j].name =  'line'  + (j-i+2);
		formfields[j].title = 'Line ' + (j-i+2) + ':';
		formfields[j].type = 'text';
		formfields[j].defaultValue = '';
		formfields[j].description = '';
	}

	var formResults = form(formfields, 'Alarm Definition: ' + fullDateOf(isoDate), 'Set');
			
	var result = "";
	var display, k;

	if (formResults !== null)
	{
		display = formResults[0];
		result = display;
		for (k = i; k < 10; k += 1)
		{
			display = formResults[k];
			if (display !== "") { result += '%0A' + display; }
		}
	}
			
	for (i = 0; i < 10 ; i += 1)
	{
		delete formfields[i];
		formfields[i] = null;
	}
	formfields = null;
	return result;
}

function emailForm(isoDate)
{
	var objDef = [['mailto', 'To:', 'text', [''], '', 'Enter the destination email address.'],
				  ['subject', 'Subject:', 'text', [''], '', 'Enter the subject of the message.'],
				  ['body', 'Message:', 'text', [''], '', 'Enter the message.']];

	var formfields = [];

	for (var i = 0; i < 3 ; i += 1)
	{
		formfields[i] = new FormField();
		formfields[i].name = objDef[i][0];
		formfields[i].title = objDef[i][1];
		formfields[i].type = objDef[i][2];
		formfields[i].option = objDef[i][3];
		formfields[i].defaultValue = objDef[i][4];
		formfields[i].description = objDef[i][5];
	}

	for (var j = i; j < 10; j += 1)
	{
		formfields[j] = new FormField();
		formfields[j].name =  'line'  + (j-i+2);
		formfields[j].title = 'Line ' + (j-i+2) + ':';
		formfields[j].type = 'text';
		formfields[j].defaultValue = '';
		formfields[j].description = '';
	}

	var formResults = form(formfields, 'Alarm Definition: ' + fullDateOf(isoDate), 'Set');
			
	var result = "";
	var mailto, subject, body, k;
	
	if (formResults !== null)
	{
		mailto   = formResults[0];
		subject  = formResults[1];
		body     = formResults[2];
		
		result = mailto + itemSep + subject + itemSep + body;
		for (k = i; k < 10; k += 1)
		{
			 body = formResults[k];
			if (body !== "") { result += '%0A' + body; }
		}
	}
			
	for (i = 0; i < 10 ; i += 1)
	{
		delete formfields[i];
		formfields[i] = null;
	}
	formfields = null;
	return result;
}

function fileFolderForm(isoDate, kind)
{
	var legend = "Select File"; var description = 'Select the file to be opened.';
	if (kind == "folders") { legend = "Select Folder"; description = 'Select the folder to be opened.'; }
	
	var objDef = [['open', legend, 'selector', [''], '', description]];

	var formfields = [];

	for (var i = 0; i < 1 ; i += 1)
	{
		formfields[i] = new FormField();
		formfields[i].name = objDef[i][0];
		formfields[i].title = objDef[i][1];
		formfields[i].type = objDef[i][2];
		formfields[i].style = 'open';
		formfields[i].kind = kind;
		formfields[i].option = objDef[i][3];
		formfields[i].defaultValue = objDef[i][4];
		formfields[i].description = objDef[i][5];
	}

	var formResults = form(formfields, 'Alarm Definition: ' + fullDateOf(isoDate), 'Set');
			
	var result = "", open;

	if (formResults !== null)
	{
		open   = formResults[0];
		result = open;
	}
			
	for (i = 0; i < 1 ; i += 1)
	{
		delete formfields[i];
		formfields[i] = null;
	}
	formfields = null;
	return result;
}

function urlForm(isoDate)
{
	var objDef = [['url', 'URL:', 'text', [''], '', 'Enter the url to be opened.']];

	var formfields = [];

	for (var i = 0; i < 1 ; i += 1)
	{
		formfields[i] = new FormField();
		formfields[i].name = objDef[i][0];
		formfields[i].title = objDef[i][1];
		formfields[i].type = objDef[i][2];
		formfields[i].option = objDef[i][3];
		formfields[i].defaultValue = objDef[i][4];
		formfields[i].description = objDef[i][5];
	}

	var formResults = form(formfields, 'Alarm Definition: ' + fullDateOf(isoDate), 'Set');
			
	var result = "", display;

	if (formResults !== null)
	{
		display   = formResults[0];
		result = display;
	}
			
	for (i = 0; i < 1 ; i += 1)
	{
		delete formfields[i];
		formfields[i] = null;
	}
	formfields = null;
	return result;
}

function fullDateOf(isoDate)
{
	var len   = isoDate.length;
	var year  = parseInt(isoDate.substring(0,       len - 4), 10);
	var month = parseInt(isoDate.substring(len - 4, len - 2), 10);
	var day   = parseInt(isoDate.substring(len - 2         ), 10);

	var d = new Date(year, month - 1, day);
	return d.toDateString();
}

function extraForms(isoDate, fileArray, fileDefault, flagList)
{
	var flags = flagList.split(itemSep);
		
	var time       = flags[0];
	var repeat     = flags[1];
	var every      = flags[2];
	
	var audio      = flags[3];
	var display    = flags[4];
	var email      = flags[5];
	var openFile   = flags[6];
	var openFolder = flags[7];
	var openURL    = flags[8];
	var repMemo    = flags[9];

	var result  = time + itemSep + repeat + itemSep + every;
			
	var res = "";
	var subResults = "";
	
	//var alarmTypes = ["Audio", "Display", "Email", "OpenFile", "OpenFolder", "OpenURL", "RepMemo"];
	
	if (audio == "1")
	{
		res = audioForm(isoDate, fileArray, fileDefault);
		if (res !== "") { subResults += listSep + "Audio" + itemSep + res; }
	}
	
	if (display == "1")
	{
		res = displayForm(isoDate, 'Enter the text to be displayed.');
		if (res !== "") { subResults += listSep + "Display" + itemSep + res; }
	}
		
	if (email == "1")
	{
		res = emailForm(isoDate);
		if (res !== "") { subResults += listSep + "Email" + itemSep + res; }
	}
							
	if (openFile == "1")
	{
		res = fileFolderForm(isoDate, "files");
		if (res !== "") { subResults += listSep + "OpenFile" + itemSep + res; }
	}
		
	if (openFolder == "1")
	{
		res = fileFolderForm(isoDate, "folders");
		if (res !== "") { subResults += listSep + "OpenFolder" + itemSep + res; }
	}

	if (openURL == "1")
	{
		res = urlForm(isoDate);
		if (res !== "") { subResults += listSep + "OpenURL" + itemSep + res; }
	}

	if (repMemo == "1")
	{
		res = displayForm(isoDate, 'Enter the text of the memo.');
		if (res !== "") { subResults += listSep + "RepMemo" + itemSep + res; }
	}

	if (subResults !== "") { result += subResults; } else { result = ""; }
	
	eprint('extraForms:result=' + result);

	return result;
}

function inTheFuture(every)
{
	return (every == "day")  || (every == "two-days")  || (every == "three-days")  || (every == "four-days")  || (every == "five-days") || (every == "six-days") ||
		   (every == "week") || (every == "two-weeks") || (every == "three-weeks") || (every == "four-weeks") || (every == "month")     || (every == "year");
}


function alarmForm(isoDate, fileArray, fileDefault)
{
	//var alarmTypes = ["Audio", "Display", "Email", "OpenFile", "OpenFolder", "OpenURL", "RepMemo"];
	
	var repeatMessage  = 'Choose the maximum number of times that the alarm is to be repeated.';
	//  repeatMessage += '\n\nAlternatively, you may ask for the alarm to be repeated periodically on future dates. You cannot do both.';

	var everyMessage   = 'Choose the interval at which the alarm is to be repeated.';
	//  everyMessage  += '\n\nAlternatively, choose one of "day", "week", "two-weeks", "three-weeks", "four-weeks", "month" or "year" (without the quotes).';
	
	var repDef =	['0 times', '1 time',  '2 times', '3 times', '4 times',
					 '5 times', '6 times', '7 times', '8 times', '9 times'];
					 
	var everyDef =	['','minute', 'two minutes', 'five minutes', 'ten minutes', 'fifteen minutes', 'thirty minutes',
					 'hour', 'two hours', 'four hours', 'eight hours', 'twelve hours',
					 '-',
					 'day', 'two-days', 'three-days', 'four-days', 'five-days', 'six-days',
					 'week', 'two-weeks', 'three-weeks', 'four-weeks', 'month', 'year'];
			  
	 var objDef = [['time', 'Alarm Time:', 'text', [''], '', 'Enter the alarm time in the format: HH:MM:SS or HH:MM'],
				  ['repeat', 'Repeat:', 'popup', repDef, '0 times', repeatMessage],
				  ['every', 'Every:', 'popup', everyDef, '', everyMessage],
				  ['audio', 'Audio', 'checkbox', [''], "0", ''],
				  ['display', 'Display', 'checkbox', [''], "0", ''],
				  ['email', 'Email', 'checkbox', [''], "0", ''],
				  ['openFile', 'Open File', 'checkbox', [''], "0", ''],
				  ['openFolder', 'Open Folder', 'checkbox', [''], "0", ''],
				  ['openURL', 'Open URL', 'checkbox', [''], "0", ''],
				  ['repMemo', 'Memo and Display', 'checkbox', [''], "0", 'Choose the type of alarm required.']];

	var formfields = [];

	for (var i = 0; i < 10 ; i += 1)
	{
		formfields[i] = new FormField();
		formfields[i].name = objDef[i][0];
		formfields[i].title = objDef[i][1];
		formfields[i].type = objDef[i][2];
		formfields[i].option = objDef[i][3];
		formfields[i].defaultValue = objDef[i][4];
		formfields[i].description = objDef[i][5];
	}

	var formResults = form(formfields, 'Alarm Definition: ' + fullDateOf(isoDate), 'Go On');
			
	var result = "", time, repeat, every, audio, display, email, openFile, openFolder, openURL, repMemo;

	if (formResults !== null)
	{
		time   = formResults[0];
		repeat = formResults[1];
		every  = formResults[2];
		
		audio      = formResults[3];
		display    = formResults[4];
		email      = formResults[5];
		openFile   = formResults[6];
		openFolder = formResults[7];
		openURL    = formResults[8];
		repMemo    = formResults[9];

		result  = time + itemSep + repeat + itemSep + every + itemSep;
		result += audio + itemSep + display + itemSep + email + itemSep + openFile + itemSep + openFolder + itemSep + openURL + itemSep + repMemo;
	}
			
	for (i = 0; i < 10 ; i += 1)
	{
		delete formfields[i];
		formfields[i] = null;
	}
	formfields = null;
	return result;
}

function parseTime(time)	//	14:03[:59]
{
	var hours, mins, secs;
	var found = time.match(/^\d{2}\:\d{2}(\:\d{2})?$/);
	if (found !== null)
	{
		if (time.length == 5) { time += ':00'; }
		
		hours = parseInt(time.substring(0, 2), 10);
		mins  = parseInt(time.substring(3, 5), 10);
		secs  = parseInt(time.substring(6, 8), 10);
		
		if ((hours < 24) && (mins < 60) && (secs < 60)) { return time; }
	}
	return "";
}

function alarmSelect(isoDate)
{
	var i, res, item, repeat, every, theDate, theISODate, theAlarmTime, theTime, repeatClause, theAlarm, list, memoText, k;
	var alarmItem, alarmType, file, remove, text, mailto, subject, message, path, url, data;
	
	if (isoDate < makeISODate1(new Date())) { beep(); alert('Cannot set alarms for past dates.'); return; }

	var directory = memoFolderPath + '/Alarms';
	var files     = filesystem.getDirectoryContents(directory, false);
	var fileArray = [];
	var n = 0;
	fileArray[n] = gDefaultFile; n += 1;
	if (files !== null) { for (i = 0; i < files.length; i += 1) { if (files[i] != '.DS_Store') { fileArray[n] = files[i]; n += 1; } } }

	do
	{
		res = alarmForm(isoDate, fileArray, gSoundFile);	// result = time + itemSep + repeat + itemSep + every + itemSep + ...

		if (res !== "")	// if not cancelled
		{
			item   = res.split(itemSep);
			time   = item[0];
			repeat = item[1];
			every  = item[2];
			
			time = parseTime(time);
			if (time === "") { beep(); continue; }

			theDate = new Date();
			theISODate = makeISODate1(theDate);
				
			if (isoDate  < theISODate) { beep(); alert('Cannot set alarms for past dates.'); return; }
			if (isoDate == theISODate)
			{
				theAlarmTime = 3600*parseInt(time.substring(0, 2), 10) + 60*parseInt(time.substring(3, 5), 10) + parseInt(time.substring(6, 8), 10);
				theTime = 3600*theDate.getHours() + 60*theDate.getMinutes() + theDate.getSeconds();
				if (theAlarmTime <= theTime) { beep(); alert('Cannot set alarms for past times.'); continue; }
			}
			
			repeat = parseInt(repeat, 10);
			repeat = String(repeat);
			
			if (repeat != "0")	// there is a repeat clause
			{
				//every = every.toLowerCase();	// time is not damaged by toLowerCase()
				
				if (inTheFuture(every)) { repeat = "1"; }	// repeat clause found for future date
				else
				{
					switch (every)
					{
						case 'minute':			every = '00:01:00'; break;
						case 'two minutes':		every = '00:02:00'; break;
						case 'five minutes':	every = '00:05:00'; break;
						case 'ten minutes':		every = '00:10:00'; break;
						case 'fifteen minutes':	every = '00:15:00'; break;
						case 'thirty minutes':	every = '00:30:00'; break;
						case 'hour':			every = '01:00:00'; break;
						case 'two hours':		every = '02:00:00'; break;
						case 'four hours':		every = '04:00:00'; break;
						case 'eight hours':		every = '08:00:00'; break;
						case 'twelve hours':	every = '12:00:00'; break;
						default:				every = ''; 		break;
					}
					//every = parseTime(every);
					if (every === "") { beep(); alert('Invalid "every" clause.'); continue; }
				}
			}

			repeatClause = "";
			if ((repeat != "0") && (every !== "")) { repeatClause = ';REPEAT=' + repeat + ';EVERY=' + every; }
			
			res = extraForms(isoDate, fileArray, gSoundFile, res);
			if (res === "") { return; }
			
			theAlarm = '<<ALARM=' + time + repeatClause;	//  + '>>\n';
			
			list = res.split(listSep);	// split the basic alarm data and alarm definitions. list[0] not used here
			
			memoText = "";

			for (k = 1; k < list.length; k += 1)	// work through alarm definitions
			{
				alarmItem = list[k].split(itemSep);
				alarmType  = alarmItem[0];
				
				//alarmTypes = ["Audio", "Display", "Email", "OpenFile", "OpenFolder", "OpenURL", "RepMemo"];
				
				eprint('alarmSelect:alarmType=' + alarmType);
			
				if (alarmType == "Audio")	// audio alarm		result = sound + itemSep + remove;
				{
					file   = alarmItem[1];
					remove = alarmItem[2];
		
					if (remove == "1")	// delete sound so don't generate an alarm
					{
						if (file != gDefaultFile)
						{
							filesystem.remove(memoFolderPath + '/Alarms/' + file);
							if (file == gSoundFile) { gSoundFile = gDefaultFile; }
						}
						else { beep(); }
					}
					else
					{
						gSoundFile = file.replace(/\;/g, "%3B");
						theAlarm += ';SOUND=' + file;
					}
				}
				else if (alarmType == "Display")
				{
					text = alarmItem[1].replace(/\;/g, "%3B");
					theAlarm += ';TEXT=' + text;
				}
				else if (alarmType == "Email")
				{
					mailto  = alarmItem[1].replace(/\;/g, "%3B");
					subject = alarmItem[2].replace(/\;/g, "%3B");
					message = alarmItem[3].replace(/\;/g, "%3B");
					theAlarm += ';TO=' + mailto + ';SUBJECT=' + subject + ';MESSAGE=' + message;
				}
				else if (alarmType == "OpenFile")
				{
					path = alarmItem[1].replace(/\;/g, "%3B");
					theAlarm += ';OPEN=' + path;
				}
				else if (alarmType == "OpenFolder")
				{
					path = alarmItem[1].replace(/\;/g, "%3B");
					theAlarm += ';SHOW=' + path;
				}
				else if (alarmType == "OpenURL")
				{
					url = alarmItem[1].replace(/\;/g, "%3B");
					theAlarm += ';URL=' + url;
				}
				else if (alarmType == "RepMemo")
				{
					memoText += alarmItem[1].replace(/%0A/g, "\n") + "\n";
					text = alarmItem[1].replace(/\;/g, "%3B");
					theAlarm += ';MEMO=' + text;
				}

			}
			theAlarm += '>>\n';
				
			if (memo_info.visible)
			{
				memo.data += memoText + theAlarm;
			}
			else
			{
				data = getMemo(isoDate);
				data +=  memoText + alarmMarker + theAlarm;
				saveMemo(isoDate, data);
			}
			updateCalendar();			// was updateDate(false);
			updateMemos();
			main_window.focus();
			focusWidget();
			break;
		} else { return; }

	} while (true);
}

function makeAlarmDir(accessMode)
{
	var path  = memoFolderPath + '/Alarms';
	if (filesystem.itemExists(path) && filesystem.isDirectory(path)) { return; }
	eprint('makeAlarmDir:mkdir=' + filesystem.createDirectory(path));
	eprint('makeAlarmDir:chmod=' + filesystem.changeMode(path, accessMode));
}

function convertToSecs(time)	// time in format hh:mm:ss
{
	var hours = parseInt(time.substring(0, 2), 10);
	var mins  = parseInt(time.substring(3, 5), 10);
	var secs  = parseInt(time.substring(6, 8), 10);

	return 3600*hours + 60*mins + secs;	// time in seconds
}

function convertToTime(seconds)	// time in format hh:mm:ss
{
	var hours = String(Math.floor(seconds / 3600));
	var rem   = seconds % 3600;
	var mins  = String(Math.floor(rem / 60));
	var secs  = String(rem % 60);
	
	if (hours.length == 1) { hours = '0' + hours; }
	if (mins.length  == 1) { mins  = '0' + mins;  }
	if (secs.length  == 1) { secs  = '0' + secs;  }

	return hours + ':' + mins + ':' + secs;
}

function getAlarms(item) // example: item = "ALARM=20:21:45[;REPEAT=3;EVERY=00:15:00];SOUND=G6AUC.wav".split(';');
{
	var alarmList = "";
	
	eprint('getAlarms:item=' + item);
	
	var time = parseTime(item[0].split('=')[1]);
	if (time === "") { return; }

	var repeat  = "0";
	var every   = "";
	var sound   = "";
	var text    = "";
	var to      = "";
	var subject = "";
	var message = "";
	var open    = "";
	var show    = "";
	var url     = "";
	var memo    = "";
	
	var alarm, pair, command, value, nextTime;
	
	for (var k = 1; k < item.length; k += 1)	// may not be executed at all
	{
		pair = item[k].split('=');
		command = pair[0];
		value   = pair[1];
		
		switch (command.toLowerCase())
		{
			case "repeat": 	repeat = value; break;
			case "every" : 	every  = value.toLowerCase(); break;

			case "sound":  	sound   = value; break;
			case "text":	text    = value; break;
			case "to":		to      = value; break;
			case "subject": subject = value; break;
			case "message": message = value; break;
			case "open":	open    = value; break;
			case "show":    show    = value; break;
			case "url":		url		= value; break;
			case "memo":	memo    = value; break;

			default:	   break;
		}
	}
	
	for (var r = 0; r <= repeat; r += 1)
	{
		if ((sound !== "") || (item.length < 2))
		{
			alarm = time + itemSep + 'Audio' + itemSep + sound + itemSep + every;
			if (alarmList === "") { alarmList = alarm; } else { alarmList += listSep + alarm; }
		}
	
		if (text !== "")
		{
			alarm = time + itemSep + 'Display' + itemSep + text + itemSep + every;
			if (alarmList === "") { alarmList = alarm; } else { alarmList += listSep + alarm; }
		}
	
		if (to !== "")
		{
			alarm = time + itemSep + 'Email' + itemSep + to  + itemSep + subject  + itemSep + message + itemSep + every;
			if (alarmList === "") { alarmList = alarm; } else { alarmList += listSep + alarm; }
		}
		
		if (open !== "")
		{
			alarm = time + itemSep + 'OpenFile' + itemSep + open + itemSep + every;
			if (alarmList === "") { alarmList = alarm; } else { alarmList += listSep + alarm; }
		}
		
		if (show !== "")
		{
			alarm = time + itemSep + 'OpenFolder' + itemSep + show + itemSep + every;
			if (alarmList === "") { alarmList = alarm; } else { alarmList += listSep + alarm; }
		}

		if (url !== "")
		{
			alarm = time + itemSep + 'OpenURL' + itemSep + url + itemSep + every;
			if (alarmList === "") { alarmList = alarm; } else { alarmList += listSep + alarm; }
		}
		
		if (memo !== "")
		{
			alarm = time + itemSep + 'RepMemo' + itemSep + memo + itemSep + every;
			if (alarmList === "") { alarmList = alarm; } else { alarmList += listSep + alarm; }
		}

		if (inTheFuture(every))
		{
				break;	// these may only fire once
		}
		
		nextTime = convertToSecs(time) + convertToSecs(every) ;
		if (nextTime >= 86400) { break; }
		time = convertToTime(nextTime);
	}
	return alarmList;
}

function setAlarm(item)
{
	var alarmList = getAlarms(item);
	
	if (gAlarmList === "") { gAlarmList = alarmList; } else { gAlarmList += listSep + alarmList; }
}

function clearAlarms()
{
	gAlarmList = "";
}

function setAlarmParams(i, times)
{
	var sound, path, file, testPath;
	var mailto, subject, message;

	var alarm = times[i].split(itemSep);
	var time  = alarm[0];
	var alarmType = alarm[1];

	var hours = parseInt(time.substring(0, 2), 10);
	var mins  = parseInt(time.substring(3, 5), 10);
	var secs  = parseInt(time.substring(6, 8), 10);
		
	var alarmTime = 3600*hours + 60*mins + secs;	// alarm time in seconds from midnight
		
	if (alarmTime < gFirstAlarmTime) { return "continue"; }	// ignore old alarms

	gFirstAlarmTime = alarmTime;
	gAlarmType = alarmType;
	gRepeatAlarm = times[i];					// for day/week/two-weeks/three-weeks/four-weeks/month/year repeats
		
	eprint('setAlarmParams:i=' + i + '>>>' + 'gFirstAlarmTime=' + gFirstAlarmTime + '>>>' + 'gAlarmType=' + gAlarmType);
		
	//alarmTypes = ["Audio", "Display", "Email", "OpenFile", "OpenFolder", "OpenURL", "RepMemo"];

	if (alarmType == "Audio")
	{
		sound = 'G6AUC.wav';					// default alarm sound
		path  = 'Resources/Sounds/G6AUC.wav';	// default path
		file  = alarm[2].replace(/%3B/g, ";");
		if (file !== "")						// a sound file has been specified
		{			
			if (file != sound)
			{ 
				testPath = memoFolderPath + '/Alarms/' + file;
				if (filesystem.itemExists(testPath)) { path = testPath; }
			}
		}
		gSoundPath = path;
		eprint('setAlarms:gSoundPath=' + gSoundPath);
	}
	else if (alarmType == "Display")
	{
		gDisplayText = alarm[2].replace(/%3B/g, ";");
	}
	else if (alarmType == "Email")
	{
		mailto  = alarm[2].replace(/%3B/g, ";");
		subject = alarm[3].replace(/%3B/g, ";");
		message = alarm[4].replace(/%3B/g, ";");
		
		gEmailText = 'mailto:' + mailto + '?Subject=' + escape(subject) + '&Body=' + escape(message.replace(/\%0A/g, "\n"));
	}
	else if ((alarmType == "OpenFile") || (alarmType == "OpenFolder"))
	{
		gOpenPath = alarm[2].replace(/%3B/g, ";");
	}
	else if (alarmType == "OpenURL")
	{
		gOpenURL = alarm[2].replace(/%3B/g, ";");
	}
	else if (alarmType == "RepMemo")
	{
		gDisplayText = alarm[2].replace(/%3B/g, ";");	// repeating memos produce a display text
	}
	return "";
}

function setAlarms(reset, theDate)	// called whenever gAlarmList has been changed
{
	var timerInterval;
	
	eprint('setAlarms:gAlarmList=' + gAlarmList);

	if (gAlarmList === "") { alarmTimer.ticking = false; return; }
	
	gAlarmISODate = makeISODate1(theDate);
	
	var theHours = theDate.getHours();
	var theMins  = theDate.getMinutes();
	var theSecs  = theDate.getSeconds();
	var theTime  = 3600*theHours + 60*theMins + theSecs;	// current time in seconds from midnight

	if (reset) { gNextAlarm = 0; gFirstAlarmTime = theTime; }

	var times = gAlarmList.split(listSep); eprint('setAlarms:times.length=' + times.length);
	times.sort();

	for (var i = gNextAlarm; i < times.length; i += 1)
	{
		if (setAlarmParams(i, times) == "continue") { continue; }	// ignore old alarms

		if (gFirstAlarmTime < theTime + 3)
		{
			gNextAlarm = i + 1; alarmReset(); break;
		}
		else	// set timer for first alarm
		{
			gNextAlarm = i + 1;		// to prevent alarm firing more than once
			
			timerInterval = gFirstAlarmTime - theTime;
			if ((gAlarmType == "Audio"))	// || (alarmType == "Display"))
			{
				if (timerInterval > 60 ) { timerInterval -= 30; gNextAlarm = i; gAdvanceAlarm = true; }
			}
			alarmTimer.interval = timerInterval;
			alarmTimer.ticking = true;
			break;
		}
	}
}

function alarmReset()			// called when the alarmTimer fires
{
	var nextAlarm = gAlarmISODate + ':' + gFirstAlarmTime + ':' + gNextAlarm; 
	preferences.nextAlarmPref.value = nextAlarm;
	savePreferences();
	lprint('Alarm Fired - nextAlarm: ' + nextAlarm);
	executeAlarm(gAlarmType);
	if (gAdvanceAlarm) { gAdvanceAlarm = false; } else { resetAlarm(gRepeatAlarm); }
	var theDate  = new Date();
	setAlarms(false, theDate);		// set next alarm
}

function executeAlarm(alarmType)
{
	switch(alarmType)
	{
		case "Audio":      soundAlarm(gSoundPath);		break;
		case "Display":    displayAlarm(gDisplayText);	break;
		case "Email":      sendEmail(gEmailText);		break;
		case "OpenFile":   openFileOrFolder(gOpenPath);	break;
		case "OpenFolder": openFileOrFolder(gOpenPath);	break;
		case "OpenURL":    openURL(gOpenURL);			break;
		case "RepMemo":    displayAlarm(gDisplayText);	break;
		default:	       break;
	}
}

function soundAlarm(soundPath)
{
	eprint('soundAlarm:soundPath=' + soundPath);
	play(soundPath);
}

function displayAlarm(displayText)
{
	eprint('displayAlarm:displayText=' + displayText);
	display_window.hOffset = Math.round(0.5*(screen.width  - display_window.width ));
	display_window.vOffset = Math.round(0.5*(screen.height - display_window.height));
	display.data = displayText.replace(/\%0A/g, "\n");
	display_window.level = "topmost";
	updateNow();
	display_window.visible = true;
}

function sendEmail(emailText)
{
	eprint('sendEmail:emailText=' + emailText);
	openURL(emailText);
}

function openFileOrFolder(openPath)
{
	eprint('openFileOrFolder:openPath=' + openPath);
	filesystem.open(openPath);
}

function nextRepeatDate(isoDate, every)
{	
	var len   = isoDate.length;
	var year  = parseInt(isoDate.substring(0,       len - 4), 10);
	var month = parseInt(isoDate.substring(len - 4, len - 2), 10);
	var day   = parseInt(isoDate.substring(len - 2         ), 10);
	
	var maxDays = daysInMonth(year, month); // month 1..12

	switch (every)
	{
		case "day":			day += 1;
							if (day > maxDays) { day -= maxDays; month += 1; if (month > 12) { month = 1; year += 1; } }
							break;	
	
		case "two-days":	day += 2;
							if (day > maxDays) { day -= maxDays; month += 1; if (month > 12) { month = 1; year += 1; } }
							break;	
	
		case "three-days":	day += 3;
							if (day > maxDays) { day -= maxDays; month += 1; if (month > 12) { month = 1; year += 1; } }
							break;	
	
		case "four-days":	day += 4;
							if (day > maxDays) { day -= maxDays; month += 1; if (month > 12) { month = 1; year += 1; } }
							break;	
	
		case "five-days":	day += 6;
							if (day > maxDays) { day -= maxDays; month += 1; if (month > 12) { month = 1; year += 1; } }
							break;	
	
		case "six-days":	day += 6;
							if (day > maxDays) { day -= maxDays; month += 1; if (month > 12) { month = 1; year += 1; } }
							break;	
	
		case "week":		day += 7;
							if (day > maxDays) { day -= maxDays; month += 1; if (month > 12) { month = 1; year += 1; } }
							break;	
	
		case "two-weeks":	day += 14;
							if (day > maxDays) { day -= maxDays; month += 1; if (month > 12) { month = 1; year += 1; } }
							break;	
	
		case "three-weeks":	day += 21;
							if (day > maxDays) { day -= maxDays; month += 1; if (month > 12) { month = 1; year += 1; } }
							break;	
	
		case "four-weeks":	day += 28;
							if (day > maxDays) { day -= maxDays; month += 1; if (month > 12) { month = 1; year += 1; } }
							break;	
	
		case "month":		month += 1; if (month > 12) { month = 1; year += 1; }
							maxDays = daysInMonth(year, month);
							if (day > maxDays) { day = maxDays; }
							break;	
	
		case "year":		year += 1;
							maxDays = daysInMonth(year, month);
							if (day > maxDays) { day = maxDays; }
							break;
		default:
							break;
	}
	return makeISODate3(year, month, day);
}

function resetAlarm(entry)	// called when an alarm has fired to set up an alarm for the next day/week/month/year
{
	var alarm = entry.split(itemSep);
	var time      = alarm[0];
	var alarmType = alarm[1];
	var every;
	var newText;
	var isoDate = gAlarmISODate;
	
	switch(alarmType)
	{
		case "Audio":	// alarm = time + itemSep + 'Audio' + itemSep + sound + itemSep + every;
						every = alarm[3];
						if (! inTheFuture(every)) { break; }
						var sound = alarm[2];
						isoDate = nextRepeatDate(isoDate, every);
						newText = '<<ALARM=' + time + ';REPEAT=1;EVERY=' + every + ';SOUND=' + sound + '>>';
						updateMemoAlarm(isoDate, newText);
						break;
						
		case "Display":	// alarm = time + itemSep + 'Display' + itemSep + text + itemSep + every;
						every = alarm[3];
						if (! inTheFuture(every)) { break; }
						var text = alarm[2];
						isoDate = nextRepeatDate(isoDate, every);
						newText = '<<ALARM=' + time + ';REPEAT=1;EVERY=' + every + ';TEXT=' + text + '>>';
						updateMemoAlarm(isoDate, newText);
						break;
						
		case "Email":	// alarm = time + itemSep + 'Email' + itemSep + to  + itemSep + subject  + itemSep + message + itemSep + every;
						every = alarm[5];
						if (! inTheFuture(every)) { break; }
						var to = alarm[2];
						var subject = alarm[3];
						var message = alarm[4];
						isoDate = nextRepeatDate(isoDate, every);
						newText = '<<ALARM=' + time + ';REPEAT=1;EVERY=' + every + ';TO=' + to + ';SUBJECT=' + subject + ';MESSAGE=' + message + '>>';
						updateMemoAlarm(isoDate, newText);
						break;

		case "OpenFile":// alarm = time + itemSep + 'OpenFile' + itemSep + open + itemSep + every;
						every = alarm[3];
						if (! inTheFuture(every)) { break; }
						var open = alarm[2];
						isoDate = nextRepeatDate(isoDate, every);
						newText = '<<ALARM=' + time + ';REPEAT=1;EVERY=' + every + ';OPEN=' + open + '>>';
						updateMemoAlarm(isoDate, newText);
						break;
						
		case "OpenFolder":// alarm = time + itemSep + 'OpenFolder' + itemSep + show + itemSep + every;
						every = alarm[3];
						if (! inTheFuture(every)) { break; }
						var show = alarm[2];
						isoDate = nextRepeatDate(isoDate, every);
						newText = '<<ALARM=' + time + ';REPEAT=1;EVERY=' + every + ';SHOW=' + show + '>>';
						updateMemoAlarm(isoDate, newText);
						break;

		case "OpenURL":// alarm = time + itemSep + 'OpenURL' + itemSep + url + itemSep + every;
						every = alarm[3];
						if (! inTheFuture(every)) { break; }
						var url = alarm[2];
						isoDate = nextRepeatDate(isoDate, every);
						newText = '<<ALARM=' + time + ';REPEAT=1;EVERY=' + every + ';URL=' + url + '>>';
						updateMemoAlarm(isoDate, newText);
						break;

		case "RepMemo":	// alarm = time + itemSep + 'RepMemo' + itemSep + memo + itemSep + every;
						every = alarm[3];
						if (! inTheFuture(every)) { break; }
						var memo = alarm[2];
						var memoText = memo.replace(/%3B/g, ";").replace(/%0A/g, "\n") + "\n";
						isoDate = nextRepeatDate(isoDate, every);
						newText = memoText + '<<ALARM=' + time + ';REPEAT=1;EVERY=' + every + ';MEMO=' + memo + '>>';
						updateMemoAlarm(isoDate, newText);
						break;
						
		default:		break;
	}
}

function updateMemoAlarm(isoDate, theAlarm)
{
	var message, result;
	
	if ((memo_info.visible) && (isoDate == gISOdate))
	{
		beep();
		message  = "Month Calendar must close the memo window to set an alarm for you.";
			message += " You may save the memo contents, or cancel your changes.";
		result = alert(message,"Save", "Cancel");
		if (result == "1") { saveMemoWindow(); } else { closeMemoWindow(); }
	}
	eprint('New alarm for ' + isoDate + ' ' + theAlarm);
	var data = getMemo(isoDate);
	data += alarmMarker + theAlarm;
	saveMemo(isoDate, data);
}

function updateAlarmPrefs()
{
	display.font = preferences.displayFontPref.value;
	display.size = preferences.displayFontSizePref.value;
	display.color = preferences.displayTextColor.value;
	displayBg.colorize = preferences.displayBgColor.value;
	
	if (preferences.alarmMarkerPref.value == "0") {
		alarmMarker = "";
	} else {
		alarmMarker = "Alarm:";
	}
}

//isoDate = makeISODate3(year, month, day);
//gAlarmISODate = makeISODate1(theDate);
//var theTime  = 3600*theHours + 60*theMins + theSecs;	// current time in seconds from midnight
//if (reset) { gNextAlarm = 0; gFirstAlarmTime = theTime; }
//function nextISODate(isoDate)
//function prevISODate(isoDate)

function catchUp()	// work in progress to execute missed alarms.
{
	function findActions(data) { return data.match(/\<\<\w*\=[^\;\n\<\>]*?(\;\w*\=[^\;\n\<\>]*?)*\>\>/g); }

	var actions = null, i, action, item, main, command, value, alarms;
	
	var nextAlarm = preferences.nextAlarmPref.value;	// the first missed alarm on alarmISODate - may not exist
	if (nextAlarm === "") { return null; }
	var part = nextAlarm.split(':');
	var alarmISODate    = part[0];
	var firstAlarmTime  = part[1];
	var firstAlarmIndex = Number(part[2]);
	
	var alarmList = "";
	
	var data = getMemo(alarmISODate);
	if (data !== "") { actions = findActions(data); }
	if (actions !== null)
	{
		for (i = 0; i < actions.length; i += 1)
		{
			action  = actions[i];	// <<COLOR=blue>> or <<ALARM=20:21:45;SOUND=g6auc>>
			item    = action.substring(2, action.length - 2).split(';');
			main    = item[0].split('=');
			command = main[0].toLowerCase();	//eprint('command=' + command);
			value   = main[1];					//eprint('value=  ' + value);
			switch(command)
			{
				case 'color':  break;
				case 'colour': break;
				case 'alarm':  alarms = getAlarms(item);
							   if (alarmList === "") { alarmList = alarms; } else { alarmList += listSep + alarms; }
							   break;
				case 'event':  break;
				default:	   eprint('"' + command + '" is not a valid memo command.'); break;
			}
		}
	}
	eprint('catchUp:alarmList=   ' + alarmList);
	
	// alarmList is a list of all alarms on alarmISODate. Some (or all) may already have fired.
	
	var alarm, time, alarmType;		// hours, mins, secs, alarmTime, sound, path, file, testPath;
									// var mailto, subject, message, timerInterval;

	var times = alarmList.split(listSep); eprint('catchUp:times.length=' + times.length);
	times.sort();
	
	for (i = firstAlarmIndex; i < times.length; i += 1)	// loop through the alarms that have not already fired
	{
		alarm = times[i].split(itemSep);
		time  = alarm[0];
		alarmType = alarm[1];
		eprint('catchUp:executing alarm: time=' + time + ' alarmType=' + alarmType);
	}
}
