/*
	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.5.1
	4 July, 2009
	Copyright © 2005-2009 Harry Whitfield
	mailto:g6auc@arrl.net
*/

/*global bf, bkgd, buildCalendarVitality, customWeekOfYear, displayTooltip, main_frame, 
		 main_window, marker, memo, memo_info, next, prev, removeTooltip, theTimer
		 eprint , itemSep , listSep , makeISODate1 , memoFolderPath , time 
		 GlassWindow, cardinalOf, clearAlarms, column, fullDateOf, gISOdate, getCachedEvents,
		 getMemo, getMemoLines, lprint, makeISODate3, onDragDropped, onMultiClicked,
		 openMemoWindow, row, saveMemo, setAlarm, setAlarms, simpleForm, testLicense, theISOMonth,
		 windowTimer, lock, restorePlist, savePlist
*/

/*members alignment, altKey, appendChild, autoModePref, autoOpenPref, 
    backgroundPref, bgColor, bgColorization, bgOpacity, color, colorize, 
    data, defaultValue, description, dockColorization, dockTextColor, event, 
    floor, focus, font, fontDeltaPref, fontSizePref, generalFontPref, 
    getDate, getDay, getFullYear, getHours, getMinutes, getMonth, 
    getSeconds, hAlign, hOffset, height, i, iCalPref, indexOf, interval, 
    isoDate, j, join, lastIndexOf, length, mainAnchorXPref, mainAnchorYPref, 
    mainTooltipPref, match, memoBgColor, memoBgOpacity, memoColor, 
    memoFontPref, memoFontSizePref, memoMarkersPref, monthArrowsPref, 
    monthPref, monthTextColor, myTooltip, name, onDragDrop, onDragEnter, 
    onDragExit, onMouseEnter, onMouseExit, onMouseUp, onMultiClick, opacity, 
    option, platform, realFontSizePref, recalcShadow, replace, round, row, 
    satTextColor, setColorize, setDimension, setOpacity, shiftKey, size, 
    split, src, startWeekOnSunday, substring, sunTextColor, textColor, 
    ticking, title, toLowerCase, toString, todayMarkerColor, 
    todayMarkerHOffset, todayMarkerHeight, todayMarkerOpacity, 
    todayMarkerPref, todayMarkerVOffset, todayMarkerWidth, tooltip, type, 
    vOffset, value, visible, weekColor, weekNumberPref, width, windowTimer, 
    yearPref, zOrder
*/

// globals

var systemPlatform = system.platform;
//systemPlatform = 'windows';	// for testing Windows code on the Macintosh
print('systemPlatform=' + systemPlatform);

var parent = main_frame;			// was main_window;

var year;
var lastYear = 9999;				// code is safe until 10000 AD.
var month;

var font;
var fontSize;
var fontStyle;
var biggerFontSize;
var realFontSize;

var width;
var height;
var scale;
	
var hOffset;
var vOffset;

var mainFrameWidth;
var mainFrameHeight;

var glassWindow = null;
var greyWindow  = null;
var whiteWindow = null;

var displayMemoCount = 3;
var sem = "";
var selectHotKey = null;
var speechHotKey = null;

var oldSelectHotKeyPref;
var oldSpeechHotkeyPref;
var oldMemoScalePref;

var extraFontSize = 0;
var fontDelta = 0;

var Head = null;

var T = null;
var D = null;
var M = null;

var widgetName = null;

var nweek;	// Does this need to be global?

var updateCalendar = function () { alert("updateCalendar forward"); };

var calendar = function (year, month) { alert("calendar forward"); };

function isLeapYear(year)
{
    if ((year %   4) !== 0) { return false; }
    if ((year % 400) === 0) { return true; }
    if ((year % 100) === 0) { return false; }
    return true;
}

function daysInMonth(year, month) // month 1..12
{
    var daysInMonthArr = [31,28,31,30,31,30,31,31,30,31,30,31];
    if (month != 2) { return daysInMonthArr[month - 1]; }
    if (isLeapYear(year)) { return 29; } return 28;
}

function dayOfYear(year, month, day) // month 1..12
{
    var startDayOfMonth = [0,31,59,90,120,151,181,212,243,273,304,334];
    var leap = 0;
    if (month > 2) { leap = Number(isLeapYear(year)); }
    return startDayOfMonth[month - 1] + day + leap;
}

function weekOfYear(year, month, day) // month 1..12
{
    var d, week;
    if (preferences.weekNumberPref.value == bf("Hidden")) { return 99; }

    if (preferences.weekNumberPref.value == bf("Dots"))   { return 99; }

    if (preferences.weekNumberPref.value == "ISO8601")
    {
    	d = new Date(year, 0, 4).getDay();	// d: 0..6, Sun=0, Sat=6
    	if (d === 0) { d = 7; }					// d: 1..7, Mon=1, Sun=7;
    	d = dayOfYear(year, month, day) - 4 + d;
    	if (d < 1) { return weekOfYear(year - 1, 12, 31); }
    	week = Math.floor((d - 1) / 7) + 1;
    	if ((month == 12) && (day > 28)) { if (weekOfYear(year + 1, 1, day - 24) == 2) { return 1; } }
    	return week;
    }
    return customWeekOfYear(year, month, day);
}

