/* 
 * 
 * new date converter
 * 
 */
var dateConverter = {
	defaults: {},
	
	init: function(options) {
		this.options = $.extend(this.defaults, options);
		
		for(var calendar in this.calendars) {
			this.calendars[calendar] = $.extend(this.calendars[calendar], this.calendarPrototype);
		}
	},
	
	convert: function(date, from, to) {
		if (this.isDate(date)) {
			if(!to) {
				to = from;
			}
			
			date = this.prepare(date);
			var jed = this.calendars[from].toJED(date);
			return this.calendars[to].fromJED(jed);
		} else {
			return false;
		}
	},
	
	prepare: function(date) {
		date.d = parseInt(date.d, 10);
		date.m = parseInt(date.m, 10);
		date.y = parseInt(date.y, 10);
		
		return date;
	},
	
	isDate: function(date) {
		if (!isNaN(date.d) && !isNaN(date.m) && !isNaN(date.y)) {
			return true;
		} else {
			return false;
		}
	},
	
	calendarPrototype: {
		yearToAstronomical: function(y){
			if (y < 0) {
				return y + 1;
			}
			
			if (!y) {
				return 10000000;
			}
			
			return y;
		},
		
		yearFromAstronomical: function (y) {
			return (y <= 0) ? y - 1 : y;
		},
	
		iWrap: function (iVal, iLo, iHi) {
			var wide = iHi + 1 - iLo;
	
			if (wide == 0) {
				return iLo;
			} else {
				return iLo + this.iModp(iVal - iLo, wide);
			}
		},
	
		iModp: function (i, j) {
			var ret = i % j;
	
			if (ret < 0) {
				ret += Math.abs(j);
			}
	
			return ret;
		}
	},
	
	calendars: {
		alexandrian: {
			toJED: function (date) {
				var y = date.y, m = date.m, d = date.d;
				
				y  = y + 4690 - Math.floor((13 - m) / 13);
		
				m = (m + 12) % 13;
				d = d - 1;
				
				return (Math.floor((1461 * y) / 4) + 30 * m + d - 124) - 0.5;
			},
		
			fromJED: function (jed) {
				var y, m, d, jPrime, tPrime;
				jed = Math.floor(jed + 0.5);
		
				jPrime = jed + 124;
		
				y = Math.floor((4 * jPrime + 3) / 1461);
				tPrime = Math.floor(((4 * jPrime + 3) % 1461) /4);
				m = Math.floor(tPrime / 30);
				d = tPrime % 30;
		
				d = d + 1;
				m = (m % 13) + 1;
				
				y = y - 4690 + Math.floor((13 - m) / 13);
				
				var date = {d: d, m: m,	y: y};
		
				return date;
			}
		}, // end: alexandrian
		
		armenian: {
			toJED: function (date) {
				var y = date.y, m = date.m, d = date.d;
				
				y  = Math.floor(y + 5268 - (13 - m) / 13);
		
				if (m < 13) {
					y += 1;		// temporary hack?
				}
		
				m = Math.floor((m + 12) % 13);
				d = d - 1;
		
				return (365 * y + 30 * m + d - 317) - 0.5;
			},
		
			fromJED: function (jed) {
				var y, m, d, jPrime, tPrime;
				jed = Math.floor(jed + 0.5);
		
				jPrime = jed + 317;
		
				y = Math.floor(jPrime / 365);
				tPrime = jPrime % 365;
				m = Math.floor(tPrime / 30);
				d = tPrime % 30;
		
				d = d + 1;
				m = (m % 13) + 1;
				y = Math.floor(y - 5268 + (13 - m) / 13);
				
				var date = {d: d, m: m,	y: y};
		
				return date;
			}
		}, // end: armenian
		
		bahai: {
			toJED: function (date) {
				var y = date.y, m = date.m, d = date.d;
				
				y  = y + 6560 - Math.floor((39 - m) / 20);
				m = m % 20;
				d = d - 1;
				
				var g = 3 * Math.floor(Math.floor((y + 184) / 100) / 4) - 50;
				
				return Math.floor((1461 * y) / 4) + (19 * m) + d - 1412 - g - 0.5;
			},
		
			fromJED: function (jed) {
				var y, m, d, jPrime, tPrime;
				jed = Math.floor(jed + 0.5);
				
				var g = 3 * Math.floor(Math.floor((4 * jed +274273) / 146097) / 4) - 50;
				jPrime = jed + 1412 + g;
		
				y = Math.floor((4 * jPrime + 3) / 1461);
				tPrime = Math.floor(((4 * jPrime + 3) % 1461) /4);
				m = Math.floor(tPrime / 19);
				d = tPrime % 19;
		
				d = d + 1;
				m = ((m + 19) % 20) + 1;
				y = y - 6560 + Math.floor((39 - m) / 20);
				
				var date = {d: d, m: m,	y: y};
				
				return date;
			}
		}, // end: bahai
		
		gregorian: {
			yearLengthMonths: 12,
			
			toJED: function(date) {
				var y = date.y, m = date.m, d = date.d;
				
				this.refs = {
					y: y,
					m: m,
					d: d
				};
		
				if (this.ymdCheck('y', 'm', 'd')) {
					return -1; 
				}
		
				y = this.refs.y;
				m = this.refs.m;
				d = this.refs.d;
				
				
				var y2 = this.yearToAstronomical(y);
				
				var yPrime, mPrime, dPrime, j1, j2, g, jed;
		
		        yPrime = y2 + 4716 - Math.floor((14 - m) / 12);
		        mPrime = (m + 9) % 12;
		        dPrime = d - 1;
		
		        j1 = Math.floor((1461 * yPrime) / 4);
		        j2 = Math.floor((153 * mPrime + 2) / 5);
		        g = Math.floor(3 * Math.floor((yPrime + 184) / 100) / 4) - 38;
		
				jed = j1 + j2 + dPrime - 1401 - Math.floor(g) - 0.5;
				//console.log(jed);
				return jed;
			},
			
			fromJED: function (jed) {
				var j = Math.floor(jed + 0.5);
				
				var g, jPrime, yPrime, tPrime, mPrime, dPrime, d, m, y;
				
				g = Math.floor(3 * Math.floor((4 * j + 274277) / 146097) / 4) - 38;
		
				jPrime = j + 1401 + g;
				
				yPrime = Math.floor((4 * jPrime + 3) / 1461);
				tPrime = Math.floor(((4 * jPrime + 3) % 1461) / 4);
				mPrime = Math.floor((5 * tPrime + 2) / 153);
				dPrime = Math.floor(((5 * tPrime + 2) % 153) / 5);
			
				d = dPrime + 1;
				m = ((mPrime + 2) % 12) + 1;
				
				y = Math.floor(yPrime - 4716 + (14 - m) / 12);
			   
				y = this.yearFromAstronomical(y);
				
				var date = new Date((y < 0 ? y + 1 : y), m - 1, d);
				var dow = date.getDay();
				if(dow == 0) dow = 7;
				
				var date = {
					y: y,
					m: m,
					d: d,
					dow: dow
				};
				
				return date;
				
			},
		
			ymdCheck: function (y, m, d) {
				if (this.ymCheck(y, m)) {
					return 1;
				}
		
				this.dayBorrow(y, m, d);
				this.dayCarry(y, m, d);
		
				return 0;
			},
		
			ymCheck: function (y, m)  {
				if (this.yCheck(y)) {
					return 1;
				};
				
				this.monthBorrow(y, m);
				this.monthCarry(y, m);
				
				return 0;
			},
		
			yCheck: function (y) {
				return this.refs[y] == 0;
			},
		
			monthBorrow: function (y, m) {
				while (this.refs[m] <= 0) {
					this.refs[m] += this.yearLengthMonths;
					this.refs[y]--;
				
					if (!this.refs[y]) {
						this.refs[y] = -1;
					}
				}
			},
		
			monthCarry: function (y, m) {
				var months = this.yearLengthMonths;
		
				if (this.refs[m] <= months) {
					return;
				}
		
				this.refs[m] -= months;
				this.refs[y]++;
			},
		
			dayBorrow: function (y, m, d){
				while (this.refs[d] <= 0) {
					this.refs[m]--;
					this.monthBorrow(y, m);
					this.refs[d] += this.monthLength(this.refs[y], this.refs[m]);
				}
			},
		
			dayCarry: function (a, b, c) {
				var days = this.monthLength(this.refs[a], this.refs[b]);
				
				while (this.refs[c] > days) {
					this.refs[c] -= days;
					this.refs[b]++;
					
					days = this.monthLength(this.refs[a], this.refs[b]);
					this.monthCarry(a, b);
				}
			},
		
			monthLength: function (y, i) {
				this.refs.y2 = y;
				this.refs.m2 = i;
		
				if (this.ymCheck('y2', 'm2')) {
					return 0;
				}
		
				var mdays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
		
				var ret = mdays[this.refs.m2 - 1];
				
				if (this.refs.m2 == 2 && this.yearIsLeap(this.refs.y2)) {
					ret++;
				}
		
				return ret;
			},
		
			yearIsLeap: function (y) {
				if (!y) {
					return 0;
				}
		
				var y2 = this.yearToAstronomical(y);
				
				if (y2 % 400 == 0) {
					return 1;
				}
				if (y2 % 100 == 0) {
					return 0;
				}
				if (y2 % 4 == 0) {
					return 1;
				}
			
				return 0;
			}
		}, // end: gregorian
		
		hebrew: {
			epoch: 347995.5,
			
			toJED: function (date) {
				var d = date.d, m = date.m, y = date.y;
				
				var months = this.yearMonths(y);
		
				var jed = this.epoch + this.delay1(y) + this.delay2(y) + d + 1;
				
				if (m < 7) {
					for (var mon = 7; mon <= months; mon++) {
						jed += this.monthDays(y, mon);
					}
		
					for (var mon = 1; mon < m; mon++) {
						jed += this.monthDays(y, mon);
					}
				} else {
					for (var mon = 7; mon < m; mon++) {
						jed += this.monthDays(y, mon);
					}
				}
				
				return jed;
		
			},
		
			fromJED: function (jed) {
				var y, m, d;
		
				jed = Math.floor(jed) + 0.5;
		
				var count = Math.floor(((jed - this.epoch) * 98496.0) / 35975351.0);
				var y = count - 1;
				
				for (var i = count; jed >= this.toJED({y: i, m: 7, d: 1}); i++) {
					y++;
				}
				
				var first = (jed < this.toJED({y: y, m: 1, d: 1})) ? 7 : 1;
				
				m = first;
		
				for (var i = first; jed > this.toJED({y: y, m: i, d: this.monthDays(y, i)}); i++) {
					m++;
				}
				
				d = (jed - this.toJED({y: y, m: m, d: 1})) + 1;
				
				var date = {d: d, m: m,	y: y};
				
				return date;
			},
		
			yearMonths: function (y) {
				return this.leap(y) ? 13 : 12;
			},
		
			leap: function (y) {
				return (((y * 7) + 1) % 19) < 7;
			},
		
			delay1: function (y) {
				var months = Math.floor(((235 * y) - 234) / 19);
				var parts = 12084 + (13753 * months);
				var days = (months * 29) + Math.floor(parts / 25920);
		
				if (((3 * (days + 1)) % 7) < 3) {
					days++;
				}
		
				return days;
			},
		
			delay2: function (y) {
				var last = this.delay1(y - 1);
				var present = this.delay1(y);
				var next = this.delay1(y + 1);
		
				return ((next - present) == 356) ? 2 : (((present - last) == 382) ? 1 : 0);
			},
		
			monthDays: function (y, m) {
				if (m == 2 || m == 4 || m == 6 || m == 10 || m == 13) {
					return 29;
				}
		
				if (m == 12 && !this.leap(y)) {
					return 29;
				}
		
				if (m == 8 && !((this.yearDays(y) % 10) == 5)) {
					return 29;
				}
				
				if (m == 9 && ((this.yearDays(y) % 10) == 3)) {
					return 29;
				}
			
				return 30;
			},
			
			yearDays: function (y) {
				return this.toJED({y: y + 1, m: 7, d: 1}) - this.toJED({y: y, m: 7, d: 1});
			}
		}, // end: hebrew
		
		zoroastrian: {
			epoch: 1579768.5,
			
			toJED: function (date) {
				var d = date.d, m = date.m, y = date.y;
				
				var jed = this.epoch + (d - 1) + 30 * (m - 1) + 365 * (y - 1);
				
				return jed;
		
			},
		
			fromJED: function (jed) {
				var y, m, d;
				
				jed = Math.floor(jed - this.epoch);
				
				d = 1 + jed;
				m = 1;
				y = 1;
				
				var years = Math.floor((d - 1) / 365);
				y += years;
				d -= years * 365;
				
				var months = Math.floor((d -1) / 30);
				m += months;
				d = d - months * 30;
				
				var date = {d: d, m: m,	y: y};
				
				return date;
			}
		},
		
		saka: {
			toJED: function (date) {
				var y = date.y, m = date.m, d = date.d;
				y  = y + 4794 - Math.floor((13 - m) / 12);
				m = (m + 10) % 12;
				d = d - 1;
				
				var j1 = Math.floor((1461 * y) / 4);
				var z = Math.floor(m / 6);
				var j2 = (31 - z) * m +5 * z;
				var g = 3 * Math.floor(Math.floor((y + 184) / 100) / 4) - 36;
				
				return j1 + j2 + d - 1348 - g - 0.5;
			},
		
			fromJED: function (jed) {
				var y, m, d, jPrime, tPrime, g, x, z, s;
				jed = Math.floor(jed + 0.5);
				
				g = 3 * Math.floor(Math.floor((4 * jed + 274073) / 146097) / 4) - 36;
				
				jPrime = jed + 1348 + g;
				y = Math.floor((4 * jPrime + 3) / 1461);
				tPrime = Math.floor(((4 * jPrime + 3) % 1461) /4);
				
				x = Math.floor(tPrime / 365);
				z = Math.floor(tPrime / 185) - x;
				s = 31 - z;
				
				m = Math.floor((tPrime - 5 * z) / s);
				d = 6 * x + ((tPrime - 5 * z) % s);
		
				d = d + 1;
				m = ((m + 1) % 12) + 1;
				y = y - 4794 + Math.floor((13 - m) / 12);
				
				var date = {d: d, m: m,	y: y};
				
				return date;
			}
		}, // end: saka
		
		coptic: {
			toJED: function (date) {
				var y = date.y, m = date.m, d = date.d;
				y  = y + 4996 - Math.floor((13 - m) / 13);
				m = (m + 12) % 13;
				d = d - 1;
				
				return (Math.floor((1461 * y) / 4) + 30 * m + d - 124) - 0.5;
			},
		
			fromJED: function (jed) {
				var y, m, d, jPrime, tPrime;
				jed = Math.floor(jed + 0.5);
		
				jPrime = jed + 124;
		
				y = Math.floor((4 * jPrime + 3) / 1461);
				tPrime = Math.floor(((4 * jPrime + 3) % 1461) /4);
				m = Math.floor(tPrime / 30);
				d = tPrime % 30;
		
				d = d + 1;
				m = (m % 13) + 1;
				y = y - 4996 + Math.floor((13 - m) / 13);
				
				var date = {d: d, m: m,	y: y};
		
				return date;
			}
		}, // end: coptic
		
		islamic: {
			epoch: 1948439.5,

			toJED: function (date) {
				var d = date.d, m = date.m, y = date.y;
				
				return (
					d - 1
					+ Math.ceil(29.5 * (m - 1))
					+ (y - 1) * 354
					+ Math.floor((3 + (11 * y)) / 30)
					+ this.epoch) - 1;
			},
		
			fromJED: function (jed) {
				var y, m, d;
				jed = Math.floor(jed) + 0.5 + 1;
				y   = Math.floor(((30 * (jed - this.epoch)) + 10646) / 10631);
				m   = Math.min(
					12,
					Math.ceil((jed - (29 + this.toJED({y: y, m: 1, d: 2}))) / 29.5) + 1
				);
		
				d = (jed - this.toJED({y: y, m: m, d: 2})) + 1;
				
				var date = {
					d: d,
					m: m,
					y: y
				};
		
				return date;
			}
		}, // end: islamic
		
		persian: {
			toJED: function (date) {
				var y = date.y, m = date.m, d = date.d;
				y = y + 5348 - Math.floor((22 - m) / 13);
				//y += 1;		// temporary hack? Slava: no, it's not a hack, it's a misstake
				m = (m + 3) % 13;
				d = d - 1;
		
				return 365 * y + 30 * m + d - 77 - 0.5;
			},
		
			fromJED: function (jed) {
				var y, m, d, jPrime, tPrime;
				jed = Math.floor(jed + 0.5);
		
				jPrime = jed + 77;
		
				y = Math.floor(jPrime / 365);
				tPrime = jPrime % 365;
				m = Math.floor(tPrime / 30);
				d = tPrime % 30;
		
				d = d + 1;
				m = (m + 9) % 13 + 1;
				y = Math.floor(y - 5348 + (22 - m) / 13);
				
				var date = {d: d, m: m,	y: y};
		
				return date;
			}
		}, // end: persian
		
		republican: {
			yearLengthMonths: 13,
			
			toJED: function (date) {
				var y = date.y, m = date.m, d = date.d;
				
				this.refs = {
					y: y,
					m: m,
					d: d
				};
		
				if (this.ymdCheck('y', 'm', 'd')) {
					return -1; 
				}
		
				y = this.refs.y;
				m = this.refs.m;
				d = this.refs.d;
		
				var yPrime, mPrime, dPrime, j1, j2, g, jed;
		
		        yPrime = y + 6504 - Math.floor((13 - m) / 13);
		        mPrime = (m + 12) % 13;
		        dPrime = d - 1;
		
		        j1 = Math.floor((1461 * yPrime) / 4);
		        j2 = 30 * mPrime;
				
		        g = Math.floor(3 * Math.floor((yPrime + 396) / 100) / 4) - 51;
		
				jed = j1 + j2 + dPrime - 111 - g - 0.5;
		
				return jed;
			},
		
			fromJED: function (jed) {
				var j = Math.floor(jed + 0.5);
				
				var g, jPrime, yPrime, tPrime, mPrime, dPrime, d, m, y;
				
				g = Math.floor(3 * Math.floor((4 * j + 578797) / 146097) / 4) - 51;
		
				jPrime = j + 111 + g;
				
				yPrime = Math.floor((4 * jPrime + 3) / 1461);
				tPrime = Math.floor(((4 * jPrime + 3) % 1461) / 4);
				mPrime = Math.floor(tPrime / 30);
				dPrime = tPrime % 30;
			
				d = dPrime + 1;
				m = (mPrime % 13) + 1;
				y = yPrime - 6504 + Math.floor((13 - m) / 13);
				
				var dow = (Math.abs(y) * 12 + m * 30 + d) % 10;
				if(dow == 0) dow = 10;
				
				var date = {d: d, m: m,	y: y, dow: dow};
		
				return date;				
			},
		
			ymdCheck: function (a, b, c) {
				if (this.ymCheck(a, b)) {
					return 1;
				}
		
				this.dayBorrow(a, b, c);
				this.dayCarry(a, b, c);
		
				return 0;
			},
		
			ymCheck: function (a, b)  {
				if (this.yCheck(a)) {
					return 1;
				};
				
				this.monthBorrow(a, b);
				this.monthCarry(a, b);
				
				return 0;
			},
		
			yCheck: function (a) {
				return !(this.refs[a] > 0);
			},
		
			monthBorrow: function (a, b) {
				while (this.refs[b] <= 0) {
					this.refs[b] += this.yearLengthMonths;
					this.refs[a]--;
				}
			},
		
			monthCarry: function (a, b) {
				var months = this.yearLengthMonths;
		
				if (this.refs[b] <= months) {
					return;
				}
		
				this.refs[b] -= months;
				this.refs[a]++;
			},
		
			dayBorrow: function (a, b, c){
				while (this.refs[c] <= 0) {
					this.refs[b]--;
					
					this.monthBorrow(a, b);
					this.refs[c] += this.monthLength(this.refs[a], this.refs[b]);
				}
			},
		
			dayCarry: function (a, b, c) {
				var days = this.monthLength(this.refs[a], this.refs[b]);
				
				while (this.refs[c] > days) {
					this.refs[c] -= days;
					this.refs[b]++;
					
					days = this.monthLength(this.refs[a], this.refs[b]);
					this.monthCarry(a, b);
				}
			},
		
			monthLength: function (y, i) {
				this.refs.y2 = y;
				this.refs.m2 = i;
		
				if (this.ymCheck('y2', 'm2')) {
					return 0;
				} 
				
				if(1 <= this.refs.m2 && this.refs.m2 <= 12) {
					return 30;
				} else {
					if(this.refs.m2 == 13) {
						if(this.yearIsLeap(this.refs.y2)) {
							return 6;
						} else {
							return 5;
						}
					}
				}
			},
		
			yearIsLeap: function (y) {
				if (this.yCheck(y)) {
					return 0;
				}
		
				var ret = 0;
				
				if((y + 1) % 4 == 0) {
					ret = 1;
					if((y + 1) % 100 == 0) {
						ret = 0;
						if((y + 1) % 400 == 0) {
							ret = 1;
							if((y + 1) % 4000 == 0) {
								ret = 0;
							}
						}
					}
				}
				
				return ret;
			}
		}, // end: republican
		
		roman: {
			yearLengthMonths: 12,

			toJED: function (date) {
				var y = date.y, m = date.m, d = date.d;
				
				this.refs = {
					y: y,
					m: m,
					d: d
				};
		
				if(this.ymdCheck('y', 'm', 'd')) {
					return -1;
				}
				
				y = this.refs.y;
				m = this.refs.m;
				d = this.refs.d;
				
				y = this.yRomanToJulian(y);
				
				
				var y = this.yearToAstronomical(y);
				
				var yPrime, mPrime, dPrime, j1, j2;
		
				yPrime = y + 4716 - Math.floor((14 - m) / 12);
				mPrime = (m + 9) % 12;
				dPrime = d - 1;
			
				j1 = Math.floor((1461 * yPrime) / 4);
				j2 = Math.floor((153 * mPrime + 2) / 5);
				
				var jed = (j1 + j2 + dPrime - 1401) - 0.5;
				
				return jed;
			},
		
			fromJED: function (jed) {		
				var j = Math.floor(jed + 0.5);
				
				var jPrime, yPrime, tPrime, mPrime, dPrime, d, m, y;
		
				jPrime = j + 1401;
				
				yPrime = Math.floor((4 * jPrime + 3) / 1461);
				tPrime = Math.floor(((4 * jPrime + 3) % 1461) / 4);
				mPrime = Math.floor((5 * tPrime + 2) / 153);
				dPrime = Math.floor(((5 * tPrime + 2) % 153) / 5);
				
				d = dPrime + 1;
				m = ((mPrime + 2) % 12) + 1;
				y = yPrime - 4716 + Math.floor((14 - m) / 12);
				
				y = this.yearFromAstronomical(y);
				
				y = this.yJulianToRoman(y);
				
				var date = {d: d, m: m,	y: y};
		
				return date;
				
			},
			
			yRomanToJulian: function(y) {
				y = y - 753;
				
				if(y <= 0) {
					y--
				}
				
				return y;
			},
			
			yJulianToRoman: function(y) {
				if(y == 0) {
					return -1;
				}
				
				if(y < 0) {
					y++;
				}
				
				y = y + 753;
				return y;
			},
		
			ymdCheck: function (y, m, d) {
				if (y <= 0) {
					return 1;
				}
				
				this.monthBorrow(y, m);
				this.monthCarry(y, m);
		
				this.dayBorrow(y, m, d);
				this.dayCarry(y, m, d);
		
				return 0;
			},
		
			ymCheck: function (y, m)  {
				if (this.yCheck(y)) {
					return 1;
				};
				
				this.monthBorrow(y, m);
				this.monthCarry(y, m);
				
				return 0;
			},
		
			yCheck: function (a) {
				return !(this.refs[a] > 0);
			},
		
			monthBorrow: function (a, b) {
				while (this.refs[b] <= 0) {
					this.refs[b] += this.yearLengthMonths;
					this.refs[a]--;
					
					if(!this.refs[a]) {
						this.refs[a] = -1;
					}
				}
			},
		
			monthCarry: function (a, b) {
				var months = this.yearLengthMonths;
		
				if (this.refs[b] <= months) {
					return;
				}
		
				this.refs[b] -= months;
				this.refs[a]++;
			},
		
			dayBorrow: function (a, b, c){
				while (this.refs[c] <= 0) {
					this.refs[b]--;
					
					this.monthBorrow(a, b);
					this.refs[c] += this.monthLength(this.refs[a], this.refs[b]);
				}
			},
		
			dayCarry: function (a, b, c) {
				var days = this.monthLength(this.refs[a], this.refs[b]);
				
				while (this.refs[c] > days) {
					this.refs[c] -= days;
					this.refs[b]++;
					
					days = this.monthLength(this.refs[a], this.refs[b]);
					this.monthCarry(a, b);
				}
			},
		
			monthLength: function (y, i) {
				this.refs.y2 = y;
				this.refs.m2 = i;
		
				if (this.ymCheck('y2', 'm2')) {
					return 0;
				}
		
				var mdays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
		
				var ret = mdays[this.refs.m2 - 1];
				
				if (this.refs.m2 == 2 && this.yearIsLeap(this.refs.y2)) {
					ret++;
				}
		
				return ret;
			},
		
			yearIsLeap: function (y) {
				if (this.yCheck(y)) {
					return 0;
				}
		
				y = this.yRomanToJulian(y);
				
				if (!y) {
					return 0;
				}
				
				y = this.yearToAstronomical(y);
				
				return this.iModp(y, 4) == 0;
			}
		}, // end: roman
		
		syrian: {
			toJED: function (date) {
				var y = date.y, m = date.m, d = date.d;
				y  = y + 4405 - Math.floor((17 - m) / 12);
				m = (m + 6) % 12;
				d = d - 1;
				
				return Math.floor((1461 * y) / 4) + Math.floor((153 * m + 2) / 5) + d - 1401 - 0.5;
			},
		
			fromJED: function (jed) {
				var y, m, d, jPrime, tPrime;
				jed = Math.floor(jed + 0.5);
		
				jPrime = jed + 1401;
		
				y = Math.floor((4 * jPrime + 3) / 1461);
				tPrime = Math.floor(((4 * jPrime + 3) % 1461) / 4);
				m = Math.floor((5 * tPrime + 2) / 153);
				d = Math.floor(((5 * tPrime + 2) % 153) / 5);
		
				d = d + 1;
				m = (m + 5) % 12 + 1;
				y = y - 4405 + Math.floor((17 - m) / 12);
				
				var date = {d: d, m: m,	y: y};
				
				return date;
			}
		}, // end: syrian
		
		ethiopian: {
			toJED: function (date) {
				var y = date.y, m = date.m, d = date.d;
				
				y  = y + 4720 - Math.floor((13 - m) / 13);
				m = (m + 12) % 13;
				d = d - 1;
				
				return Math.floor((1461 * y) / 4) + (30 * m) + d - 124 - 0.5;
			},
		
			fromJED: function (jed) {
				var y, m, d, jPrime, tPrime;
				jed = Math.floor(jed + 0.5);
		
				jPrime = jed + 124;
		
				y = Math.floor((4 * jPrime + 3) / 1461);
				tPrime = Math.floor(((4 * jPrime + 3) % 1461) /4);
				m = Math.floor(tPrime / 30);
				d = tPrime % 30;
		
				d = d + 1;
				m = (m % 13) + 1;
				y = y - 4720 + Math.floor((13 - m) / 13);
				
				var date = {d: d, m: m,	y: y};
		
				return date;
			}
		}, // end: ethiopian
		
		julian: {
			toJED: function (date) {
				var y = date.y, m = date.m, d = date.d;
				
				var y2 = this.yearToAstronomical(y);
		
				var yPrime, mPrime, dPrime, j1, j2;
		
				yPrime = y2 + 4716 - Math.floor((14 - m) / 12);
				mPrime = (m + 9) % 12;
				dPrime = d - 1;
			
				j1 = Math.floor((1461 * yPrime) / 4);
				j2 = Math.floor((153 * mPrime + 2) / 5);
				
				var iAbsol = (j1 + j2 + dPrime - 1401) - 0.5;
				
				return iAbsol;
			},
		
			fromJED: function (jed) {
				var j = Math.floor(jed + 0.5);
				
				var jPrime, yPrime, tPrime, mPrime, dPrime, d, m, y;
		
				jPrime = j + 1401;
				
				yPrime = Math.floor((4 * jPrime + 3) / 1461);
				tPrime = Math.floor(((4 * jPrime + 3) % 1461) / 4);
				mPrime = Math.floor((5 * tPrime + 2) / 153);
				dPrime = Math.floor(((5 * tPrime + 2) % 153) / 5);
				
				d = dPrime + 1;
				m = ((mPrime + 2) % 12) + 1;
				y = yPrime - 4716 + Math.floor((14 - m) / 12);
				
				y = this.yearFromAstronomical(y);
				
				var date = {d: d, m: m,	y: y};
				
				return date;
			}
		} // end: julian
	}
};

