//
// Extensions to String
//

// Format-function to format a string.
// Arguments: Unlimited, replaces {0} with first argument, {1} with second argument, and so forth
// Ex: "Hello {0}, this is {1}".format("world", "nice");
// Returns: "Hello world, this is nice"
String.prototype.format = function() {
	var args = arguments;
	return this.replace(/{(\d+)}/g, function(o, m) {
		return args[m];
	});
};

// Returns new string with first letter in uppercase and all the rest i lowercase
String.prototype.capitalize = function() {
	return this.substring(0, 1).toUpperCase() + this.substring(1).toLowerCase();
};

// Returns true if string is one of the strings passed as arguments
String.prototype.isOneOf = function () {
	return $.inArray(this.toString(), arguments) > -1;
};

// jQuery 1.3.2 does not parse URI's with fragments (#) as it should,
// so we have to build the URI ourselves.
// @param String params  Params in query string format: 'key=value&key2=value2'
String.prototype.appendParams = function (params) {
	var uri = new URI(this.toString());
	uri.query = (uri.query ? uri.query + '&' : '') + params;
	return uri.toString();
};

// Replace placehoders in string with corresponding keys from Object o
String.prototype.supplant = function (o) {
    return this.replace(/{([^{}]*)}/g,
        function (a, b) {
            var r = o[b];
            return typeof r === 'string' || typeof r === 'number' ? r : a;
        }
    );
};

// Trim leading and trailing whitespace
String.prototype.trim = function () {
	return this.replace(/^\s+(.*)\s+/, '$1');
};


// Extend Date
Date.prototype.getCorrectDay = function () {
	// In my opinion, monday = 1 (first day of week) and sunday = 7 (last day of week)
	var day = this.getDay();
	if (day === 0) {
		return 7;
	}
	else {
		return day;
	}
};
Date.prototype.getNextDay = function () {
	return new Date(this.getFullYear(), this.getMonth(), this.getDate() + 1);
};
Date.prototype.getPreviousDay = function () {
	return new Date(this.getFullYear(), this.getMonth(), this.getDate() - 1);
};
Date.prototype.getFirstDayOfWeek = function () {
	return new Date(this.getFullYear(), this.getMonth(), this.getDate() - (this.getCorrectDay() - 1));
};
Date.prototype.getLastDayOfWeek = function () {
	return new Date(this.getFullYear(), this.getMonth(), this.getFirstDayOfWeek().getDate() + 6);
};
Date.prototype.getFirstDayOfMonth = function () {
	return new Date(this.getFullYear(), this.getMonth(), 1);
};
Date.prototype.getLastDayOfMonth = function () {
	return new Date(this.getFullYear(), this.getMonth() + 1, 0);
};
Date.prototype.isFirstDayOfWeek = function () {
	return this.getCorrectDay() == 1;
};
Date.prototype.isLastDayOfWeek = function () {
	return this.getCorrectDay() == 7;
};
Date.prototype.isToday = function () {
	return this.isTheSameAs(new Date());
};
Date.prototype.compareTo = function (otherDate) {
	return this.getTime() - otherDate.getTime();
};
Date.prototype.isTheSameAs = function (otherDate) {
	return this.compareTo(otherDate) === 0;
};
Date.prototype.getMonthName = function () {
	return Date.i18n.monthNames[this.getMonth()];
};
Date.prototype.toISODateString = function () {
	var y = this.getFullYear(),
	    m = (this.getMonth() + 1).toString().replace(/^(\d)$/, '0$1'),
	    d = (this.getDate()).toString().replace(/^(\d)$/, '0$1');
	return y + '-' + m + '-' + d;
};
Date.prototype.toUSDateString = function () {
	var y = this.getFullYear(),
	    m = (this.getMonth() + 1).toString().replace(/^(\d)$/, '0$1'),
	    d = (this.getDate()).toString().replace(/^(\d)$/, '0$1');
	return m + '/' + d + '/' + y;
};
Date.parseISODate = function (string) {
	var split, date;
	if (string) {
		split = string.split('-');
		date = new Date(split[0], split[1] - 1, split[2]);
		return date;
	}
};
Date.parseUSDate = function (string) {
	var split, date;
	if (string) {
		split = string.split('/');
		date = new Date(split[2], split[0] - 1, split[1]);
		return date;
	}
};