function dayOfWeek(year, month, day) // month 1..12
{
	return new Date(year, month - 1, day).getDay();	// Sun=0, Mon=1, Sat = 6
}

function updateTooltip()
{
	var d = new Date();
	Head.myTooltip = bf("todaysDate") + "\n\n" + d.toString();
}

function updateMemos()
{
	if (memo_info !== null) 
	{
		memo.font = preferences.memoFontPref.value;
		memo.size = preferences.memoFontSizePref.value;
	}
}

function updateDate(forced)
{
	var theDate, theYear, theMonth, timerInterval;
	
	theTimer.ticking = false;
	
	theDate  = new Date();
	theYear  = theDate.getFullYear();
	theMonth = theDate.getMonth() + 1;

	timerInterval = 86400 - 3600*theDate.getHours() - 60*theDate.getMinutes() - theDate.getSeconds(); // is always >= 1
	if (timerInterval > 60 ) { timerInterval -= 30; }
	theTimer.interval = timerInterval;
	theTimer.ticking = true;
		
	if ((preferences.autoModePref.value == "1") || forced)
	{
		preferences.yearPref.value  = String(theYear);
		preferences.monthPref.value = String(theMonth);
	}
		
	buildCalendarVitality(theDate, preferences.dockColorization.value, preferences.dockTextColor.value);

	updateCalendar();
	updateMemos();
}

function setWindowLock(flag)
{
	if (flag)
	{
		preferences.mainAnchorXPref.value = String(main_window.hOffset);
		preferences.mainAnchorYPref.value = String(main_window.vOffset);
		
		windowTimer.ticking = true;
		preferences.windowTimer.value = "1";
		lock.src = "Resources/Images/locked.png";
		lock.tooltip = "Window position is locked.";
	}
	else
	{
		windowTimer.ticking = false;
		preferences.windowTimer.value = "0";
		lock.src = "Resources/Images/unlocked.png";
		lock.tooltip = "Window position is unlocked.";
	}
}


function toggleWindowLock()
{
	windowTimer.ticking = ! windowTimer.ticking;
	setWindowLock(windowTimer.ticking);
}

function myMoveToToday()
{ 
	if (system.event.altKey)
	{ 
		setWindowLock(true);
	}
	else if (system.event.shiftKey)
	{
		setWindowLock(false);
	}
	else
	{
		updateDate(true); removeTooltip();
	}
}

function myDisplayTooltip() { updateTooltip(); displayTooltip(-1, 0); }

function makeHead(scale, width, height, hOffset, vOffset, font, size, style, zOrder, tooltip)
{
	var monthTextColor = preferences.monthTextColor.value;
	var todayMarkerColor   = preferences.todayMarkerColor.value;

	if (Head === null) { Head = new Text(); }
	var cell = Head;
	cell.data = '';
	cell.hAlign = "left";
	cell.width = Math.round(8*width*scale);
	cell.height = height;
	cell.hOffset = hOffset;
	cell.vOffset = vOffset + height;
	cell.color = monthTextColor;
	cell.opacity = 255;
	cell.bgColor = todayMarkerColor;
	cell.bgOpacity = 0;
	cell.font = font;
	cell.size = size + 2;
	cell.zOrder = zOrder;
	cell.myTooltip = bf("todaysDate");
	cell.onMouseUp    = myMoveToToday;
	cell.onMouseEnter = myDisplayTooltip;
	cell.onMouseExit  = removeTooltip;
	parent.appendChild(cell);
}

function smallSize(size)
{
	if (size <= 13) { return 9;  }
	if (size == 14) { return 10; }
	if (size == 16) { return 11; }
	if (size == 18) { return 12; }
	if (size == 20) { return 13; }
	if (size == 22) { return 14; }
	if (size == 24) { return 16; }
	if (size == 26) { return 18; }
	if (size == 28) { return 18; }
	if (size == 32) { return 22; }
	if (size == 36) { return 24; }
	if (size == 40) { return 26; }
	if (size == 44) { return 28; }
	if (size == 48) { return 32; }
	if (size == 52) { return 36; }
	if (size == 56) { return 40; }
	if (size == 64) { return 44; }
	if (size == 72) { return 48; }
	return size;
}

function createTable()
{
	var j;
	if (T !== null) { return; }

	T = [];
	D = [];
	M = [];
	
	for (var i = 0; i < 7; i += 1)
	{
		T[i] = [];
		D[i] = [];
		M[i] = [];

		for (j = 0; j < 8; j += 1)
		{
			T[i][j] = new Text();
		}
	}
}

function displayTheTooltip() { displayTooltip(this.i, this.j); }