dateConverter.init();

/*
 * Date converter interface plugin
 * 
 * @author slava
 */
(function($){
	$.widget("ui.dateConverterList", {
		_init: function() {
			var o = this.options;
			var el = this.element;
			var self = this;
			
			el.find('a.bubble-link').cluetip();
			
			this.rows = el.find('li');
			var rows = this.rows;
			
			this.calendars = {};
			rows.each(function(){
				self.calendars[this.id] = {};
				var calendar = self.calendars[this.id];
				
				var $this = $(this);
				calendar.day = $this.find('.day');
				calendar.month = $this.find('.month');
				calendar.year = $this.find('.year');
				calendar.row = $this;
			});
			
			// default values
			var defCal = this.calendars[o.defaultType];
			var today = new Date();
			defCal.day.val(today.getDate());
			defCal.month.val(today.getMonth() + 1);
			defCal.year.val(today.getFullYear());
			
			// selectmenu functions
			var content = $('#content');
			function close(event, selectmenu) {
				selectmenu.list.shadow('hide');
				$(document).trigger('hideCluetip');
				content.height('');
			}
						
			function open(event, selectmenu) {
				var list = selectmenu.list;
				list.css('top', selectmenu.newelement.children().offset().top);
				if (o.converterType != 'information') {
					if(!IE6) 
						list.width('auto');
				}
				
				list.shadow();
				list.shadow('show');
				
				var listHeight = list.height();
				var listOffset = list.offset();
				var contentHeight = content.height();
				var contentOffset = content.offset();
				if(listHeight + listOffset.top > contentHeight + contentOffset.top) {
					content.height(listHeight + listOffset.top - contentOffset.top);
				}
			}
			// end: selectmenu functions
			
			el.find('.month').selectmenu({
				close: close,
				open: open,
				style: 'dropdown',
				transferClasses: true
			});
			
			el.find('.day, .month, .year').bind('keyup change', function() {
				var id = $(this).closest('li')[0].id;
				self.select(id);
			});
			
			rows.click(function() {
				self.select(this.id);
			});
			
			this.select(o.defaultType);
			
			el.show();
		},
		
		convert: function(type){
			var el = this.element;
			var o = this.options;
						
			if (this.isEmpty(type)) {				
				var calendar = this.calendars[type];
				
				if (this.isDate(type)) {
					
					var date = {
						d: parseInt(calendar.day.val(), 10),
						m: parseInt(calendar.month.val(), 10),
						y: parseInt(calendar.year.val(), 10)
					}
					
					for (var outType in this.calendars) {
						if (outType != type) {
							var outCalendar = this.calendars[outType];
							
							var outDate = o.converter.convert(date, type, outType);
							if (outDate) {
								outCalendar.day.val(outDate.d);
								outCalendar.month.selectmenu('value', outDate.m - 1);
								outCalendar.year.val(outDate.y);
							} else {
								this.disable(outType);
							}
						}
					}
				} else {
					this.error(type);
				}
			}
		},
		
		select: function(type) {
			var el = this.element;
			
			this.error(false);
			this.disable(false);
			
			var selected = 'selected bg bg-h36 dc-bg';
			this.rows.removeClass(selected).filter('#'+type).addClass(selected);
			
			this.convert(type);
		},
		
		error: function(type) {
			var el = this.element;
			var error = 'error red-h36';
			this.rows.removeClass(error);
			if(type) {
				this.calendars[type].row.addClass(error);
			}
		},
		
		disable: function(type) {
			var el = this.element;
			var disabled = 'disabled';
			this.rows.removeClass(disabled);
			if(type) {
				this.calendars[type].row.addClass(disabled);
			}
		},
		
		isEmpty: function(type) {
			var calendar = this.calendars[type];
			
			if(calendar.day.val() != '' && calendar.year.val() != '' && calendar.year.val() != '-') {
				return true;
			} else {
				return false;
			}
		},
		
		isDate: function(type) {
			var o = this.options;
			var flag = false;
			var calendar = this.calendars[type];
			var date = {
				d: calendar.day.val(),
				m: parseInt(calendar.month.val(), 10),
				y: calendar.year.val()
			}
			
			if (date.d.search(/^\d+$/) != -1 && date.y.search(/^-?\d+$/) != -1) {
				var convDate = o.converter.convert(date, type, type);
				
				if(date.d == convDate.d && date.m == convDate.m && date.y == convDate.y) {
					flag = true;
				}
			}
			
			return flag;
		}
	});
	
	$.extend($.ui.dateConverterList, {
		defaults: {
			converter: dateConverter,
			defaultType: 'gregorian'
		}
	});
})(jQuery);
/* end: new date converter */

