/*
 * Project: JavaScript Alarm Clock
 * Version: 0.4
 * URL: http://neswork.com/javascript/alarm-clock/
 * Author: Gavriel Fleischer (flocsy@gmail.com)
 * Copyright: (C) 2010 Gavriel Fleischer
 * File name: alarm-clock.js
 * Minimized file name: alarm-clock.min.js
 * File last modified: 2010-02-03
 */

function printVal(val)
{
	var out;
	switch (typeof val)
	{
	case "string":
		out = '"'+val+'"';
		break;
	default:
		out = val;
	}
	return out;
}

var Alarm = function(args)
{
	// public attributes
	this.format = "HH:MM:ss";

	this.objectId = 0;
	this.offset = 0;
	this.tickCallbacks = [];
	this.alarms = [];
	this.interval_id = null;
	this.interval = null;
	this.tz = null;
	this.message = null;

	if ('undefined' == typeof Alarm.counter)
	{
		Alarm.counter = 0;
		Alarm.objects = [];
	}
	if (0 == this.objectId)
	{
		this.objectId = ++Alarm.counter;
		Alarm.objects[this.objectId] = this;
	}

	if ('undefined' != typeof args)
	{
		Alarm.prototype.init.call(this,args);
	}
};

Alarm.prototype.init = function(args)
{
	var alarmKeys = ["alarmCallback","date","recurrent","message"];
	var alarmSet = false;
	var alarm = {};
	for (var i in alarmKeys)
	{
		var key = alarmKeys[i];
		if ('undefined' != typeof args[key])
		{
			alarm[key] = args[key];
			alarmSet = true;
		}
	}
	if (alarmSet)
	{
		alarm.callback = alarm.alarmCallback;
		delete alarm.alarmCallback;
		this.addAlarm(alarm);
	}
	this.setTZ(args.tz);
	if ('undefined' != typeof args.format)
	{
		this.format = args.format;
	}
	if ('undefined' != typeof args.tickCallback)
	{
		this.addTickCallback(args.tickCallback);
	}
	if ('undefined' != typeof args.interval)
	{
		this.changeInterval(args.interval);
	}
	else
	{
		this.changeInterval(1000);
	}
};

Alarm.prototype.toStr = function()
{
	var str = "";
	for (var key in this)
	{
		if ('function' != typeof this[key])
		{
			str += (""!=str ? ", " : "") + key + ":" + printVal(this[key]);
		}
	}
//		str += ", objectId:"+printVal(this.objectId);
//		str += ", interval:"+printVal(this.interval);
//		str += ", tz:"+printVal(this.tz);
//		str += ", message:"+printVal(this.message);
/*
;;;		for (var i in alarms)
;;;		{
;;;			str += ", "+printVal(alarms[i]);
;;;		}
*/
	return str;
};

Alarm.prototype.getObjectId = function()
{
	return this.objectId;
};

Alarm.prototype.className = function()
{
	return "Alarm";
};

Alarm.prototype.toString = function()
{
	return "[object "+this.className()+"{"+this.toStr()+"}]";
};

Alarm.prototype.tick = function()
{
	var time = this.toTimeStr();
	var now = new Date();
	var i;
	for (i = 0; i < this.alarms.length; i++)
	{
		var alarm = this.alarms[i];
		if (null !== alarm.date && alarm.date <= now)
		{
			if ("function" == typeof alarm.callback)
			{
				var msg = ('undefined' != typeof alarm.message ? alarm.message : this.message);
				alarm.callback(time,msg);
			}
			else if ("string" == typeof alarm.callback)
			{
				eval("("+alarm.callback+")");
			}
			if (alarm.recurrent)
			{
				alarm.date.setTime(alarm.date.getTime()+alarm.recurrent);
			}
			else
			{
				alarm.date = null;
			}
			this.alarms[i] = alarm;
		}
	}
	for (i = 0; i < this.tickCallbacks.length; i++)
	{
		var tickCallback = this.tickCallbacks[i];
		if ("function" == typeof tickCallback)
		{
			tickCallback(time,this.message);
		}
		else if ("string" == typeof tickCallback)
		{
			eval("("+tickCallback+")");
		}
	}
};

Alarm.prototype.getTZ = function()
{
	return this.tz;
};