function makeTable(scale, width, height, hOffset, vOffset, font, size, style, zOrder, tooltip)
{
	var textColor    = preferences.textColor.value;
	var todayMarkerColor = preferences.todayMarkerColor.value;
	var weekColor    = preferences.weekColor.value;
	var weekOpacity  = 255;
	
	if (preferences.weekNumberPref.value == bf("Hidden")) { weekOpacity = 0; }

	createTable();
	
	var j, cell;
	for (var i = 0; i < 7; i += 1)
	{
		// T[i] = [];
		// D[i] = [];
		// M[i] = [];

		for (j = 0; j < 8; j += 1)
		{
			// T[i][j] = new Text();
			cell = T[i][j];
			cell.data = '  ';
			cell.alignment = "left";
//			cell.wrap = true;
			cell.width = width;
			cell.height = height;
			cell.hOffset = hOffset + Math.round(j*width*scale);
			cell.vOffset = (i+1)*height + vOffset;
			if (j === 0) { cell.color = weekColor; cell.opacity = weekOpacity; } else  { cell.color = textColor; cell.opacity = 255; }
			cell.bgColor = todayMarkerColor;
			cell.bgOpacity = 0;
			cell.font = font;
			if (i !== 0) { cell.size = size; } else { cell.size = smallSize(size); }
			cell.zOrder = zOrder;
			cell.myTooltip = tooltip;
			cell.i = i;
			cell.j = j;
			cell.onMouseEnter = displayTheTooltip;
			cell.onMouseExit  = removeTooltip;
			D[i][j] = false;
			M[i][j] = false;
			parent.appendChild(cell);
		}
	}
}

function resetTable(T, D, M, color, bgColor, wkColor)
{
	var j;
	for (var i = 0; i < 7; i += 1)
	{
		for (j = 0; j < 8; j += 1)
		{
			T[i][j].data = '  ';   T[i][j].bgOpacity = 0;
			T[i][j].color = color; T[i][j].bgColor = bgColor;
			T[i][j].myTooltip = "";
			if (j !== 0)
			{
				T[i][j].onMultiClick = ""; T[i][j].onDragDrop = "";
				T[i][j].onDragEnter  = ""; T[i][j].onDragExit = "";
			}
			else { T[i][j].color = wkColor; }
			D[i][j] = false;
			M[i][j] = false;
		}
	}
}

function setMarkers(T, D, M, opacity)
{
	var mmOpacity = opacity;
	var tmOpacity = opacity;
	
	if (preferences.memoMarkersPref.value == bf("Never"))  { mmOpacity =   0; }
	if (preferences.todayMarkerPref.value == bf("Never"))  { tmOpacity =   0; }
	
	if (preferences.memoMarkersPref.value == bf("Always")) { mmOpacity = 255; }
	if (preferences.todayMarkerPref.value == bf("Always")) { tmOpacity = 255; }
	
	if (mmOpacity !== 0) { mmOpacity = preferences.memoBgOpacity.value; }

	if (tmOpacity !== 0) { tmOpacity = preferences.todayMarkerOpacity.value; }

	marker.opacity = 0;
	
	var j;
	for (var i = 1; i < 7; i += 1)
	{
		for (j = 0; j < 8; j += 1)
		{
			if (M[i][j]) { T[i][j].bgOpacity = mmOpacity; }
//			if (D[i][j]) { T[i][j].bgOpacity = 0; marker.opacity = tmOpacity; }
			if (D[i][j]) { marker.opacity = tmOpacity; }
		}
	}
}

function stringWidth(string, fontname, fontstyle, fontsize)
{
	var tmpText = new Text();
	var width;
	tmpText.opacity = 0;
	tmpText.font = fontname;
	//tmpText.style = fontstyle;
	tmpText.size = fontsize;
	tmpText.data = string;
	width = tmpText.width;
	tmpText = null;
	return width;
}

function head(year, month, hOffset, fontname, fontstyle, fontsize)
{
	var theMonths   = [bf("January"),bf("February"),bf("March"),bf("April"),bf("May"),bf("June"),
				   	   bf("July"),bf("August"),bf("September"),bf("October"),bf("November"),bf("December")];
	var string = theMonths[month-1] + ' ' + year;
	var width = 1.05*stringWidth(string, fontname, fontstyle, fontsize + 2);
	Head.data = string;
	Head.hOffset = ((parent.width - width)>>1) +  hOffset - (10*fontsize>>3);
	Head.width = width;
}

function cal(year, month, hOffset, font, fontStyle, fontSize)
{
	head(year, month, hOffset, font, fontStyle, fontSize);
	calendar(year, month);
}

function showButtons(opacity)
{
	if (preferences.monthArrowsPref.value == "Always") { prev.opacity = next.opacity = 255; } else { prev.opacity = next.opacity = opacity; }
	
	setMarkers(T, D, M, opacity);
}

function nextBigger(size)
{
	if (size <   14) { return size + 1; }
	if (size <   28) { return size + 2; }
	if (size <   56) { return size + 4; }
	if (size <   72) { return size + 8; }
					   return 72;	
}

function adjustHeight()
{
	if (T[5][0].data == '  ')      { parent.height = mainFrameHeight - 2*height; }
	else if (T[6][0].data == '  ') { parent.height = mainFrameHeight -   height; }
	else 						   { parent.height = mainFrameHeight; }
	if (glassWindow !== null) { glassWindow.setDimension(parent.width, parent.height); }
	if (greyWindow  !== null) {  greyWindow.setDimension(parent.width, parent.height); }
	if (whiteWindow !== null) { whiteWindow.setDimension(parent.width, parent.height); }
	bkgd.height = parent.height;
	main_window.recalcShadow();
}