var DATE = {};

DATE.DateConverter = function () {
	this.formats = {};
	this.formats['gregorian'] = new this.gregorian(this);
	this.formats['hebrew']    = new this.hebrew(this);
	this.formats['julian']    = new this.julian(this);
	this.formats['islamic']   = new this.islamic(this);
	this.formats['armenian']  = new this.armenian(this);
	this.formats['persian']   = new this.persian(this);
	this.formats['alexandrian'] = new this.alexandrian(this);
	this.formats['bahai'] = new this.bahai(this);
	this.formats['coptic'] = new this.coptic(this);
	this.formats['ethiopian'] = new this.ethiopian(this);
	//this.formats['macedonian'] = new this.macedonian(this);
	this.formats['republican'] = new this.republican(this);
	this.formats['roman'] = new this.roman(this);
	this.formats['saka'] = new this.saka(this);
	this.formats['syrian'] = new this.syrian(this);
	//this.formats['tamil'] = new this.tamil(this);
	this.formats['zoroastrian'] = new this.zoroastrian(this);

	return this;
}

DATE.DateConverter.prototype = {
	convert: function (from, to, aDate) {
		var jed = this.formats[from].toJED(aDate[0], aDate[1], aDate[2]);
		return this.formats[to].fromJED(jed);
	},

	mod: function (a, b) {
		return a - (b * Math.floor(a / b));
	},

	yearToAstronomical: function (y) {
		if (y < 0) {
			return y + 1;
		}

		if (!y) {
			return 10000000;
		}

        return y;
	},

	yearFromAstronomical: function (y) {
		return (y <= 0) ? y - 1 : y;
	},

	iWrap: function (iVal, iLo, iHi) {
		var wide = iHi + 1 - iLo;

		if (wide == 0) {
			return iLo;
		} else {
			return iLo + this.iModp(iVal - iLo, wide);
		}
	},

	iModp: function (i, j) {
		var ret = i % j;

		if (ret < 0) {
			ret += Math.abs(j);
		}

		return ret;
	}
}

