/**
 * DateSelector class for creating date selectors based on SELECT html elements.
 *
 * @author Konstantin Bychkov <k.bychkov@acamar.ru>
 * @version 1.7
 */


var aMonths = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"];


function DateSelector(aId, aPeriod, init) {
	this.selectedY = 0;
	this.selectedM = 0;
	this.selectedD = 0;

	this.elY = this.$(aId[0]);
	this.elM = this.$(aId[1]);
	this.elD = this.$(aId[2]);

	this.setPeriod(aPeriod, init);
	this.addEventHandler(this.elY, "change", this.fill, this);
	this.addEventHandler(this.elM, "change", this.fill, this);
	this.addEventHandler(this.elD, "change", this.fill, this);

	return this;
}


DateSelector.prototype.fill = function (Y, M, D) {
	this.selectedY = Y ? Y : this.elY.options[this.elY.selectedIndex].value;
	this.selectedM = M ? M : this.elM.options[this.elM.selectedIndex].value;
	this.selectedD = D ? D : this.elD.options[this.elD.selectedIndex].value;
	this.fillYear();
	this.fillMonth();
	this.fillDay();
}


DateSelector.prototype.fillYear = function () {
	val = opt = this.range(this.start.getFullYear(), this.end.getFullYear());
	this.fillOptions(this.elY, opt, val, this.selectedY);
}


DateSelector.prototype.fillMonth = function () {

	if (this.start.getFullYear() == this.end.getFullYear()) {
		opt = aMonths.slice(this.start.getMonth(), this.end.getMonth() + 1);
		val = this.range(this.start.getMonth() + 1, this.end.getMonth() + 1);
	} else if (this.selectedY == this.start.getFullYear()) {
		opt = aMonths.slice(this.start.getMonth());
		val = this.range(this.start.getMonth() + 1, 12);
		if (this.selectedM < val[0]) this.selectedM = val[0];
	} else if (this.selectedY == this.end.getFullYear()) {
		opt = aMonths.slice(0, this.end.getMonth() + 1);
		val = this.range(1, this.end.getMonth() + 1);
		if (this.selectedM > val[val.length - 1]) this.selectedM = val[val.length - 1];
	} else {
		opt = aMonths;
		val = this.range(1, 12);
	}

	this.fillOptions(this.elM, opt, val, this.selectedM);
}


DateSelector.prototype.fillDay = function () {
	var nDays = this.inMonth();
	if (this.start.getMonth() == this.end.getMonth() && this.start.getFullYear() == this.end.getFullYear()) {
		val = opt = this.range(this.start.getDate(), this.end.getDate());
	} else if (this.selectedM == this.start.getMonth() + 1 && this.selectedY == this.start.getFullYear()) {
		val = opt = this.range(this.start.getDate(), nDays);
		if (this.selectedD < val[0]) this.selectedD = val[0];
	} else if (this.selectedM == this.end.getMonth() + 1 && this.selectedY == this.end.getFullYear()) {
		val = opt = this.range(1, this.end.getDate());
		if (this.selectedD > val[val.length - 1]) this.selectedD = val[val.length - 1];
	} else {
		val = opt = this.range(1, nDays);
		if (this.selectedD > nDays) this.selectedD = nDays;
	}

	this.fillOptions(this.elD, opt, val, this.selectedD);
}


DateSelector.prototype.inMonth = function () {
	var aNumDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

	if (this.selectedM != 2) {
		n = aNumDays[this.selectedM - 1];
	} else {
		n = this.isLeapYear() ? 29 : 28;
	}
	return n;
}


DateSelector.prototype.fillOptions = function (el, opt, val, selected) {
	if (opt.length != val.length) {
		throw new Error("Options and values arrays must have equal size in fillOptions function.");
	}

	this.dropOptions(el);
	for (i in opt) {
		bSelected = val[i] == selected ? true : false;
		el.options[el.length] = new Option(opt[i], val[i], false, bSelected);
	}
}


DateSelector.prototype.dropOptions = function (el) {
	while (el.length) {
		el.remove(el.length - 1);
	}
}


DateSelector.prototype.selectDate = function (date) {
	var aDate = this.parseDate(date);
	var oDate = new Date(aDate[0], aDate[1] - 1, aDate[2]);

	var iTime = oDate.getTime();
	if (iTime < this.start.getTime() || iTime > this.end.getTime()) {
		throw new Error("The date is out of defined range in selectDate function.");
	}

	Y = oDate.getFullYear();
	M = oDate.getMonth() + 1;
	D = oDate.getDate();
	this.fill(Y, M, D);
}


DateSelector.prototype.parseDate = function (date) {
	return date.split(/\-/);
}


DateSelector.prototype.isLeapYear = function () {
	var Y = this.selectedY;
	return ((Y % 4 == 0) && (Y % 100 != 0)) || (Y % 400 == 0) ? true : false;
}


DateSelector.prototype.setPeriod = function (aPeriod, init) {
	aDate = this.parseDate(aPeriod[0]);
	this.start = new Date(aDate[0], aDate[1] - 1, aDate[2]);

	aDate = this.parseDate(aPeriod[1]);
	this.end = new Date(aDate[0], aDate[1] - 1, aDate[2]);

	if (init) {
		aDate = this.parseDate(init);
		oDate = new Date(aDate[0], aDate[1] - 1, aDate[2]);
		iTime = oDate.getTime();

		if (iTime < this.start.getTime()) init = aPeriod[0];
		if (iTime > this.end.getTime()) init = aPeriod[1];

		this.selectDate(init);
	} else {
		this.selectDate(aPeriod[0]);
	}
}


DateSelector.prototype.getDate = function () {
	var Y = this.selectedY, M = this.selectedM, D = this.selectedD;

	return Y + "-" + M + "-" + D;
}


DateSelector.prototype.range = function (n, m) {
	var a = [];
	for (i = n; i <= m; i++) {
		a = a.concat(i);
	}
	return a;
}


DateSelector.prototype.$ = function (id) {
	return document.getElementById(id);
}


DateSelector.prototype.addEventHandler = function (target, type, fn, obj) {
	var wrappedFn = function () {
			return fn.call(obj)
		}

	if (target.addEventListener) {
		target.addEventListener(type, wrappedFn, false);
	} else if (target.attachEvent) {
		target.attachEvent("on" + type, wrappedFn);
	} else {
		target["on" + type] = wrappedFn;
	}
}