updateCalendar = function ()
{
	year  = parseInt(preferences.yearPref.value, 10);
	month = Number(preferences.monthPref.value);
	
	if (isNaN(year)) { year = 2006; preferences.yearPref.value = String(year); }
	if ((year < 1900) || (year > lastYear)) { year = 2006; preferences.yearPref.value = String(year); }

	font         = preferences.generalFontPref.value;
	fontSize     = Number(preferences.fontSizePref.value);
	realFontSize = Number(preferences.realFontSizePref.value);

	if (extraFontSize > 0) { fontSize = nextBigger(fontSize); realFontSize = nextBigger(realFontSize);}
	if (extraFontSize > 1) { fontSize = nextBigger(fontSize); realFontSize = nextBigger(realFontSize);}
	if (extraFontSize > 2) { fontSize = nextBigger(fontSize); realFontSize = nextBigger(realFontSize);}
	if (extraFontSize > 3) { fontSize = nextBigger(fontSize); realFontSize = nextBigger(realFontSize);}
	if (extraFontSize > 4) { fontSize = nextBigger(fontSize); realFontSize = nextBigger(realFontSize);}

	fontStyle = 'regular';
	
	width  = Math.round(3*fontSize/2);
	height = Math.round(3*fontSize/2);
	scale  = 3/2;
	
	hOffset = width;
	vOffset = height>>1;
	
	prev.width = next.width = lock.height = prev.height = next.height = fontSize;
	lock.width = Math.round(1.22*fontSize);
	prev.hOffset = hOffset + (width>>1);
	prev.vOffset = vOffset + (fontSize>>1);
	
	lock.hOffset = hOffset - (width>>1) + (width>>2);
	lock.vOffset = vOffset + (fontSize>>1);

	mainFrameWidth  = 2* hOffset + Math.round(7*width*scale + 4*width/5);
	mainFrameHeight = Math.round(9*height) + vOffset;
	
	next.hOffset = mainFrameWidth - hOffset - next.width - (width>>1);
	next.vOffset = vOffset + (fontSize>>1);
	
	lock.colorize = prev.colorize = next.colorize = preferences.monthTextColor.value;

	bkgd.height = mainFrameHeight;
	bkgd.width  = mainFrameWidth;
	bkgd.colorize = preferences.bgColorization.value;

	main_window.width  = parent.width  = mainFrameWidth;
	main_window.height = parent.height = mainFrameHeight;
	
	var bgPref = preferences.backgroundPref.value;
	
	if ((bgPref == bf("Colorized")) || (bgPref == bf("darkGlass")) || (bgPref == bf("White")))
	{
		if (glassWindow === null)
		{
			glassWindow = new GlassWindow("Resources/Glass", parent, mainFrameWidth, mainFrameHeight, 5);
		}
		else
		{
			glassWindow.setDimension(mainFrameWidth, mainFrameHeight);
			glassWindow.setOpacity(255);
		}
	}

	if (bgPref == bf("darkGlass"))
	{
		if (greyWindow  !== null) {  greyWindow.setOpacity(0); }
		if (whiteWindow !== null) { whiteWindow.setOpacity(0); }
		bkgd.opacity = 0;
	}
	else if (bgPref == bf("Colorized"))
	{
		if (greyWindow === null)
		{
			greyWindow = new GlassWindow("Resources/Grey", parent, mainFrameWidth, mainFrameHeight, 3, preferences.bgColorization.value);
		}
		else
		{
			greyWindow.setDimension(mainFrameWidth, mainFrameHeight);
			greyWindow.setOpacity(255);
			greyWindow.setColorize(preferences.bgColorization.value);
		}
		if (whiteWindow !== null) { whiteWindow.setOpacity(0); }
		bkgd.opacity = 0;
	}
	else if (bgPref == bf("White"))
	{
		if (whiteWindow === null)
		{
			whiteWindow = new GlassWindow("Resources/White", parent, mainFrameWidth, mainFrameHeight, 3);
		}
		else
		{
			whiteWindow.setDimension(mainFrameWidth, mainFrameHeight);
			whiteWindow.setOpacity(255);
		}
		if (greyWindow !== null) { greyWindow.setOpacity(0); }
		bkgd.opacity = 0;
	}
	else if (bgPref == bf("colorizedChart"))
	{
		if (glassWindow !== null) { glassWindow.setOpacity(0); }
		if (greyWindow  !== null) {  greyWindow.setOpacity(0); }
		if (whiteWindow !== null) { whiteWindow.setOpacity(0); }
		bkgd.opacity = 255;
	}
	else if (bgPref == bf("None"))
	{
		if (glassWindow !== null) { glassWindow.setOpacity(0); }
		if (greyWindow  !== null) {  greyWindow.setOpacity(0); }
		if (whiteWindow !== null) { whiteWindow.setOpacity(0); }
		bkgd.opacity = 0;
	}

	biggerFontSize = fontSize; if (realFontSize < fontSize) { biggerFontSize = realFontSize; }

	makeHead (scale, width, height, hOffset, vOffset, font, fontSize, fontStyle, 10, '');

//	var biggerWidth  = Math.round(3*biggerFontSize/2);
//	var biggerHeight = Math.round(3*biggerFontSize/2);
//	makeHead (scale, biggerWidth, biggerHeight, (mainFrameWidth>>1) - Math.round(4*biggerWidth*scale), vOffset, font, biggerFontSize, fontStyle, 10, '');

	var startHOffset = hOffset;
	
	if (preferences.weekNumberPref.value == bf("Hidden"))
	{
		startHOffset = hOffset - Math.round(0.5*width*scale);
	}

	if (fontDelta > 0) { biggerFontSize = nextBigger(biggerFontSize); }
	if (fontDelta > 1) { biggerFontSize = nextBigger(biggerFontSize); }
	
	makeTable(scale, width, height, startHOffset, vOffset + height, font, biggerFontSize, fontStyle, 10, '');

	cal(year, month, hOffset, font, fontStyle, fontSize);
	adjustHeight();
	showButtons(255);

	updateNow();

	if (main_window.visible) { focusWidget(); }
};