// GREGORIAN
DATE.DateConverter.prototype.gregorian = function (that) {
	var t = this;
	t.that = that;
	t.yearLengthMonths = 12;
}

DATE.DateConverter.prototype.gregorian.prototype = {
	toJED: function (y, m, d) {
		this.refs = {
			y: y,
			m: m,
			d: d
		};

		if (this.ymdCheck('y', 'm', 'd')) {
			return -1; 
		}

		y = this.refs.y;
		m = this.refs.m;
		d = this.refs.d;
		
		
		var y2 = this.that.yearToAstronomical(y);
		
		var yPrime, mPrime, dPrime, j1, j2, g, jed;

        yPrime = y2 + 4716 - Math.floor((14 - m) / 12);
        mPrime = (m + 9) % 12;
        dPrime = d - 1;

        j1 = Math.floor((1461 * yPrime) / 4);
        j2 = Math.floor((153 * mPrime + 2) / 5);
        g = Math.floor(3 * Math.floor((yPrime + 184) / 100) / 4) - 38;

		jed = j1 + j2 + dPrime - 1401 - Math.floor(g) - 0.5;

		return jed;
	},

	fromJED: function (jed) {
		var j = Math.floor(jed + 0.5);
		
		var g, jPrime, yPrime, tPrime, mPrime, dPrime, d, m, y;
		
		g = Math.floor(3 * Math.floor((4 * j + 274277) / 146097) / 4) - 38;

		jPrime = j + 1401 + g;
		
		yPrime = Math.floor((4 * jPrime + 3) / 1461);
		tPrime = Math.floor(((4 * jPrime + 3) % 1461) / 4);
		mPrime = Math.floor((5 * tPrime + 2) / 153);
		dPrime = Math.floor(((5 * tPrime + 2) % 153) / 5);
	
		d = dPrime + 1;
		m = ((mPrime + 2) % 12) + 1;
		y = Math.floor(yPrime - 4716 + (14 - m) / 12);
	   
		y = this.that.yearFromAstronomical(y);
		
		var date = new Date((y < 0 ? y+1 : y), m-1, d); 
		var dow = date.getDay();
		if(dow == 0) dow = 7;
		
		return [y, m, d, dow];
		//return [y, m, d];
		
	},

	ymdCheck: function (a, b, c) {
		if (this.ymCheck(a, b)) {
			return 1;
		}

		this.dayBorrow(a, b, c);
		this.dayCarry(a, b, c);

		return 0;
	},

	ymCheck: function (a, b)  {
		if (this.yCheck(a)) {
			return 1;
		};
		
		this.monthBorrow(a, b);
		this.monthCarry(a, b);
		
		return 0;
	},

	yCheck: function (a) {
		return this.refs[a] == 0;
	},

	monthBorrow: function (a, b) {
		while (this.refs[b] <= 0) {
			this.refs[b] += this.yearLengthMonths;
			this.refs[a]--;
		
			if (!this.refs[a]) {
				this.refs[a] = -1;
			}
		}
	},

	monthCarry: function (a, b) {
		var months = this.yearLengthMonths;

		if (this.refs[b] <= months) {
			return;
		}

		this.refs[b] -= months;
		this.refs[a]++;
	},

	dayBorrow: function (a, b, c){
		while (this.refs[c] <= 0) {
			this.refs[b]--;
			this.monthBorrow(a, b);
			this.refs[c] += this.monthLength(this.refs[a], this.refs[b]);
		}
	},

	dayCarry: function (a, b, c) {
		var days = this.monthLength(this.refs[a], this.refs[b]);
		
		while (this.refs[c] > days) {
			this.refs[c] -= days;
			this.refs[b]++;
			
			days = this.monthLength(this.refs[a], this.refs[b]);
			this.monthCarry(a, b);
		}
	},

	monthLength: function (y, i) {
		this.refs.y2 = y;
		this.refs.m2 = i;

		if (this.ymCheck('y2', 'm2')) {
			return 0;
		}

		var mdays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

		var ret = mdays[this.refs.m2 - 1];
		
		if (this.refs.m2 == 2 && this.yearIsLeap(this.refs.y2)) {
			ret++;
		}

		return ret;
	},

	yearIsLeap: function (y) {
		if (!y) {
			return 0;
		}

		var y2 = this.that.yearToAstronomical(y);
		
		if (y2 % 400 == 0) {
			return 1;
		}
		if (y2 % 100 == 0) {
			return 0;
		}
		if (y2 % 4 == 0) {
			return 1;
		}
	
		return 0;
	}
}
// eof GREGORIAN