Alarm.prototype.setTZ = function(_tz)
{
	var now = new Date();
	if (null === _tz)
	{
		var o = now.getTimezoneOffset();
		_tz = String(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60);
		while (_tz.length < 4)
		{
			_tz = "0" + _tz;
		}
		this.tz = (0 < o ? "-" : "+") + _tz;
		this.offset = 0;
	}
	else
	{
		this.tz = _tz;
		this.offset = 60000*(Math.floor(_tz/100)*60 + _tz%100 + now.getTimezoneOffset());
	}
	return this;
};

Alarm.prototype.dateFormat = function(date, _format)
{
	var str;
	if ('function' == typeof dateFormat)
	{
		str = dateFormat(date, _format);
	}
	else
	{
		str = date.toTimeString();
	}
	return str;
};

Alarm.prototype.toTimeStr = function(_format)
{
	var str;
	var now = new Date();
	if ('undefined' == typeof _format)
	{
		_format = this.format;
	}
	if (this.offset)
	{
		str = this.dateFormat(new Date(now.getTime()+this.offset),_format.replace("o",this.tz).replace("Z","'GMT'"+this.tz));
	}
	else
	{
		str = Alarm.prototype.dateFormat(now,_format);
	}
	return str;
};

Alarm.prototype.getAlarm = function(i)
{
	return this.alarms[i];
};

Alarm.prototype.addAlarm = function(alarmCallback_or_alarmObject,date,recurrent,msg)
{
	if ('object' == typeof alarmCallback_or_alarmObject)
	{
		this.alarms.push(alarmCallback_or_alarmObject);
	}
	else
	{
		var alarm = {};
		alarm.callback = alarmCallback_or_alarmObject;
		alarm.date = date;
		alarm.recurrent = recurrent;
		alarm.message = msg;
		this.alarms.push(alarm);
	}
	return this;
};

Alarm.prototype.changeInterval = function(_interval)
{
	this.clearInterval();
	this.interval = _interval;
	if (null !== this.interval)
	{
		var self = this;
//			this.interval_id = window.setInterval(function(){tick();},this.interval);
		this.interval_id = window.setInterval(function(){self.tick();},this.interval);
	}
	return this;
};

Alarm.prototype.setInterval = function(tickCallback,_interval,msg)
{
	this.message = msg;
	this.addTickCallback(tickCallback);
	if ('undefined' != typeof _interval)
	{
		this.interval = _interval;
		this.changeInterval(this.interval);
	}
	return this;
};

Alarm.prototype.clearInterval = function()
{
	if (null !== this.interval_id)
	{
		window.clearInterval(this.interval_id);
		this.interval_id = null;
	}
	return this;
};

Alarm.prototype.getTickCallback = function(i)
{
	return this.tickCallbacks[i];
};

Alarm.prototype.addTickCallback = function(tickCallback)
{
	this.tickCallbacks.push(tickCallback);
	return this;
};

var Clock = function(args)
{
	// public attributes
	this.id = null;
	this.el = null;

	Alarm.call(this, args);

	if ('undefined' != typeof args)
	{
		Clock.prototype.init.call(this,args);
	}
};

Clock.prototype = new Alarm();
Clock.prototype.constructor = Clock;

Clock.prototype.init = function(args)
{
	if (!document.all && !document.getElementById)
	{
		return false;
	}
	this.setId(args["id"]);
	this.setEl(args["el"]);
	if (null !== this.el)
	{
		var self = this;
		this.showTime();
		this.addTickCallback(function(t){self.show(t);});
	}
};

Clock.prototype.className = function()
{
	return "Clock";
};

Clock.prototype.getId = function()
{
	return this.id;
};

Clock.prototype.setId = function(_id)
{
	if ('undefined' !== typeof _id)
	{
		this.id = _id;
		if (null !== _id)
		{
			this.el = document.getElementById(_id);
		}
		else
		{
			this.el = null;
		}
	}
};

Clock.prototype.getEl = function()
{
	return this.el;
};

Clock.prototype.setEl = function(_el)
{
	if ('undefined' !== typeof _el)
	{
		this.el = _el;
		if (null !== _el && 'undefined' != typeof _el.id)
		{
			this.id = _el.id;
		}
		else
		{
			this.id = null;
		}
	}
};

Clock.prototype.show = function(timeStr)
{
	if (null !== this.el)
	{
		this.el.innerHTML = timeStr;
	}
	return this;
};

Clock.prototype.showTime = function()
{
	return this.show(this.toTimeStr());
};