function invColor(color)
{
	var inv = (parseInt(color.substring(1), 16) ^ 0xFFFFFF).toString(16);
	while (inv.length < 6) { inv = '0' + inv; }
	return '#' + inv;
}

function colorForm(isoDate)
{
	var colorDef = [bf('useColorPicker'), '-', bf('black'), bf('red'), bf('yellow'), bf('green'), bf('cyan'), bf('blue'), bf('magenta'), bf('gray'), bf('white')];

	 var objDef  = [['color', bf('colorColon'), 'popup', colorDef, bf('useColorPicker'), bf('chooseAColor')]];

	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, bf('colorDefinition') + fullDateOf(isoDate), bf('goOn'));
			
	var result = null;

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

function colorSelect(isoDate)
{
	var theCommand, data;
	
	var color = colorForm(isoDate);
	if (color === null) { return; }			// form was cancelled
	
	if (color == bf('useColorPicker'))
	{
		color = chooseColor('#FFFFFF');
	}
	if (color !== null)
	{
		theCommand = '<<COLOR=' + color + '>>\n';
				
		if (memo_info.visible)
		{
			memo.data += theCommand;
		}
		else
		{
			data = getMemo(isoDate);
			data += theCommand;
			saveMemo(isoDate, data);
		}
		updateCalendar();			// was updateDate(false);
		updateMemos();
		main_window.focus();
		focusWidget();
	}
}

function parseColor(color)
{
	var found = color.match(/^\#(\d|[abcdefABCDEF]){6}$/);
	if (found !== null) { return color; } else { return ""; }
}

function mapColor(color)
{
	color = color.toLowerCase();
	
		 if (color == bf('red'))     { color = '#FF0000'; }
	else if (color == bf('green'))   { color = '#00FF00'; }
	else if (color == bf('blue'))    { color = '#0000FF'; }
	else if (color == bf('yellow'))  { color = '#FFFF00'; }
	else if (color == bf('cyan'))    { color = '#00FFFF'; }
	else if (color == bf('magenta')) { color = '#FF00FF'; }
	else if (color == bf('white'))   { color = '#FFFFFF'; }
	else if (color == bf('grey'))    { color = '#808080'; }
	else if (color == bf('gray'))    { color = '#808080'; }
	else if (color == bf('black'))   { color = '#000000'; }
	else { color = parseColor(color); }
	
	return color;
}

function setSize(row)
{
	extraFontSize = row - 1;
	updateCalendar();
}

function cycleFontSize()
{
	fontDelta = (fontDelta + 1) % 3;	// 0..2
	preferences.fontDeltaPref.value = fontDelta;

	updateCalendar();
}

function setSize1()  { setSize(1); }
function mySetSize() { setSize(this.row); }

function myOnOpenToDo()     { openMemoWindow("19700101", ""); }

function myOnMultiClicked() { onMultiClicked(this.isoDate); }
function myOnDragDropped()  { onDragDropped(this.isoDate);  }
function myToggleBgOacity() { this.bgOpacity = 255 - this.bgOpacity; }

calendar = function (year, month)	// was /\<\<\w*\=[\w\#\:\.]*?(\;\w*\=[\w\#\:\.]*?)*\>\>/g
{
	var day;
	var today;
	
	function setColor(color, isToday)
	{
		color = mapColor(color);
		if (color !== "") { M[row][column] = true; T[row][column].bgColor = color; if (isToday) { marker.colorize = color; } }
	}

	function findActions(data) { return data.match(/<<\w*\=[^\;\n<\>]*?(\;\w*\=[^\;\n<\>]*?)*\>\>/g); }

	function executeActions(actions)
	{
		var i, action, item, main, command, value;
		
		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': setColor(value, (day == today)); break;
					case 'colour': setColor(value, (day == today)); break;
					case 'alarm': if (day == today) { setAlarm(item); } break;
					case 'event': break;
					default:	  print('"' + command + '" is not a valid memo command.'); break;
				}
			}
		}
	}
	
	var textColor    = preferences.textColor.value;
	var satTextColor = preferences.satTextColor.value;
	var sunTextColor = preferences.sunTextColor.value;
	var weekColor    = preferences.weekColor.value;
//	var todayColor   = preferences.todayColor.value;
	var todayMarkerColor = preferences.todayMarkerColor.value;
	var memoColor    = preferences.memoColor.value;
	var memoBgColor  = preferences.memoBgColor.value;
	
	var autoOpenPref = preferences.autoOpenPref.value;
	
	var swos = (preferences.startWeekOnSunday.value == "1");	// Start Week on Sunday