// HEBREW
DATE.DateConverter.prototype.hebrew = function (that) {
	var t = this;
	t.that = that;
	t.epoch = 347995.5;
};

DATE.DateConverter.prototype.hebrew.prototype = {
	toJED: function (y, m, d) {
		var months = this.yearMonths(y);

		var jed = this.epoch + this.delay1(y) + this.delay2(y) + d + 1;
		
		if (m < 7) {
			for (var mon = 7; mon <= months; mon++) {
				jed += this.monthDays(y, mon);
			}

			for (var mon = 1; mon < m; mon++) {
				jed += this.monthDays(y, mon);
			}
		} else {
			for (var mon = 7; mon < m; mon++) {
				jed += this.monthDays(y, mon);
			}
		}
		
		return jed;

	},

	fromJED: function (jed) {
		var y, m, d;

		jed = Math.floor(jed) + 0.5;

		var count = Math.floor(((jed - this.epoch) * 98496.0) / 35975351.0);
		var y = count - 1;
		
		for (var i = count; jed >= this.toJED(i, 7, 1); i++) {
			y++;
		}
		
		var first = (jed < this.toJED(y, 1, 1)) ? 7 : 1;
		
		m = first;

		for (var i = first; jed > this.toJED(y, i, this.monthDays(y, i)); i++) {
			m++;
		}
		
		d = (jed - this.toJED(y, m, 1)) + 1;
		
		return [y, m, d];
	},

	yearMonths: function (y) {
		return this.leap(y) ? 13 : 12;
	},

	leap: function (y) {
		return (((y * 7) + 1) % 19) < 7;
	},

	delay1: function (y) {
		var months = Math.floor(((235 * y) - 234) / 19);
		var parts = 12084 + (13753 * months);
		var days = (months * 29) + Math.floor(parts / 25920);

		if (((3 * (days + 1)) % 7) < 3) {
			days++;
		}

		return days;
	},

	delay2: function (y) {
		var last = this.delay1(y - 1);
		var present = this.delay1(y);
		var next = this.delay1(y + 1);

		return ((next - present) == 356) ? 2 : (((present - last) == 382) ? 1 : 0);
	},

	monthDays: function (y, m) {
		if (m == 2 || m == 4 || m == 6 || m == 10 || m == 13) {
			return 29;
		}

		if (m == 12 && !this.leap(y)) {
			return 29;
		}

		if (m == 8 && !((this.yearDays(y) % 10) == 5)) {
			return 29;
		}
		
		if (m == 9 && ((this.yearDays(y) % 10) == 3)) {
			return 29;
		}
	
		return 30;
	},
	
	yearDays: function (y) {
		return this.toJED(y + 1, 7, 1) - this.toJED(y, 7, 1);
	}
}
// eof HEBREW


