String.prototype.lpad = function(padString, length) {
	var str = this;
    while (str.length < length)
        str = padString + str;
    return str;
}

function Timestamp(stampString) {
	if(!stampString) {
		stampString = "0001-01-01 00:00:00";
	}
	this.year = 1;
	this.month = 1;
	this.day = 1;
	this.hour = 0;
	this.minute = 0;
	this.second = 0;
	this.calendar = "Gregorian";
	this.accuracy = 1; //between 1 and 6.  1 is year only, 6 is year, month, day, hour, minute, second
	
	
	this.parseString = function(str) {
		//check for time portion
		var parts = String(str).split(" ");
		var status = true;
		if(parts.length > 2) {
			//badly formed string
		} else if(parts.length == 1) {
			//date only
			status = this.parseDate(parts[0]);
		} else if(parts.length == 2) {
			//date and time
			status = this.parseDate(parts[0]);
			status = status && this.parseTime(parts[1]);
		}
		return status;
	}
	
	this.parseDate = function(str) {
		var parts = String(str).split("-");
		var acc = 0;
		switch(parts.length) {
			case 3: //year, month, day
				this.day = parseInt(parts[2], 10);
				acc -= 1;
			case 2: //year and month
				this.month = parseInt(parts[1], 10);
				acc -= 1;
			case 1: //year only
				this.year = parseInt(parts[0], 10);
				acc -= 1;
				this.accuracy = Math.abs(acc);
				return true;
				break;
			default:
				return false;
		}
		
	}
	
	this.parseTime = function(str) {
		var parts = String(str).split(":");
		var acc = 0;
		switch(parts.length) {
			case 3: // hour, minute, second
				this.second = parseInt(parts[2], 10);
				acc -= 1;
			case 2: // hour, minute
				this.minute = parseInt(parts[1], 10);
				acc -= 1;
			case 1: //hour only
				this.hour = parseInt(parts[0], 10);
				acc -= 1;
				//since we must have a whole date to have any time, add 3
				this.accuracy = Math.abs(acc) + 3;
				return true;
				break;
			default:
				return false;
		}
	}
	
	this.addTime = function(addend, unit) {
		//for years, just add the year and don't bother with the carrying nonsense.
		if(unit == "year") {
			this.year += addend;
			return;
		}
		//add addend units to this timestamp
		//note that adding Months will produce only estimated results
		//normalize addend to seconds
		addend = unitToSeconds(addend, unit);
		//add to the seconds of the timestamp
		this.second += addend;
		//start carrying down.
		//carry seconds to minutes
		if(this.second >= 60) {
			this.minute += Math.floor(this.second / 60);
			this.second = this.second % 60;
		}
		//carry minutes to hours
		if(this.minute >= 60) {
			this.hour += Math.floor(this.minute / 60);
			this.minute = this.minute % 60;
		}
		//carry hours to days
		if(this.hour >= 24) {
			this.day += Math.floor(this.hour / 24);
			this.hour = this.hour % 24;
		}
		//carry days to months
		//this is the sticky bit -- if only months were all the same length...
		while(this.day > otl.calendars[this.calendar].months(this.year)[this.month].days) {
			this.day -= otl.calendars[this.calendar].months(this.year)[this.month].days;
			this.month++;
			//wrap years
			if(this.month > (otl.calendars[this.calendar].months(this.year).length - 1)) {
				this.month = 1;
				this.year++;
			}
		}
	}
	
	this.subtractTime = function(quantity, unit) {
		//for years, just add the year and don't bother with the borrowing nonsense.
		if(unit == "year") {
			this.year -= quantity;
			return;
		}
		//subtract quantity units from this timestamp
		//note that subtracting Months will produce only estimated results
		//normalize quantity to seconds
		quantity = unitToSeconds(quantity, unit);
		//add to the seconds of the timestamp
		this.second -= quantity;
		//start carrying down.
		//borrow seconds from minutes
		if(this.second < 0) {
			//how many minutes do we need?
			var minToBorrow = Math.ceil(Math.abs(this.second) / 60);
			this.minute -= minToBorrow;
			this.second = minToBorrow * 60 + this.second;
		}
		//borrow minutes from hours
		if(this.minute < 0) {
			//how many hours do we need?
			var hoursToBorrow = Math.ceil(Math.abs(this.minute) / 60);
			this.hour -= hoursToBorrow;
			this.minute = hoursToBorrow * 60 + this.minute;
		}
		//borrow hours from days
		if(this.hour < 0) {
			// how many days to borrow?
			var daysToBorrow = Math.ceil(Math.abs(this.hour) / 24);
			this.day -= daysToBorrow;
			this.hour = daysToBorrow * 24 + this.hour;
		}
		//borrow days from months
		//this is the sticky bit -- if only months were all the same length...
		while(this.day <= 0) {
			this.month--;
			//wrap years
			if(this.month <= 0) {
				this.month = otl.calendars[this.calendar].monthsInYear();
				this.year--;
			}
			this.day += otl.calendars[this.calendar].months(this.year)[this.month].days;
		}
	}
	
	this.setCalendar = function(newCal) {
		this.calendar = newCal;
	}
	
	this.setYear = function(newYear) {
		this.year = newYear;
	}
	
	this.setMonth = function(newMonth) {
		this.month = newMonth;
	}
	
	this.setDay = function(newDay) {
		this.day = newDay;
	}
	
	this.setHour = function(newHour) {
		this.hour = newHour;
	}
	
	this.setMinute = function(newMinute) {
		this.minute = newMinute;
	}
	
	this.setSecond = function(newSecond) {
		this.second = newSecond;
	}
	
	this.getCalendar = function() {
		return this.calendar;
	}
	
	this.getSecond = function() {
		return this.second;
	}
	
	this.getMinute = function() {
		return this.minute;
	}
	
	this.getHour = function() {
		return this.hour;
	}
	
	this.getDay = function() {
		return this.day;
	}
	
	this.getMonth = function() {
		return this.month;
	}
	
	this.getYear = function() {
		return this.year;
	}
	
	this.toString = function() {
		var str = '';
		str += String(this.year).lpad("0", 4);
		str += "-";
		str += String(this.month).lpad("0", 2);
		str += "-";
		str += String(this.day).lpad("0", 2);
		str += " ";
		str += String(this.hour).lpad("0", 2);
		str += ":";
		str += String(this.minute).lpad("0", 2);
		str += ":";
		str += String(Math.round(this.second)).lpad("0", 2);
		return str;
	}
	
	if(stampString) {
		this.parseString( stampString );
	}
}