//	var invCol   = invColor(textColor);
//	var invBgCol = invColor(todayMarkerColor);
	
	var theDate  = new Date();
	var theYear  = theDate.getFullYear();
	var theMonth = theDate.getMonth() + 1;
	var theDay   = theDate.getDate();
		today = 0; if ((year == theYear) && (month == theMonth)) { today = theDay; }
	
	var row0 = [bf("WK"),bf("Mon"),bf("Tue"),bf("Wed"),bf("Thu"),bf("Fri"),bf("Sat"),bf("Sun")];
	if ((fontSize < 13) || (fontSize > 24)) { row0 = [bf("Wk"),bf("Mo"),bf("Tu"),bf("We"),bf("Th"),bf("Fr"),bf("Sa"),bf("Su")]; }
	
	if (swos)
	{
		row0 = [bf("WK"),bf("Sun"),bf("Mon"),bf("Tue"),bf("Wed"),bf("Thu"),bf("Fri"),bf("Sat")];
		if ((fontSize < 13) || (fontSize > 24)) { row0 = [bf("Wk"),bf("Su"),bf("Mo"),bf("Tu"),bf("We"),bf("Th"),bf("Fr"),bf("Sa")]; }
	}

	resetTable(T, D, M, textColor, todayMarkerColor, weekColor);
	for (var j = 0; j < 8; j += 1) { T[0][j].data = row0[j]; }
	T[0][0].onMouseUp = T[0][1].onMouseUp = cycleFontSize;
	T[0][0].myTooltip = T[0][1].myTooltip = bf("varyFontSize");
	
	T[0][7].onMouseUp = myOnOpenToDo;
	T[0][7].myTooltip = "Open the To Do List";
	
	var week = weekOfYear(year, month, 1);
	var sweek = String(week); if (week < 10) { sweek = "0" + sweek; }
	if (week == 99) { sweek = "•"; T[0][0].data = "";}
	T[1][0].data = sweek;
	//print('1 sweek1: ' + sweek);
	T[1][0].onMouseUp = setSize1;
	T[1][0].myTooltip = bf("restoreInitialSize");

	var row    = 1;
	var column = dayOfWeek(year, month, 1);
	if (swos) { column += 1; } else if (column === 0) { column = 7; }

	clearAlarms();

	var sday, dow, isoDate, iCalEvents, tooltip, head, tHead, data;
	var lastDay = daysInMonth(year, month);
	//print('lastDay: ' + lastDay);
	for (day = 1; day <= lastDay; day += 1)
	{
		//print('day: ' + day);
		sday = String(day); if (day < 10) { sday = " " + sday; }
		if (column > 7) { row += 1; column = 1; }
		T[row][column].data = sday;
		dow = dayOfWeek(year, month, day);
		if (dow == 6) { T[row][column].color = satTextColor; }
		if (dow === 0) { T[row][column].color = sunTextColor; }
		if ((dow == 1) || (swos && (day == lastDay)))
		{
			week = weekOfYear(year, month, day);
			nweek = String(week); if (week < 10) { nweek = "0" + nweek; }
			if (week == 99) { nweek = "•"; }
			if (dow == 1) { sweek = nweek; }
			T[row][0].data = sweek;
			//print('2 sweek' + row +' : ' + sweek);
			T[row][0].row = row;
			T[row][0].onMouseUp = mySetSize;
			T[row][0].myTooltip = bf("setInitialSizePlus") + (row-1) + ".";
		}

		isoDate = makeISODate3(year, month, day);
		T[row][column].isoDate = isoDate;
		T[row][column].onMultiClick = myOnMultiClicked;
		T[row][column].onDragDrop   = myOnDragDropped;
		
		//cell = "T["+row+"]["+column+"].bgOpacity";
		T[row][column].onDragEnter   = myToggleBgOacity;
		T[row][column].onDragExit    = myToggleBgOacity;
		
		iCalEvents = getCachedEvents(isoDate).split(listSep).join('\n').replace(/\n\n/g, "\n");
		tooltip = "";
		if (preferences.iCalPref.value != "0") { tooltip = iCalEvents; }

		if (displayMemoCount === 0) { head = getMemoLines(isoDate, 1); }
		else { head = getMemoLines(isoDate, displayMemoCount); }
		tHead = head; if (displayMemoCount === 0) { tHead = ""; }
		
//		T[row][column].data += '\n' + head;

		if (head !== "")
		{
			M[row][column] = true;
			T[row][column].color = memoColor; T[row][column].bgColor = memoBgColor;
		}
		
		if (tHead !== "")
		{
			if (tooltip !== "") { tooltip += '\n- -\n' + tHead; } else { tooltip = tHead; }
		}

		if ((preferences.iCalPref.value == "2") && (iCalEvents !== "") && (head === ""))
		{
			M[row][column] = true;
			T[row][column].color = memoColor; T[row][column].bgColor = memoBgColor;
		}
		
		if ((tooltip === "") && (preferences.mainTooltipPref.value == "0")) { tooltip = bf("mainTooltip"); }
		T[row][column].myTooltip = tooltip;

		if (day == today)
		{ 
			D[row][column] = true;
			
			var markerWidth   = 0.005*(preferences.todayMarkerWidth.value   - 100);
			var markerHeight  = 0.005*(preferences.todayMarkerHeight.value  - 100);
			var markerHOffset = 0.005*(preferences.todayMarkerHOffset.value - 100);
			var markerVOffset = 0.005*(preferences.todayMarkerVOffset.value - 100);
			
			marker.width  = Math.round((2.25 + markerWidth)  * fontSize);
			marker.height = Math.round((2.00 + markerHeight) * fontSize);
			
			marker.hOffset = T[row][column].hOffset - Math.round(0.50 * (1.0 - markerHOffset) * fontSize);
			marker.vOffset = T[row][column].vOffset - Math.round(1.15 * (1.0 - markerVOffset) * fontSize);
			
			marker.colorize = todayMarkerColor;

/*
			if (head !== "")
			{
				T[row][column].color = invColor(todayColor);
				T[row][column].bgColor = invColor(todayMarkerColor);
			}
			else
			{
				T[row][column].color = todayColor; 
				T[row][column].bgColor = todayMarkerColor;
			}
*/			

//			eprint('autoOpenPref: ' + autoOpenPref);
			switch (autoOpenPref)
			{
				case "Always": if (! memo_info.visible)  { openMemoWindow(isoDate, ""); } break;
				case "Only when it has content": if ((head !== "") && (! memo_info.visible)) { openMemoWindow(isoDate, ""); } break;
				case "Never": break;
			}
		}
		
		data = getMemo(isoDate);
		if (data !== "") { executeActions(findActions(data)); }	// calls setColor() and setAlarm()

		column += 1;
	}
	//theDate = new Date();
	setAlarms(true, theDate);	// recompute alarm list
};

