BS.com.Calendar = function (obj, key, value)
{
	this.mm = new BS.com.Delete('BsCalendar');
	this.obj = obj;
	this.key = key;
	this.val = ['YYYY', '', 'DD'];

	this.param = {
		showcal:	true,
		future:		false,
		eval:		null,
		zindex:		'100',
		offset:		[0,0]
	};
	
	this.clearE = this.mm.ceNew('clearEvt', this);
	this.clearE.addCB(this._clear);

	this.clearFocE = this.mm.ceNew('clearFocEvt', this);
	this.clearFocE.addCB(this._clearFoc);

	this.setE = this.mm.ceNew('set', this);
	this.setE.addCB(this._setCB);

	this.date = new Date();

	if (value) this.setVal(value);
};

BS.com.Calendar.prototype = {
	f_init:			false,
	cal:			null,

	_delete: function ()
	{
		this.obj = null;
		delete this.param;
		delete this.date;

		this.mm._delete();
	},
	
	_calSet: function (y, m, d)
	{
		var month = (m.toString().length < 2) ? '0'+m : m;
		var day = (d.toString().length < 2) ? '0'+d : d;
		var year = (y.toString().length == 2) ? '19'+y : y;
	
		BS.utl.form.setValue(this.yyINP, year);
		this.mmSEL.setVal(month);
		BS.utl.form.setValue(this.ddINP, day);
	},

	_setCB: function (type, data, args)
	{
		var		str = args[0];

		var y = str.substr(0, 4);
		var m = str.substr(5, 2);
		var d = str.substr(8, 2);

		this._calSet(y, m, d);
	},
	
	_calShow: function (type, data, args) 
	{
		var popDate;

		var dd = this.ddINP.value;
		if (dd.length < 2) dd = '0' + dd;

		var inp = this.yyINP.value + '-' + this.mmSEL.getVal() + '-' + dd;

		if (!inp.match(/[0-9]{4}-[0-9]{2}-[0-9]{2}/))
			inp = this.date.strftime('%Y-%m-%d');

		if (!this.cal)
			this.cal = this.mm.oNew(BS.com.Calendar.Popup, this.setE);

		if (this.getParam('future'))
			this.cal.disableDates(null, this.date);

		if (this.getParam('zindex'))
			this.cal.setZindex(this.getParam('zindex'));

		if (this.getParam('pos'))
			this.cal.setPos(this.getParam('pos'));

		this.cal.showLink(inp, this.mmSEL.sel);

		// eval anything in param.eval - sort of a hack,
		// works with "calopt" argument in smarty
		if (this.param.eval) eval(this.param.eval);
	},		

	_draw: function ()
	{
		if (this.f_init) return;
		this.f_init = true;

		var moA = [];

		this.mmSEL = this.mm.oNew(BS.com.Form.Select, this.obj, this.key + '[MM]', ['','']);

		for (var i = 0; i < BS.utl.date.MO_NUM_A.length; i++)
			moA.push([BS.utl.date.MO_NUM_A[i], BS.utl.date.MO_STR2_A[i]]);

		this.mmSEL.load(moA, true);

		this.ddINP = this.mm.domNew(this.obj, 'input');
		with (this.ddINP) {
			setAttribute('name', this.key + '[DD]');
			setAttribute('size', 3); setAttribute('maxlength', 2);
		}

		this.yyINP = this.mm.domNew(this.obj, 'input');
		with (this.yyINP) {
			setAttribute('name', this.key + '[YYYY]');
			setAttribute('size', 5); setAttribute('maxlength', 4);
		}

		this.clearFocE.attach(this.ddINP, 'focus');
		this.clearFocE.attach(this.yyINP, 'focus');

		// if we do not want to show the pop-up
		if (this.getParam('showCal') == 'false')
			return;

		this.calB = this.mm.domNew(this.obj, 'a', 'calB');
		this.calB.innerHTML = '<img border="0" src="/img/calendar/cal.gif">';
		this.clearB = this.mm.domNew(this.obj, 'a', 'clearB');
		this.clearB.innerHTML = '<img border="0" src="/img/calendar/cal-clear.gif">';

		this.calE = this.mm.ceNew('calEvt', this);
		this.calE.addCB(this._calShow);
		this.calE.attach(this.calB, 'click');

		this.clearE.attach(this.clearB, 'click');
	},

	_clear: function ()
	{
		this.setVal('');
		this.show();
	},

	_clearFoc: function (type, data, args)
	{
		var t = BS.utl.event.getTarget(args[0]);
		t.value = '';
	},

	/*!\param	Returns parameter value for specified name.
	* \param	name		name
	* \return	value
	*/
	getParam: function (name)
	{
		if (this.param[name]) return this.param[name];
	},
	
	/*!\brief	Sets parameter value for specified name.
	* \param	name		name
	* \param	value		value 
	*/
	setParam: function (name, value)
	{
		if (name == 'className') this.mm.setParam(name, value);
		else this.param[name] = value;
	},

	getVal: function ()
	{
		var mon = this.mmSEL.getVal();
		var day = this.ddINP.value;
		var yr = this.yyINP.value;

		if (yr == '' || yr == 'YYYY') return '';

		if (mon == '') mon = '01';
		if (day == '' || day == 'DD') day = '01';
		if (day.length < 2) day = '0' + day;

		this.value = BS.utl.date.toDate(yr + '-' + mon + '-' + day);

		return this.value;
	},

	setVal: function (value)
	{
		var re = new RegExp('^[0-9]{4}-[0-9]{0,2}-[0-9]{0,2}');
		if (!re.test(value)) {
			this.value = null;
			this.val[0] = this.val[1] = this.val[2] = '';
			return;
		}

		this.value = BS.utl.date.toDate(value);
		this.val[0] = this.value.strftime('%Y');
		this.val[1] = this.value.strftime('%m');
		this.val[2] = this.value.strftime('%d');
	},

	/*!\brief	Show widget on the page. */
	show: function ()
	{
		this._draw();

		BS.utl.form.setValue(this.yyINP, this.val[0]);
		this.mmSEL.setVal(this.val[1]);
		BS.utl.form.setValue(this.ddINP, this.val[2]);
	}
};