Date.i18n = {
	monthNames: ['Januari','Februari','Mars','April','Maj','Juni', 'Juli','Augusti','September','Oktober','November','December'],
	monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', 'Jul','Aug','Sep','Okt','Nov','Dec'],
	dayNamesShort: ['Mån','Tis','Ons','Tor','Fre','Lör','Sön'],
	dayNames: ['Måndag','Tisdag','Onsdag','Torsdag','Fredag','Lördag','Söndag'],
	dayNamesMin: ['M','T','O','T','F','L','S']
};
Date.milliseconds = {
	SECOND: 1000,
	MINUTE: 60000,
	HOUR: 3600000,
	DAY: 86400000,
	WEEK: 604800000,
	YEAR: 31536000000
};


/* Month --------------------------------------------------------------*/

Month = function (date) {
	date = date || new Date();
	this.firstDay = date.getFirstDayOfMonth();
	this.lastDay  = date.getLastDayOfMonth();
};

Month.prototype = {
	getName: function () {
		return this.firstDay.getMonthName();
	},
	getMonth: function () {
		return this.firstDay.getMonth();
	},
	getYear: function () {
		return this.firstDay.getFullYear();
	},
	getPreviousMonth: function () {
		return new Month(this.firstDay.getPreviousDay());
	},
	getNextMonth: function () {
		return new Month(this.lastDay.getNextDay());
	},
	toISODateString: function () {
		return this.firstDay.toISODateString();
	},
	toUSDateString: function () {
		return this.firstDay.toUSDateString();
	},
	compareTo: function (otherMonth) {
		return this.firstDay.getTime() - otherMonth.firstDay.getTime();
	},
	isTheSameAs: function (otherMonth) {
		return this.compareTo(otherMonth) === 0;
	}
};


NetR = typeof NetR === 'undefined' ? {} : NetR;

/* DatePicker --------------------------------------------------------------*/

NetR.DatePicker = function (options) {
	var self = this;
	this.options = $.extend($.extend({}, NetR.DatePicker.defaultOptions), options || {});

	// Bind to target, if supplied
	if (this.options.target) {
		this.options.target.bind({
			click: function (e) {
				e.preventDefault();
				self.show();
			},
			focus: function (e) {
				self.show();
			},
			change: function (e) {
				(this.options.format == 'US') ? self.setDate(Date.parseUSDate(self.options.target.val())) : self.setDate(Date.parseISODate(self.options.target.val()));
			}
		});
	}
	NetR.DatePicker.datepickers.push(this);
};

NetR.DatePicker.datepickers = [];