function prevMonth()
{
	testLicense();
	year  = parseInt(preferences.yearPref.value, 10);
	month = Number(preferences.monthPref.value);
	if (month > 1) { month -= 1; }
	else { month = 12; year -= 1; preferences.yearPref.value = String(year); }
	preferences.monthPref.value = String(month);
	cal(year, month, hOffset, font, fontStyle, fontSize);
	adjustHeight();
	showButtons(255);
}

function thisMonth()
{
	testLicense();
	year  = parseInt(preferences.yearPref.value, 10);
	month = Number(preferences.monthPref.value);
	cal(year, month, hOffset, font, fontStyle, fontSize);
	adjustHeight();
	showButtons(255);
}

function nextMonth()
{
	testLicense();
	year  = parseInt(preferences.yearPref.value, 10);
	month = Number(preferences.monthPref.value);
	if (month < 12) { month += 1; }
	else { month = 1; year += 1; preferences.yearPref.value = String(year); }
	preferences.monthPref.value = String(month);
	cal(year, month, hOffset, font, fontStyle, fontSize);
	adjustHeight();
	showButtons(255);
}

function sharedUpdateTimerFired()
{
	lprint('sharedUpdateTimerFired');
	nextMonth();
	prevMonth();
}

function nextISODate(isoDate)
{
	var n     = isoDate.length;
	var year  = Number(isoDate.substring(0, n - 4));
	var month = Number(isoDate.substring(n - 4, n - 2));
	var day   = Number(isoDate.substring(n - 2));
	
	day += 1;
	var last = daysInMonth(year, month);
	if (day > last) { day -= last; month += 1; if (month > 12) { month = 1; year += 1; } }

	day   = String(day); 	if (day.length   == 1) { day   = "0" + day;   }
	month = String(month);	if (month.length == 1) { month = "0" + month; }
	year  = String(year);
	
	return year + month + day;
}

function prevISODate(isoDate)
{
	var n     = isoDate.length;
	var year  = Number(isoDate.substring(0, n - 4));
	var month = Number(isoDate.substring(n - 4, n - 2));
	var day   = Number(isoDate.substring(n - 2));
	
	day -= 1;
	if (day   <  1) { month -= 1; if (month < 1) { month = 12; year -= 1; } day = daysInMonth(year, month); }

	day   = String(day); 	if (day.length   == 1) { day   = "0" + day;   }
	month = String(month);	if (month.length == 1) { month = "0" + month; }
	year  = String(year);
	
	return year + month + day;
}

function prevDay()
{
	// gISOdate is set to current day
	if (gISOdate == "19700101") { beep(); return; }
	var oldMonth = theISOMonth(gISOdate);
	var newDate  = prevISODate(gISOdate);
	var newMonth = theISOMonth(newDate);
	openMemoWindow(newDate, "");
	if (newMonth != oldMonth) { prevMonth(); }
}

function nextDay()
{
	// gISOdate is set to current day
	if (gISOdate == "19700101") { beep(); return; }
	var oldMonth = theISOMonth(gISOdate);
	var newDate  = nextISODate(gISOdate);
	var newMonth = theISOMonth(newDate);
	openMemoWindow(newDate, "");
	if (newMonth != oldMonth) { nextMonth(); }
}