// JULIAN
DATE.DateConverter.prototype.julian = function (that) {
	var t = this;
	t.that = that;
}

DATE.DateConverter.prototype.julian.prototype = {
	toJED: function (y, m, d) {
		var y2 = this.that.yearToAstronomical(y);

		var yPrime, mPrime, dPrime, j1, j2;

		yPrime = y2 + 4716 - Math.floor((14 - m) / 12);
		mPrime = (m + 9) % 12;
		dPrime = d - 1;
	
		j1 = Math.floor((1461 * yPrime) / 4);
		j2 = Math.floor((153 * mPrime + 2) / 5);
		
		var iAbsol = (j1 + j2 + dPrime - 1401) - 0.5;
		
		return iAbsol;
	},

	fromJED: function (jed) {
		var j = Math.floor(jed + 0.5);
		
		var jPrime, yPrime, tPrime, mPrime, dPrime, d, m, y;

		jPrime = j + 1401;
		
		yPrime = Math.floor((4 * jPrime + 3) / 1461);
		tPrime = Math.floor(((4 * jPrime + 3) % 1461) / 4);
		mPrime = Math.floor((5 * tPrime + 2) / 153);
		dPrime = Math.floor(((5 * tPrime + 2) % 153) / 5);
		
		d = dPrime + 1;
		m = ((mPrime + 2) % 12) + 1;
		y = yPrime - 4716 + Math.floor((14 - m) / 12);
		
		y = this.that.yearFromAstronomical(y);
		
		return [y, m, d];
	}
}
// eof JULIAN


// ISLAMIC
DATE.DateConverter.prototype.islamic = function (that) {
	var t = this;
	t.that = that;
	t.epoch = 1948439.5;
};

DATE.DateConverter.prototype.islamic.prototype = {
	toJED: function (y, m, d) {
		return (
			d - 1
			+ Math.ceil(29.5 * (m - 1))
			+ (y - 1) * 354
			+ Math.floor((3 + (11 * y)) / 30)
			+ this.epoch) - 1;
	},

	fromJED: function (jed) {
		var y, m, d;
		jed = Math.floor(jed) + 0.5 + 1;
		y   = Math.floor(((30 * (jed - this.epoch)) + 10646) / 10631);
		m   = Math.min(
			12,
			Math.ceil((jed - (29 + this.toJED(y, 1, 2))) / 29.5) + 1
		);

		d   = (jed - this.toJED(y, m, 2)) + 1;

		return [y, m, d];
	}
};
// eof ISLAMIC


// PERSIAN
DATE.DateConverter.prototype.persian = function (that) {
	this.that = that;
};

DATE.DateConverter.prototype.persian.prototype = {
	toJED: function (y, m, d) {
		y = y + 5348 - Math.floor((22 - m) / 13);
		//y += 1;		// temporary hack? Slava: no, it's not a hack, it's a misstake
		m = (m + 3) % 13;
		d = d - 1;

		return 365 * y + 30 * m + d - 77 - 0.5;
	},

	fromJED: function (jed) {
		var y, m, d, jPrime, tPrime;
		jed = Math.floor(jed + 0.5);

		jPrime = jed + 77;

		y = Math.floor(jPrime / 365);
		tPrime = jPrime % 365;
		m = Math.floor(tPrime / 30);
		d = tPrime % 30;

		d = d + 1;
		m = (m + 9) % 13 + 1;
		y = Math.floor(y - 5348 + (22 - m) / 13);

		return [y, m, d];
	}
};
// eof PERSIAN


// ARMENIAN
DATE.DateConverter.prototype.armenian = function (that) {
	this.that = that;
};

DATE.DateConverter.prototype.armenian.prototype = {
	toJED: function (y, m, d) {
		y  = Math.floor(y + 5268 - (13 - m) / 13);

		if (m < 13) {
			y += 1;		// temporary hack?
		}

		m = Math.floor(this.that.mod(m + 12, 13));
		d = d - 1;

		return (365 * y + 30 * m + d - 317) - 0.5;
	},

	fromJED: function (jed) {
		var y, m, d, jPrime, tPrime;
		jed = Math.floor(jed + 0.5);

		jPrime = jed + 317;

		y = Math.floor(jPrime / 365);
		tPrime = this.that.mod(jPrime, 365);
		m = Math.floor(tPrime / 30);
		d = this.that.mod(tPrime, 30);

		d = d + 1;
		m = this.that.mod(m, 13) + 1;
		y = Math.floor(y - 5268 + (13 - m) / 13);

		return [y, m, d];
	}
};
// eof ARMENIAN

// ALEXANDRIAN
DATE.DateConverter.prototype.alexandrian = function (that) {
	this.that = that;
};

DATE.DateConverter.prototype.alexandrian.prototype = {
	toJED: function (y, m, d) {
		y  = y + 4690 - Math.floor((13 - m) / 13);

		m = (m + 12) % 13;
		d = d - 1;
		
		return (Math.floor((1461 * y) / 4) + 30 * m + d - 124) - 0.5;
	},

	fromJED: function (jed) {
		var y, m, d, jPrime, tPrime;
		jed = Math.floor(jed + 0.5);

		jPrime = jed + 124;

		y = Math.floor((4 * jPrime + 3) / 1461);
		tPrime = Math.floor(((4 * jPrime + 3) % 1461) /4);
		m = Math.floor(tPrime / 30);
		d = tPrime % 30;

		d = d + 1;
		m = (m % 13) + 1;
		
		y = y - 4690 + Math.floor((13 - m) / 13);

		return [y, m, d];
	}
};
// eof ALEXANDRIAN

// BAHAI
DATE.DateConverter.prototype.bahai = function (that) {
	this.that = that;
};

DATE.DateConverter.prototype.bahai.prototype = {
	toJED: function (y, m, d) {
		y  = y + 6560 - Math.floor((39 - m) / 20);
		m = m % 20;
		d = d - 1;
		
		var g = 3 * Math.floor(Math.floor((y + 184) / 100) / 4) - 50;
		
		return Math.floor((1461 * y) / 4) + (19 * m) + d - 1412 - g - 0.5;
	},

	fromJED: function (jed) {
		var y, m, d, jPrime, tPrime;
		jed = Math.floor(jed + 0.5);
		
		var g = 3 * Math.floor(Math.floor((4 * jed +274273) / 146097) / 4) - 50;
		jPrime = jed + 1412 + g;

		y = Math.floor((4 * jPrime + 3) / 1461);
		tPrime = Math.floor(((4 * jPrime + 3) % 1461) /4);
		m = Math.floor(tPrime / 19);
		d = tPrime % 19;

		d = d + 1;
		m = ((m + 19) % 20) + 1;
		y = y - 6560 + Math.floor((39 - m) / 20);

		return [y, m, d];
	}
};
// eof BAHAI