NetR.DatePicker.prototype = {
	disabledButtonClass: 'disabled',
	monthSelectFormat: '%Y-%m-%d',
	activeDate: null,
	setup: function () {
		var self = this;
		var opt = this.options;
		var target = opt.target;
		var targetCoords;

		// Create and hide containers
		this.containerElement = $('<div>', {
			'class': 'date-picker'
		});
		this.hide();

		this.navContainer = $('<div>', {
			'class': 'navigation-container cf'
		});

		this.tableContainer = $('<div>', {
			'class': 'table-container'
		});
		this.containerElement.append(this.navContainer, this.tableContainer);

		if (target) {
			targetCoords = target.position();
			target.after(this.containerElement);
			this.containerElement.css({
				'top': targetCoords.top + target.outerHeight(),
				'left': targetCoords.left
			});
		}

		// Setup navigation
		this.goBack = $('<a>', {
			'href': '#',
			'class': 'prev',
			click: function (e) {
				e.preventDefault();
				if (!self.goBackDisabled) {
					self.showLastMonth();
				}
			}
		});
		this.goBack.append($('<img>', {
			src: '/gothiatowers/i/icons/arrow-left-blue.png',
			alt: 'Föregående'
		}));

		this.goForward = $('<a>', {
			'href': '#',
			'class': 'next',
			click: function (e) {
				e.preventDefault();
				if (!self.goForwardDisabled) {
					self.showNextMonth();
				}
			}
		});
		this.goForward.append($('<img>', {
			src: '/gothiatowers/i/icons/arrow-right-blue.png',
			alt: 'Nästa'
		}));

		this.monthSelect = $('<select>');
		this.populateMonthSelect();
		this.monthSelect.change(function (e) {
			(this.options.format == 'US') ? self.changeMonth(new Month(Date.parseUSDate(self.monthSelect.val()))) : self.changeMonth(new Month(Date.parseISODate(self.monthSelect.val())));
		});
		this.navContainer.append(this.goBack, this.monthSelect, this.goForward);

		// Close datepicker when click occurs outside of it
		$(document).click(function (e) {
			if (!(e.target == self.options.target[0] || $(e.target).closest('.date-picker').length)) {
				self.hide();
			}
		});

		// Observe date clicks
		this.tableContainer.click(function (e) {
			var newDate;
			if (e.target.tagName.toLowerCase() == "a") {
				newDate = (opt.format == 'US') ? Date.parseUSDate(e.target.title) : Date.parseISODate(e.target.title);
				self.setDate(newDate);
				self.updateView();
				self.hide();
				e.preventDefault();
			}

		});

		// Set month
		this.changeMonth(this.getStartMonth(this.options.date));
	},
	populateMonthSelect: function () {
		var opt = this.options;
		var month = opt.dateRange.start;
		var endMonth = opt.dateRange.end;
		while (month.compareTo(endMonth) <= 0) {
			this.monthSelect.append($('<option>', {
				html: '{month} {year}'.supplant({month: month.getName(), year: month.getYear()}),
				value: (opt.format == 'US') ? month.toUSDateString() : month.toISODateString()
			}));
			month = month.getNextMonth();
		}
	},
	getStartMonth: function (date) {
		// Returns the supplied dates month if it has selectable dates, otherwise returns the first one that does
		var selDates = this.options.selectableDates;
		var regex = (this.options.format == 'US') ? new RegExp('^' + date.getMonth() + '/01/' + date.getYear()) : new RegExp('^' + date.getYear() + '-' + date.getMonth() + '-01');

		if (selDates.length && selDates.some(function (d) { return regex.test(d); })) {
			return new Month(date);
		} else {
			return new Month();
		}
	},
	setDate: function (newDate) {
		newDate = (this.options.format == 'US') ? Date.parseUSDate(newDate.toUSDateString()) : Date.parseISODate(newDate.toISODateString());
		if (!this.activeDate || this.activeDate && newDate.getMonth() != this.activeDate.getMonth() || newDate.getYear() != this.activeDate.getYear()) {
			this.activeDate = newDate;
			if (this.containerElement) {
				this.changeMonth(new Month(newDate)); // changeMonth updates the view
			}
		} else {
			this.activeDate = newDate;
		}
		// Update target value, if any
		if (this.options.target) {
			this.options.target.val((this.options.format == 'US') ? this.activeDate.toUSDateString() : this.activeDate.toISODateString());
		}
	},
	changeMonth: function (month) {
		this.currentMonth = month;
		this.monthSelect.val((this.options.format == 'US') ? month.toUSDateString() : month.toISODateString());
		this.updateView();
	},
	showNextMonth: function () {
		this.changeMonth(this.currentMonth.getNextMonth());
	},
	showLastMonth: function () {
		this.changeMonth(this.currentMonth.getPreviousMonth());
	},
	show: function () {
		var self = this;
		$.each(NetR.DatePicker.datepickers, function (picker) {
			if (this != self) {
				this.hide();
			}
		});
		if (!this.containerElement) {
			this.setup();
		}
		this.containerElement.show();
	},
	hide: function () {
		if (this.containerElement) {
			this.containerElement.fadeOut();
		}
	},
	updatePrevNextLinks: function () {
		var dateRange = this.options.dateRange;
		var prevMonth = this.currentMonth.firstDay.getPreviousDay();
		var nextMonth = this.currentMonth.lastDay.getNextDay();

		if (dateRange.start && dateRange.start.isTheSameAs(this.currentMonth)) {
			this.goBack.addClass(this.disabledButtonClass);
			this.goBackDisabled = true;
		} else {
			this.goBack.removeClass(this.disabledButtonClass);
			this.goBackDisabled = false;
		}
		if (dateRange.end && dateRange.end.isTheSameAs(this.currentMonth)) {
			this.goForward.addClass(this.disabledButtonClass);
			this.goForwardDisabled = true;
		} else {
			this.goForward.removeClass(this.disabledButtonClass);
			this.goForwardDisabled = false;
		}

		this.goBack.attr('title', '{m} {y}'.supplant({m:prevMonth.getMonth(), y:prevMonth.getFullYear()}));
		this.goForward.attr('title', '{m} {y}'.supplant({m:nextMonth.getMonth(), y:nextMonth.getFullYear()}));
	},
	isSelectableDate: function (date) {
		// Determine if the date should be selectable
		if (this.options.selectableDates.length) {
			return this.options.selectableDates.contains((this.options.format == 'US') ? date.toUSDateString() : date.toISODateString());
		}
		// If no selectable dates are set, all dates should be selectable
		return true;
	},
	renderMonthTable: function () {
		var d,
		    str   = "",
		    tdClass = [],
		    start = this.currentMonth.firstDay.getFirstDayOfWeek(),
		    stop  = this.currentMonth.lastDay.getLastDayOfWeek();

		str += "<table>";

		// Render table head
		str += '<thead><tr>';

		// Add week number column header
		// if (this.options.weekNumbers) {
		// 	str += '<th title="Vecka">v.</th>';
		// }

		// Render column headers
		for (d = 0; d < 7; d++) {
			str += '<th title="' + Date.i18n.dayNames[d] + '">' + Date.i18n.dayNamesMin[d] + '</th>';
		}
		str += '</tr></thead>';

		// Render table body
		str += '<tbody>';
		d = start;

		// Week loop
		// Always render six full weeks so that table height stays the same
		for (w = 0; w < 6; w++) {

			str += '<tr>';

			// Add week number column
			// if (this.options.weekNumbers) {
			// 	str += '<td class="w" title="Vecka ">v' + d.getWeek() + '</td>';
			// }

			// Weekday loop
			for (wd = 0; wd < 7; wd++) {
				// Does this date belong to another month than the current one?
				if (d.getMonth() != this.currentMonth.firstDay.getMonth()) {
					tdClass.push('other-month');
				}
				// Is this date the chosen date?
				if (this.activeDate && d.isTheSameAs(this.activeDate)) {
					tdClass.push('active');
				}
				// Is this date today?
				if (d.isToday()) {
					tdClass.push('today');
				}
				str += '<td' + (tdClass.length ? (' class="' + tdClass.join(' ') + '"') : '') + '>';
				// Should this date be selectable?
				if (this.isSelectableDate(d) && d.getMonth() == this.currentMonth.firstDay.getMonth()) {
					if (this.options.format == 'US') {
						str += '<a href="#" title="' + d.toUSDateString() + '">';
					} else {
						str += '<a href="#" title="' + d.toISODateString() + '">';
					}
					str += d.getDate();
					str += '</a>';
				} else {
					str += '<span>' + d.getDate() + '</span>';
				}
				str += '</td>';
				// Reset td class
				tdClass = [];
				d = d.getNextDay();
			}
			str += '</tr>';
		}
		str += '</tbody>';
		str += "</table>";
		return str;
	},
	updateView: function () {
		this.tableContainer.html(this.renderMonthTable());
		this.updatePrevNextLinks();
	}
};

NetR.DatePicker.defaultOptions = {
	target: null,
	date: new Date(),
	format: 'ISO',
	weekNumbers: true,
	// Array of dates that the user can choose from
	selectableDates: [],
	dateRange: {
		start: new Month().getPreviousMonth().getPreviousMonth(),
		end: new Month(new Date(new Date().getTime() + Date.milliseconds.YEAR))
	},
	// Date format for previous and next link titles and month select options
	navigationDateFormat: '%B %Y',
	// Date format for output to target element
	outputDateFormat: '%Y-%m-%d'
};

$(document).ready(function() {
    $('input[name$="DateIn"]').each(function () {
		new NetR.DatePicker({
			target: $(this),
			format: 'ISO',
			date: Date.parseUSDate($(this).val())
		});
	});
    $('input[name$="DateOut"]').each(function () {
		new NetR.DatePicker({
		    target: $(this),
		    format: 'ISO',
		    date: Date.parseUSDate($(this).val())
		});
	});
});