function selectMonth()
{
	focusWidget();
	
	var sDay = 0;
	var sMonth = month;
	var sYear = year;
	var sDate, i;
	do 
	{
		sDate = simpleForm(bf('dateSelection'), bf('Select'),'date', bf('dateColon'), 'text', [''], '', bf('enterDate'));
		eprint('selected date: ' + sDate);
		if (sDate === "") { return; }	// user cancelled or typed nothing

		for (i = 0; i < sDate.length; i += 1)
		{
			if ('0123456789'.indexOf(sDate[i]) < 0) { beep(); continue; }
		}
	
		if (sDate.length == 2)	// DD
		{
			sDay = parseInt(sDate, 10);
		}
		else if (sDate.length == 4)	// MMDD
		{
			sMonth = parseInt(sDate.substring(0,2), 10);
			sDay   = parseInt(sDate.substring(2,4), 10);
		}
		else if (sDate.length == 6)	// YYYYMM
		{
			sYear  = parseInt(sDate.substring(0,4), 10);
			sMonth = parseInt(sDate.substring(4,6), 10);
		}
		else if (sDate.length == 8)	// YYYYMMDD
		{
			sYear  = parseInt(sDate.substring(0,4), 10);
			sMonth = parseInt(sDate.substring(4,6), 10);
			sDay   = parseInt(sDate.substring(6,8), 10);
		}
		else { beep(); continue; }
		
		if ((sYear  < 1900) || (sYear  > lastYear)) { beep(); continue; }
		if ((sMonth < 1   ) || (sMonth >       12)) { beep(); continue; }
		if ((sDay   < 0   ) || (sDay > daysInMonth(sYear, sMonth))) { beep(); continue; }

		
		if ((year != sYear) || (month != sMonth))
		{
			year  = sYear;
			month = sMonth;

			preferences.yearPref.value  = String(year);
			preferences.monthPref.value = String(month);
		
			cal(year, month, hOffset, font, fontStyle, fontSize);
			adjustHeight();
			showButtons(255);
		}
		if (sDay !== 0) { openMemoWindow(makeISODate3(year, month, sDay), ""); } else { focusWidget(); }
		break;
	} while (true);
 }

function ordinalOf(num)
{
	var tens = Math.floor(num / 10);
	var units = num % 10;

	switch(num)	// num 0..59
	{
		case  0 : return bf("zeroth");
		case  1 : return bf("first");
		case  2 : return bf("second");
		case  3 : return bf("third");
		case  4 : return bf("fourth");
		case  5 : return bf("fifth");
		case  6 : return bf("sixth");
		case  7 : return bf("seventh");
		case  8 : return bf("eighth");
		case  9 : return bf("ninth");
		case 10 : return bf("tenth");
		case 11 : return bf("eleventh");
		case 12 : return bf("twelfth");
		case 13 : return bf("thirteenth");
		case 14 : return bf("fourteenth");
		case 15 : return bf("fifteenth");
		case 16 : return bf("sixteenth");
		case 17 : return bf("seventeenth");
		case 18 : return bf("eighteenth");
		case 19 : return bf("nineteenth");
		case 20 : return bf("twentieth");
		case 30 : return bf("thirtieth");
		case 40 : return bf("fortieth");
		case 50 : return bf("fiftieth");
		case 60 : return bf("sixtieth");
		case 70 : return bf("seventieth");
		case 80 : return bf("eightieth");
		case 90 : return bf("ninetieth");
		
		default : 	if (num > 20 )
						{ return cardinalOf(10*tens) + "-" + ordinalOf(units); }
	}
}

function yearOf(num)
{
	var sYear = num.toString();	// THtu
	
	var T = Number(sYear[0]);
	var H = Number(sYear[1]);
//	var t = Number(sYear[2]);
	var u = Number(sYear[3]);
	var C = 10*T + H;

	
	if ((num % 1000) === 0) { return cardinalOf(T) + bf('minThousand'); }
	if ((num % 1000)  < 10) { return cardinalOf(T) + bf('minThousandAnd') + cardinalOf(u); }
	if ((num %  100) === 0) { return cardinalOf(C) + bf('minHundred'); }
	if ((num %  100)  < 10) { return cardinalOf(C) + bf('minOhMin') + cardinalOf(u); }
	return cardinalOf(C) + '-' + cardinalOf(num % 100);
}

function speakDate(year, month, day)
{
	var theDays     = [bf("Sunday"),bf("Monday"),bf("Tuesday"),bf("Wednesday"),bf("Thursday"),bf("Friday"),bf("Saturday")];

	var theMonths   = [bf("January"),bf("February"),bf("March"),bf("April"),bf("May"),bf("June"),
				   	   bf("July"),bf("August"),bf("September"),bf("October"),bf("November"),bf("December")];
	
	var dow = new Date(year, month-1, day).getDay();
				   	   
	speak(theDays[dow] + ' ' + theMonths[month-1] + ' ' + ordinalOf(day) + ' ' + yearOf(year));
}

function saveMyPrefs() {
	var filePath = saveAs(".plist");
	if (filePath === null) {
		return;
	}

	if (savePlist(filePath, widgetName)) {
		alert('Saved preferences file for ' + widgetName + ' as: ' + filePath);
	} else {
		beep();
		alert('Could not save preferences file for ' + widgetName + ' as: ' + filePath);
	}
}

function loadMyPrefs() {
	var filePath = chooseFile(".plist");
	if (filePath === null) {
		return;
	}
	
	beep();
	var res = alert("CAUTION: You are about to overwrite the Widget's preferences.", 'Proceed', 'Cancel');
	if (res == 2) {
		return;
	}

	if (restorePlist(filePath, widgetName)) {
		eprint('restoreMyPrefs:reloadWidget');
		reloadWidget();
	} else {
		beep();
		alert('Could not load preferences file: ' + filePath + ' for ' + widgetName);
	}
}

var PATH = resolvePath(".");
lprint('PATH=' + PATH);
var idx = PATH.lastIndexOf(".widget/Contents");
var temp = PATH.substring(0, idx);
idx = temp.lastIndexOf("/");
widgetName = temp.substring(idx + 1);
lprint("widgetName: " + widgetName);