BS.com.Calendar.Popup = function (submitE)
{
	var			tmp;

	var gvId = BS.utl.mkGvId();
	BS.utl.gvA[gvId] = this;
	this.gvStr = 'BS.utl.gvA[' + gvId + ']';

	this.submitE = submitE;

	this.mm = new BS.com.Delete('BsCalendarPopup');

	this.date = new Date();
	this.pos = [0,0];

	this.obj = this.mm.domNew(document.body, 'div');
	this.obj.id = BS.utl.dom.mkid();

	if (BS.utl.browser.isIE) {
		this.ieMask = this.mm.domNew(null, 'iframe', 'BsCalendarPopup');
		with (this.ieMask) {
			setAttribute('src', '/com/mask.html');
			setAttribute('width', '1');
			setAttribute('height', '1');
			setAttribute('border', '0');
			setAttribute('scrolling', 'no');
		}
		BS.utl.dom.setStyle(this.ieMask, 'position', 'absolute');
		BS.utl.dom.setStyle(this.ieMask, 'visibility', 'hidden');
		BS.utl.dom.setStyle(this.ieMask, 'zIndex', '1');
		document.body.appendChild(this.ieMask);
	}

	tmp = this.mm.domNew(this.obj, 'h1');
	this.prevA = this.mm.domNew(tmp, 'a', 'bscLink bscPrev');
	this.nextA = this.mm.domNew(tmp, 'a', 'bscLink bscNext');
	this.prevA.innerHTML = '&lt;'; this.nextA.innerHTML = '&gt;';
	this.titleSPAN = this.mm.domNew(tmp, 'span');

	tmp = this.mm.domNew(this.obj, 'ul', 'bscCal bscCalHead');
	tmp.innerHTML = '<li>S</li><li>M</li><li>T</li><li>W</li><li>T</li><li>F</li><li>S</li>';

	this.UL = this.mm.domNew(this.obj, 'ul', 'bscCal');

	this.clickE = BS.utl.mm.ceNew(null, this);
	this.clickE.addCB(this._click);
	this.clickE.attach(this.prevA, 'click');
	this.clickE.attach(this.nextA, 'click');

	this.bodyE = BS.utl.mm.ceNew(null, this);
	this.bodyE.addCB(this._body);
};