// COPTIC
DATE.DateConverter.prototype.coptic = function (that) {
	this.that = that;
};

DATE.DateConverter.prototype.coptic.prototype = {
	toJED: function (y, m, d) {
		y  = y + 4996 - Math.floor((13 - m) / 13);
		m = (m + 12) % 13;
		d = d - 1;
		
		return (Math.floor((1461 * y) / 4) + 30 * m + d - 124) - 0.5;
	},

	fromJED: function (jed) {
		var y, m, d, jPrime, tPrime;
		jed = Math.floor(jed + 0.5);

		jPrime = jed + 124;

		y = Math.floor((4 * jPrime + 3) / 1461);
		tPrime = Math.floor(((4 * jPrime + 3) % 1461) /4);
		m = Math.floor(tPrime / 30);
		d = tPrime % 30;

		d = d + 1;
		m = (m % 13) + 1;
		y = y - 4996 + Math.floor((13 - m) / 13);

		return [y, m, d];
	}
};
// eof COPTIC

// ETHIOPIAN
DATE.DateConverter.prototype.ethiopian = function (that) {
	this.that = that;
};

DATE.DateConverter.prototype.ethiopian.prototype = {
	toJED: function (y, m, d) {
		y  = y + 4720 - Math.floor((13 - m) / 13);
		m = (m + 12) % 13;
		d = d - 1;
		
		return Math.floor((1461 * y) / 4) + (30 * m) + d - 124 - 0.5;
	},

	fromJED: function (jed) {
		var y, m, d, jPrime, tPrime;
		jed = Math.floor(jed + 0.5);

		jPrime = jed + 124;

		y = Math.floor((4 * jPrime + 3) / 1461);
		tPrime = Math.floor(((4 * jPrime + 3) % 1461) /4);
		m = Math.floor(tPrime / 30);
		d = tPrime % 30;

		d = d + 1;
		m = (m % 13) + 1;
		y = y - 4720 + Math.floor((13 - m) / 13);

		return [y, m, d];
	}
};
// eof ETHIOPIAN

// MACEDONIAN
DATE.DateConverter.prototype.macedonian = function (that) {
	this.that = that;
};

DATE.DateConverter.prototype.macedonian.prototype = {
	toJED: function (y, m, d) {
		y  = y + 4405 - Math.floor((18 - m) / 12);
		m = (m + 12) % 12;
		d = d - 1;
		
		return Math.floor((1461 * y) / 4) + Math.floor((153 * m + 2) / 5) + d - 1401 - 0.5;
	},

	fromJED: function (jed) {
		var y, m, d, jPrime, tPrime;
		jed = Math.floor(jed + 0.5);

		jPrime = jed + 1401;

		y = Math.floor((4 * jPrime + 3) / 1461);
		tPrime = Math.floor(((4 * jPrime + 3) % 1461) /4);
		m = Math.floor((5 * tPrime + 2) / 153);
		d = Math.floor(((5 * tPrime + 2) % 153) / 5);

		d = d + 1;
		m = ((m + 6) % 12) + 1;
		y = y - 4405 + Math.floor((18 - m) / 12);

		return [y, m, d];
	}
};
// eof MACEDONIAN

// REPUBLICAN
DATE.DateConverter.prototype.republican = function (that) {
	var t = this;
	t.that = that;
	t.yearLengthMonths = 13;
}

DATE.DateConverter.prototype.republican.prototype = {
	toJED: function (y, m, d) {
		this.refs = {
			y: y,
			m: m,
			d: d
		};

		if (this.ymdCheck('y', 'm', 'd')) {
			return -1; 
		}

		y = this.refs.y;
		m = this.refs.m;
		d = this.refs.d;

		var yPrime, mPrime, dPrime, j1, j2, g, jed;

        yPrime = y + 6504 - Math.floor((13 - m) / 13);
        mPrime = (m + 12) % 13;
        dPrime = d - 1;

        j1 = Math.floor((1461 * yPrime) / 4);
        j2 = 30 * mPrime;
		
        g = Math.floor(3 * Math.floor((yPrime + 396) / 100) / 4) - 51;

		jed = j1 + j2 + dPrime - 111 - g - 0.5;

		return jed;
	},

	fromJED: function (jed) {
		var j = Math.floor(jed + 0.5);
		
		var g, jPrime, yPrime, tPrime, mPrime, dPrime, d, m, y;
		
		g = Math.floor(3 * Math.floor((4 * j + 578797) / 146097) / 4) - 51;

		jPrime = j + 111 + g;
		
		yPrime = Math.floor((4 * jPrime + 3) / 1461);
		tPrime = Math.floor(((4 * jPrime + 3) % 1461) / 4);
		mPrime = Math.floor(tPrime / 30);
		dPrime = tPrime % 30;
	
		d = dPrime + 1;
		m = (mPrime % 13) + 1;
		y = yPrime - 6504 + Math.floor((13 - m) / 13);
		
		var dow = (y*12 + m*30 + d) % 10;
		if(dow == 0) dow = 10;

		return [y, m, d, dow];
		//return [y, m, d];
		
	},

	ymdCheck: function (a, b, c) {
		if (this.ymCheck(a, b)) {
			return 1;
		}

		this.dayBorrow(a, b, c);
		this.dayCarry(a, b, c);

		return 0;
	},

	ymCheck: function (a, b)  {
		if (this.yCheck(a)) {
			return 1;
		};
		
		this.monthBorrow(a, b);
		this.monthCarry(a, b);
		
		return 0;
	},

	yCheck: function (a) {
		return !(this.refs[a] > 0);
	},

	monthBorrow: function (a, b) {
		while (this.refs[b] <= 0) {
			this.refs[b] += this.yearLengthMonths;
			this.refs[a]--;
		}
	},

	monthCarry: function (a, b) {
		var months = this.yearLengthMonths;

		if (this.refs[b] <= months) {
			return;
		}

		this.refs[b] -= months;
		this.refs[a]++;
	},

	dayBorrow: function (a, b, c){
		while (this.refs[c] <= 0) {
			this.refs[b]--;
			
			this.monthBorrow(a, b);
			this.refs[c] += this.monthLength(this.refs[a], this.refs[b]);
		}
	},

	dayCarry: function (a, b, c) {
		var days = this.monthLength(this.refs[a], this.refs[b]);
		
		while (this.refs[c] > days) {
			this.refs[c] -= days;
			this.refs[b]++;
			
			days = this.monthLength(this.refs[a], this.refs[b]);
			this.monthCarry(a, b);
		}
	},

	monthLength: function (y, i) {
		this.refs.y2 = y;
		this.refs.m2 = i;

		if (this.ymCheck('y2', 'm2')) {
			return 0;
		} 
		
		if(1 <= this.refs.m2 && this.refs.m2 <= 12) {
			return 30;
		} else {
			if(this.refs.m2 == 13) {
				if(this.yearIsLeap(this.refs.y2)) {
					return 6;
				} else {
					return 5;
				}
			}
		}
	},

	yearIsLeap: function (y) {
		if (this.yCheck(y)) {
			return 0;
		}

		var ret = 0;
		
		if((y + 1) % 4 == 0) {
			ret = 1;
			if((y + 1) % 100 == 0) {
				ret = 0;
				if((y + 1) % 400 == 0) {
					ret = 1;
					if((y + 1) % 4000 == 0) {
						ret = 0;
					}
				}
			}
		}
		
		return ret;
	}
}
// eof REPUBLICAN

// ROMAN
DATE.DateConverter.prototype.roman = function (that) {
	var t = this;
	t.that = that;
	t.yearLengthMonths = 12;
}