BS.com.Calendar.Popup.prototype = {
	curDate:		null,
	setDate:		null,
	sD:			null,
	eD:			null,
	pos:			null,

	_delete: function ()
	{
		this.bodyE.attach(document.body, 'click');
		this.submitE = this.curDate = this.setDate = null;
		delete this.date;
		delete this.pos;
		this.mm._delete;
	},

	/*!\brief    Returns an array the day of the week the specified month starts
	 *	     and the number of days in the specified month.
	 * \param    year        4 digit year
	 * \param    month        month (1-12)
	 */
	_dateDayCnt: function (date)
	{
		var		d = new Date;
		var		r = [];

		var		month = date.getUTCMonth();
		var		year = date.getUTCFullYear();

		d.setUTCFullYear(year);
		d.setUTCMonth(month, 1);
		d.setUTCHours(0, 0, 0, 0);
		
		r.push(d.getUTCDay());
		
		for (i=28; d.setUTCDate(i) && d.getUTCMonth() == month; i++);
		
		r.push(i - 1);
		
		return r;
	},

	_addMonth: function (d, n)
	{
		var		month = d.getUTCMonth();
		var		year = d.getUTCFullYear();

		month += n;
		if (month < 0) {
			month = 11;
			year--;
		}
		else if (month > 11) {
			month = 0;
			year++;
		}
	
		d.setUTCMonth(month); d.setUTCFullYear(year);
		return d;
	},

	_click: function (type, data, args)
	{
		var e = args[0];
		var node = BS.utl.event.getTarget(e);

		switch (node) {
		case this.prevA:
			this.curDate = this._addMonth(this.curDate, -1);
			break;
		case this.nextA:
			this.curDate = this._addMonth(this.curDate, 1);
			break;
		}

		this._draw();
	},

	_body: function (type, data, args)
	{
		var e = args[0];
		var node = BS.utl.event.getTarget(e);

		for (; node && (node.id != this.obj.id); node = node.parentNode);

		if (node) return;

		this.show(false);
		BS.utl.event.preventDefault(e);
	},

	_attachBody: function () { this.bodyE.attach(document.body, 'click'); },

	_chkDate: function (d)
	{
		if (!this.sD && !this.eD) return true;

		var f = 0;
		if (this.sD) {
			if (BS.utl.date.compare(d, this.sD) > 0)
				f--;
			else f++;
		}

		if (this.eD) {
			if (BS.utl.date.compare(d, this.eD) < 0)
				f--;
			else f++;
		}

		if (f < 0) return false;
		return true;
	},

	_draw: function ()
	{
		if (!this.curDate) return;

		var d = new Date(this.curDate.valueOf());

		this.titleSPAN.innerHTML = d.strftime('%B %Y');

		var days = this._dateDayCnt(d);
		var set = null;
		var str = '';

		if (this.setDate.strftime('%Y%m') == d.strftime('%Y%m'))
			set = this.setDate.getUTCDate();

		for (var i = 0; i < days[0]; i++)
			str += '<li>&nbsp;</li>';

		for (var i = 1; i <= days[1]; i++) {
			d.setUTCDate(i);
			if (this._chkDate(d)) {
				str += '<li><a href="javascript:' + this.gvStr + '.set(\'' + d.strftime('%Y-%m-%d') + '\');"';
				if (i == set) str += ' class="bscSet"';
				str += '>' + i + '</a></li>';
			}
			else
				str += '<li>' + i + '</li>';
		}

		this.UL.innerHTML = str;
	},

	_reset: function (date)
	{
		var val = date.valueOf();

		delete this.curDate;
		delete this.setDate;

		this.curDate = new Date(val);
		this.setDate = new Date(val);
	},

	disableDates: function (sD, eD)
	{
		this.sD = sD;
		this.eD = eD;
	},

	set: function (str)
	{
		if (this.submitE) this.submitE.exec(str);
		this.show(false);
	},

	setZindex: function (zindex)
	{
		BS.utl.dom.setStyle(this.obj, 'zIndex', zindex);
	},

	setPos: function (pos)
	{
		delete this.pos;
		this.pos = pos.slice();
	},

	show: function (mode, date)
	{
		if (mode) {
			if (!date) date = this.date;

			this._reset(date);

			this._draw();

			if (this.ieMask) {
				var size = BS.utl.dom.size(this.obj);
				var pos = BS.utl.dom.pageOfs(this.obj);
				var scroll = BS.utl.dom.scrollOfs();
				pos = BS.utl.xy.sub(pos, scroll);
				pos = BS.utl.xy.add(pos, this.pos);
				BS.utl.dom.setStyle(this.ieMask, 'width', size[0] + 'px');
				BS.utl.dom.setStyle(this.ieMask, 'height', size[1] + 'px');
				BS.utl.dom.setPageOfs(this.ieMask, pos);
			}
			BS.utl.event.setTimeout(0, this._attachBody, this);
		} else {
			this.bodyE.detach(document.body, 'click');
		}

		BS.utl.dom.setStyle(this.obj, 'visibility', (mode) ? 'visible' : 'hidden');
		if (this.ieMask)
			BS.utl.dom.setStyle(this.ieMask, 'visibility', (mode) ? 'visible' : 'hidden');
	},

	showLink: function (dateStr, div)
	{
		if (div) {		
			var pos = BS.utl.dom.pageOfs(div);
			pos = BS.utl.xy.add(pos, this.pos);
			if (BS.utl.browser.isIE) {
				var scroll = BS.utl.dom.scrollOfs();
				pos = BS.utl.xy.sub(pos, scroll);
			}
			BS.utl.dom.setPageOfs(this.obj, pos);
		}

		this.show(true, BS.utl.date.toDate(dateStr));
	}
};