DATE.DateConverter.prototype.roman.prototype = {
	toJED: function (y, m, d) {
		this.refs = {
			y: y,
			m: m,
			d: d
		};

		if(this.ymdCheck('y', 'm', 'd')) {
			return -1;
		}
		
		y = this.refs.y;
		m = this.refs.m;
		d = this.refs.d;
		
		y = this.yRomanToJulian(y);
		
		
		var y = this.that.yearToAstronomical(y);
		
		var yPrime, mPrime, dPrime, j1, j2;

		yPrime = y + 4716 - Math.floor((14 - m) / 12);
		mPrime = (m + 9) % 12;
		dPrime = d - 1;
	
		j1 = Math.floor((1461 * yPrime) / 4);
		j2 = Math.floor((153 * mPrime + 2) / 5);
		
		var jed = (j1 + j2 + dPrime - 1401) - 0.5;
		
		return jed;
	},

	fromJED: function (jed) {		
		var j = Math.floor(jed + 0.5);
		
		var jPrime, yPrime, tPrime, mPrime, dPrime, d, m, y;

		jPrime = j + 1401;
		
		yPrime = Math.floor((4 * jPrime + 3) / 1461);
		tPrime = Math.floor(((4 * jPrime + 3) % 1461) / 4);
		mPrime = Math.floor((5 * tPrime + 2) / 153);
		dPrime = Math.floor(((5 * tPrime + 2) % 153) / 5);
		
		d = dPrime + 1;
		m = ((mPrime + 2) % 12) + 1;
		y = yPrime - 4716 + Math.floor((14 - m) / 12);
		
		y = this.that.yearFromAstronomical(y);
		
		y = this.yJulianToRoman(y);

		return [y, m, d];
		
	},
	
	yRomanToJulian: function(y) {
		y = y - 753;
		
		if(y <= 0) {
			y--
		}
		
		return y;
	},
	
	yJulianToRoman: function(y) {
		if(y == 0) {
			return -1;
		}
		
		if(y < 0) {
			y++;
		}
		
		y = y + 753;
		return y;
	},

	ymdCheck: function (y, m, d) {
		if (y <= 0) {
			return 1;
		}
		
		this.monthBorrow(y, m);
		this.monthCarry(y, m);

		this.dayBorrow(y, m, d);
		this.dayCarry(y, m, d);

		return 0;
	},

	ymCheck: function (y, m)  {
		if (this.yCheck(y)) {
			return 1;
		};
		
		this.monthBorrow(y, m);
		this.monthCarry(y, m);
		
		return 0;
	},

	yCheck: function (a) {
		return !(this.refs[a] > 0);
	},

	monthBorrow: function (a, b) {
		while (this.refs[b] <= 0) {
			this.refs[b] += this.yearLengthMonths;
			this.refs[a]--;
			
			if(!this.refs[a]) {
				this.refs[a] = -1;
			}
		}
	},

	monthCarry: function (a, b) {
		var months = this.yearLengthMonths;

		if (this.refs[b] <= months) {
			return;
		}

		this.refs[b] -= months;
		this.refs[a]++;
	},

	dayBorrow: function (a, b, c){
		while (this.refs[c] <= 0) {
			this.refs[b]--;
			
			this.monthBorrow(a, b);
			this.refs[c] += this.monthLength(this.refs[a], this.refs[b]);
		}
	},

	dayCarry: function (a, b, c) {
		var days = this.monthLength(this.refs[a], this.refs[b]);
		
		while (this.refs[c] > days) {
			this.refs[c] -= days;
			this.refs[b]++;
			
			days = this.monthLength(this.refs[a], this.refs[b]);
			this.monthCarry(a, b);
		}
	},

	monthLength: function (y, i) {
		this.refs.y2 = y;
		this.refs.m2 = i;

		if (this.ymCheck('y2', 'm2')) {
			return 0;
		}

		var mdays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

		var ret = mdays[this.refs.m2 - 1];
		
		if (this.refs.m2 == 2 && this.yearIsLeap(this.refs.y2)) {
			ret++;
		}

		return ret;
	},

	yearIsLeap: function (y) {
		if (this.yCheck(y)) {
			return 0;
		}

		y = this.yRomanToJulian(y);
		
		if (!y) {
			return 0;
		}
		
		y = this.that.yearToAstronomical(y);
		
		return this.that.iModp(y, 4) == 0
	}
}
// eof ROMAN

// SAKA
DATE.DateConverter.prototype.saka = function (that) {
	this.that = that;
};

DATE.DateConverter.prototype.saka.prototype = {
	toJED: function (y, m, d) {
		y  = y + 4794 - Math.floor((13 - m) / 12);
		m = (m + 10) % 12;
		d = d - 1;
		
		var j1 = Math.floor((1461 * y) / 4);
		var z = Math.floor(m / 6);
		var j2 = (31 - z) * m +5 * z;
		var g = 3 * Math.floor(Math.floor((y + 184) / 100) / 4) - 36;
		
		return j1 + j2 + d - 1348 - g - 0.5;
	},

	fromJED: function (jed) {
		var y, m, d, jPrime, tPrime, g, x, z, s;
		jed = Math.floor(jed + 0.5);
		
		g = 3 * Math.floor(Math.floor((4 * jed + 274073) / 146097) / 4) - 36;
		
		jPrime = jed + 1348 + g;
		y = Math.floor((4 * jPrime + 3) / 1461);
		tPrime = Math.floor(((4 * jPrime + 3) % 1461) /4);
		
		x = Math.floor(tPrime / 365);
		z = Math.floor(tPrime / 185) - x;
		s = 31 - z;
		
		m = Math.floor((tPrime - 5 * z) / s);
		d = 6 * x + ((tPrime - 5 * z) % s);

		d = d + 1;
		m = ((m + 1) % 12) + 1;
		y = y - 4794 + Math.floor((13 - m) / 12);

		return [y, m, d];
	}
};
// eof SAKA

// SYRIAN
DATE.DateConverter.prototype.syrian = function (that) {
	this.that = that;
};

DATE.DateConverter.prototype.syrian.prototype = {
	toJED: function (y, m, d) {
		y  = y + 4405 - Math.floor((17 - m) / 12);
		m = (m + 6) % 12;
		d = d - 1;
		
		return Math.floor((1461 * y) / 4) + Math.floor((153 * m + 2) / 5) + d - 1401 - 0.5;
	},

	fromJED: function (jed) {
		var y, m, d, jPrime, tPrime;
		jed = Math.floor(jed + 0.5);

		jPrime = jed + 1401;

		y = Math.floor((4 * jPrime + 3) / 1461);
		tPrime = Math.floor(((4 * jPrime + 3) % 1461) / 4);
		m = Math.floor((5 * tPrime + 2) / 153);
		d = Math.floor(((5 * tPrime + 2) % 153) / 5);

		d = d + 1;
		m = (m + 5) % 12 + 1;
		y = y - 4405 + Math.floor((17 - m) / 12);

		return [y, m, d];
	}
};
// eof SYRIAN

// TAMIL
DATE.DateConverter.prototype.tamil = function (that) {
	var t = this;
	t.that = that;
	t.epoch = 588466.75;
	t.yearLength = 1577917828 / 4320000;
	t.monthLength = t.yearLength / 12;
};

DATE.DateConverter.prototype.tamil.prototype = {
	toJED: function (y, m, d) {

		var jed = this.epoch + (d - 1) + (m - 1) * this.monthLength + y * this.yearLength;
		return jed;

	},

	fromJED: function (jed) {
		var y, m, d;

		jed = Math.floor(jed - this.epoch);
		
		y = Math.floor(jed / this.yearLength);
		jed -= Math.floor(y * this.yearLength);
		m = 1 + Math.floor(jed / this.monthLength);
		jed -= Math.floor((m - 1) * this.monthLength);
		
		d = 1 + jed;
		
		return [y, m, d];
	}
}
// eof TAMIL

// ZOROASTRIAN
DATE.DateConverter.prototype.zoroastrian = function (that) {
	var t = this;
	t.that = that;
	t.epoch = 1579768.5;
};

DATE.DateConverter.prototype.zoroastrian.prototype = {
	toJED: function (y, m, d) {

		var jed = this.epoch + (d - 1) + 30 * (m - 1) + 365 * (y - 1);
		
		return jed;

	},

	fromJED: function (jed) {
		var y, m, d;
		
		jed = Math.floor(jed - this.epoch);
		
		d = 1 + jed;
		m = 1;
		y = 1;
		
		var years = Math.floor((d - 1) / 365);
		y += years;
		d -= years * 365;
		
		var months = Math.floor((d -1) / 30);
		m += months;
		d = d - months * 30;
		
		return [y, m, d];
	}
}
// eof ZOROASTRIAN