// General functions

var isMouseDown = false;

//function getWeek(d){
	//var d = new Date();

//	var onejan = new Date(d.getFullYear(),0,1);
//	return Math.ceil((((d - onejan) / 86400000) + onejan.getDay()+1)/7);
	
	//var onejan = new Date(d.getFullYear(), 0, 1);
	//var week = Math.ceil((((d - onejan - 86400000) / 86400000) + onejan.getDay()) / 7);
	//return week > 52 ? week - 52 : week;
//}

function getWeek(d){
	/*getWeek() was developed by Nick Baicoianu at MeanFreePath: http://www.meanfreepath.com */

	dowOffset = typeof(dowOffset) == 'int' ? dowOffset : 0; //default dowOffset to zero
	var newYear = new Date(d.getFullYear(),0,1);
	var day = newYear.getDay() - dowOffset; //the day of week the year begins on
	day = (day >= 0 ? day : day + 7);
	var daynum = Math.floor((d.getTime() - newYear.getTime() -
	(d.getTimezoneOffset()-newYear.getTimezoneOffset())*60000)/86400000) + 1;
	var weeknum;

	//if the year starts before the middle of a week
	if(day < 4) {
		weeknum = Math.floor((daynum+day-1)/7) + 1;
		if(weeknum > 52) {
			nYear = new Date(d.getFullYear() + 1,0,1);
			nday = nYear.getDay() - dowOffset;
			nday = nday >= 0 ? nday : nday + 7;
			/*if the next year starts before the middle of
			the week, it is week #1 of that year*/
			weeknum = nday < 4 ? 1 : 53;
		}
	}
	else {
		weeknum = Math.floor((daynum+day-1)/7);
	}
	return weeknum;
}

function getMonday(d){
	
	var day = new Date(d.getFullYear(), d.getMonth(), d.getDate());
	
	while(day.getDay() != 1)
	{
		day.setDate(day.getDate() - 1);
	}
	
	return Math.round(day.getTime()/1000.0);
}

// Converts unix timestamp to normal date
function displayDate(d){
	new_d = new Date(d*1000);
	
	year = new_d.getFullYear();
	month = new_d.getMonth()+1; // january = 0, december = 12

	if(month.toString().length == 1)
	{
		month = '0' + month;
	}
	
	day = new_d.getDate();
	
	if(day.toString().length == 1)
	{
		day = '0' + day;
	}
	
	dateymd = new_d.getFullYear() + '-' + month + '-' + day;
	
	return dateymd;
}

// Converts a time in seconds to hours and minutes
function displayTime(t){
	var time = new Date(1970,0,1);
	time.setSeconds(t);
	var s = time.toTimeString().substr(0,8);
	if(t > 86399)
	s = Math.floor((time - Date.parse("1/1/70")) / 3600000) + s.substr(2);
	return s.substr(0,5);
}

// Return greatest common divisor

function gcd(o){
	if(!o.length)
		return 0;
	for(var r, a, i = o.length - 1, b = o[i]; i;)
		for(a = o[--i]; r = a % b; a = b, b = r);
	return b;
};

// Return index in Array based on value
function getArrayIndex(arr, val){
	for (i = 0; i < arr.length; i++) {
		if (arr[i] == val)
		{
			return i;
		}
	}
}

// Find the position of the object and return x and y
function findPos(obj) {
	var curleft = curtop = 0;
	if (obj.offsetParent) {
		do {
			curleft += obj.offsetLeft;
			curtop += obj.offsetTop;
		} while (obj = obj.offsetParent);
	}
	return [curleft,curtop];
}

// Extensions
function dateAddExtention(p_Interval, p_Number){

	var thing = new String();
	
	//in the spirt of VB we'll make this function non-case sensitive
	//and convert the charcters for the coder.
	p_Interval = p_Interval.toLowerCase();
	
	if(isNaN(p_Number)){
		//Only accpets numbers 
		//throws an error so that the coder can see why he effed up	
		throw "The second parameter must be a number. \n You passed: " + p_Number;
		return false;
	}

	p_Number = new Number(p_Number);
	switch(p_Interval.toLowerCase()){
		case "yyyy": {		// year
			this.setFullYear(this.getFullYear() + p_Number);
			break;
		}
		case "q": {		// quarter
			this.setMonth(this.getMonth() + (p_Number*3));
			break;
		}
		case "m": {		// month
			this.setMonth(this.getMonth() + p_Number);
			break;
		}
		case "y":		// day of year
		case "d":		// day
		case "w": {		// weekday
			this.setDate(this.getDate() + p_Number);
			break;
		}
		case "ww": {	// week of year
			this.setDate(this.getDate() + (p_Number*7));
			break;
		}
		case "h": {		// hour
			this.setHours(this.getHours() + p_Number);
			break;
		}
		case "n": {		// minute
			this.setMinutes(this.getMinutes() + p_Number);
			break;
		}
		case "s": {		// second
			this.setSeconds(this.getSeconds() + p_Number);
			break;
		}
		case "ms": {		// second
			this.setMilliseconds(this.getMilliseconds() + p_Number);
			break;
		}
		default: {
		
			//throws an error so that the coder can see why he effed up and
			//a list of elegible letters.
			throw	"The first parameter must be a string from this list: \n" +
					"yyyy, q, m, y, d, w, ww, h, n, s, or ms.  You passed: " + p_Interval;
			return false;
		}
	}
	return this;
}

Date.prototype.dateAdd = dateAddExtention; 

// Check if a value exists in an array
Array.prototype.inArray = function (value) {
	var i;
	for (i=0; i < this.length; i++) {
		if (this[i] === value) {
			return true;
		}
	}
	return false;
};

// General schema functions

function getDayId(id) {
	id_array = id.split('_');
	
	return id_array[0]; 
}

function getTimeId(id) {
	id_array = id.split('_');
	
	if(id_array.length > 1)
	{
		return id_array[1];
	}
}

function getBookingId(id) {

	id_array = id.split('_');
	
	if(id_array.length > 2)
	{
		return id_array[2];
	}
}

// Change class on the cell
function changeClass(id, type_id){

	$('#' + id).removeClass().addClass(arrayType[type_id]);
	$('#' + id).css('background-color', arrayTypeColors[type_id]);

}

// Specific schema functions

// Get user preferences
function getPreferences() {

	var url = getPreferencesURL();

	$.ajax({
	type: "GET",
	url: url,
	dataType: "xml",
	error: function(XMLHttpRequest, textStatus, errorThrown) {
		  alert(XMLHttpRequest);
		  alert(textStatus);
		  alert(errorThrown);
		},
	success: function(xml) {
	
			$(xml).find('user').each(function(){
				oPreferences.workday_start = parseFloat($(this).find('workday_start').text());
				oPreferences.workday_end = parseFloat($(this).find('workday_end').text());
				oPreferences.workday_interval = parseFloat($(this).find('workday_interval').text());
				oPreferences.workday_exclude = parseInt($(this).find('workday_exclude').text());
				
				// Make empty schedule
				makeSchedule(oSchedule.week, oSchedule.monday);

			});
		
		}
	});
	
}

function initiateSchedule(week, monday, user, jobbid, userid, mode) {

	oSchedule.week = week;
	oSchedule.monday = monday;
	oSchedule.jobbid = jobbid;
	oSchedule.user = user;
	oSchedule.userid = userid;

	if(mode == undefined)
	{
		oSchedule.mode = 'draw';
	}
	else
	{
		oSchedule.mode = mode;
	}
	
	// Div_kalender is filled by the calender, the header contains the week-selector and information square
	// Div_kalender_popup contains the popup messages
	
	var html = getHeaderDiv();
	html += '<div id="div_kalender_popup"><input type="button" id="btn_popup_close" onClick="$(' + String.fromCharCode(39) + '#div_kalender_popup' + String.fromCharCode(39) + ').fadeOut(500);$(' + String.fromCharCode(39) + '#div_kalender_popup_text' + String.fromCharCode(39) + ').html(' + String.fromCharCode(39) + String.fromCharCode(39) + ');" value="Stäng fönstret" class="form_border"><div id="div_kalender_popup_header"></div><div id="div_kalender_popup_info"></div><div id="div_kalender_popup_text"></div></div>';
	html += '<div id="div_kalender"><h2>Laddar schema...</h2></div>';

	$('#btn_popup_close')
	.click(function(){
		$('#div_kalender_popup').fadeOut(500);
	});

	$('div#div_result').html(html);

	// Week select

	var html_select = '<p><select name="kalender_valjvecka" id="kalender_valjvecka" class="form_border">'; 

	
	//html_select += '<option value="' + getWeek(new Date()) + '¤' + getMonday(new Date()) + '">' + 'v. ' + getWeek(new Date()) + ', ' + displayDate(getMonday(new Date())) + ' till ' + displayDate(parseFloat(getMonday(new Date()))+6*86400) +'</option>';
	
	d = new Date();
	d = d.dateAdd('d', -4*7);
	
	for(i=1; i<12; i++)
	{
		d = d.dateAdd('d', 7);

		week = getWeek(d);
		monday = getMonday(d);
		sunday = monday+6*86400;
		
		html_select += '<option value="' + week + '¤' + monday + '">' + 'v. ' + week + ', ' + displayDate(monday) + ' till ' + displayDate(sunday) + '</option>';
	}
	
	html_select += '</select></p>';
	
	// Preferences select
	
	if(oSchedule.user == 'admin_konsult' || oSchedule.user == 'admin_foretag')
	{
		html_select += 'Välj intervall: <select name="kalender_valjintervall" id="kalender_valjintervall" class="form_border">';
		html_select += '<option value="1">Timme</option><option value="0.5">Halvtimme</option><option value="0.25">Kvart</option></select>';
	}
	
	$(html_select).appendTo('div#div_kalender_header');
	
	var kalender_valjvecka = document.getElementById('kalender_valjvecka');
	
	var kalender_value = oSchedule.week + '¤' + oSchedule.monday;
	
	for(i=0; i<kalender_valjvecka.options.length; i++)
	{
		if(kalender_valjvecka.options[i].value == kalender_value)
		{
			kalender_valjvecka.selectedIndex = i;
		}	
	}

	$('select#kalender_valjvecka')
	.change(function() {
		index = this.selectedIndex;
		value = this.options[index].value;
		value_array = value.split('¤');
		
		week = value_array[0];
		monday = value_array[1];
		
		d = new Date();

		if(oSchedule.save==1 && oSchedule.monday>=getMonday(d))
		{
			if(confirm("Du har inte sparat dina ändringar. Vill du gå vidare utan att spara?"))
			{
				makeSchedule(week, monday);
				oSchedule.save = 0;
			}
			else
			{
				// If cancel, show the previous option (the current week)
				for(i=0; i<this.options.length; i++)
				{
					value = this.options[i].value;
					value_array = value.split('¤');	
					if(value_array[0] == oSchedule.week)
					{
						this.selectedIndex = i;
					}	
				}
			}
		}
		else
		{
			makeSchedule(week, monday);
			oSchedule.save = 0;
		}
	});

	if(oSchedule.user == 'admin_konsult' || oSchedule.user == 'admin_foretag')
	{
		$('select#kalender_valjintervall').change(function() {
			var kalender_valjintervall = document.getElementById('kalender_valjintervall');

			oPreferences.workday_interval = kalender_valjintervall.options[kalender_valjintervall.selectedIndex].value;
			makeSchedule(week, monday);
			oSchedule.save = 0;
		});
	}
	
	// Set preferences
	getPreferences();

}

// Makes the schedule object

function makeSchedule(week, monday){

	oSchedule.week = week;
	oSchedule.monday = monday;

	oBarray = new Array();

	var t=0;

	for(d=0; d<7; d++)
	{
		// create object to hold bookings later on (decides which to ignore and which to keep)
		oCheckBookingArray[d] = new Array();

		// create object to hold date values
		oSarray[d] = new oDay();
		oSarray[d].date = parseFloat(monday)+parseFloat(d*86400);
		oSarray[d].date_ymd = displayDate(oSarray[d].date);
		oSarray[d].colspan = 1;
		oSarray[d].nrofbookings = 1;
		
		oSarray[d].block_type_id = new Array(1,1,1,1);
		oSarray[d].block_start = new Array(8,8,13,18);
		oSarray[d].block_end = new Array(13,22,18,22);
		oSarray[d].save = 0;
		
		for(t=oPreferences.workday_start; t<oPreferences.workday_end; t=t+parseFloat(oPreferences.workday_interval))
		{
			// calculate time to suit an array
			var c = t/(oPreferences.workday_interval);

			// create object to hold time values
			// the bookings are in a new array which is contained by oSarray[d][c]
			// c still is the time array containing the time_from and time_to values
			// type, total duration, etc. of booking is found in oBooking

			oSarray[d][c] = new oTime;
			oSarray[d][c].time_from = t*3600;
			oSarray[d][c].time_from_text = displayTime(t*3600);
			oSarray[d][c].time_to = t*3600+oPreferences.workday_interval*3600;
			oSarray[d][c].time_to_text = displayTime(t*3600+oPreferences.workday_interval*3600);
			
			// oBookings contains each booking type and descr, while the time is in oTime
			oSarray[d][c][0] = new oBooking;
			oSarray[d][c][0].type = arrayType[1]; // default nonbookable
			oSarray[d][c][0].type_id = '1';
			oSarray[d][c][0].duration = 0;
			oSarray[d][c][0].descr = '';
			
			oSarray[d][c].nrofbookings = 1;
		}	
	}
	
	// Get xml containing the bookings, while sending input parameters dates to and from.
	sunday = parseFloat(monday)+parseFloat((d-1)*86400);
	var requrl = getBookingURL(monday, sunday, oSchedule.jobbid);

	$.ajax({
	type: "GET",
	url: requrl,
	dataType: (jQuery.browser.msie) ? "text" : "xml",
	error: function(XMLHttpRequest, textStatus, errorThrown) {
		  alert(XMLHttpRequest);
		  alert(textStatus);
		  alert(errorThrown);
		},
	success: function(xmlData) {

		var xml;

		if (typeof xmlData == 'string')
		{
			xml = new ActiveXObject('Microsoft.XMLDOM');
			xml.async = false;
			xml.loadXML( xmlData);
		}
		else
		{
			xml = xmlData;
		} 

		if(oSchedule.mode != 'booking')
		{
			// Get the bookings (xml) and put them in the schedule object
			$(xml).find('booking').each(function(){

					var date = $(this).find('date').text();
					var date_epoch = $(this).find('date_epoch').text();
					var time_start = parseFloat($(this).find('time_start').text());
					var time_end = parseFloat($(this).find('time_end').text());
					var typeid = $(this).find('typeid').text();
					var descr = $(this).find('description').text();
					var jobbid = $(this).find('jobbid').text();
					var jobbnamn = $(this).find('jobbnamn').text();
					var scheduleid = parseInt($(this).find('scheduleid').text());
					var status = $(this).find('status').text();
					var mappingid = parseInt($(this).find('mappingid').text());
					var antal = parseInt($(this).find('antal').text());
					var antalreserver = parseInt($(this).find('antalreserver').text());
					var platser = parseInt($(this).find('platser').text());

					// Get weekday of booking
					var wd = new Date(date_epoch*1000).getDay()-1;
					if(wd==-1)
					{
						wd = 6;
					}

					// Loop through the times of the day to see where the booking fits in
					for(t=oPreferences.workday_start; t<oPreferences.workday_end; t=t+parseFloat(oPreferences.workday_interval))
					{
						var c = t/(oPreferences.workday_interval);
						var c_next = (t+parseFloat(oPreferences.workday_interval))/oPreferences.workday_interval;

						if(oSarray[wd][c_next]!=undefined)
						{

							next_time_start = oSarray[wd][c_next].time_from;
						}
						else
						{
							next_time_start = time_start+1;
						}

						// If time_from is between time_start and time_end, the booking is put in this cell, 
						// or if time_start is earlier than next_time_start (i.e. when 8:15 > 8:00, it is still put in the 8:00- cell)
						// either by creating a new cell (if there already is a type 3 booking or higher)

						if((oSarray[wd][c].time_from>=time_start || 
							time_start < next_time_start) && 
							oSarray[wd][c].time_from<time_end)
						{
						
							// Default, add booking
							addschedule=1;

							// Check if there isn't an overlapping booking the user has subscribed to
							// Valid for bookings the user hasn't subscribed to yet
							for(x=0; x<oCheckBookingArray[wd].length; x++)
							{
								if(status != 'Anmäld' && typeid >=3 &&
									((time_start/3600 <= oCheckBookingArray[wd][x].time_from_t && time_end/3600 > oCheckBookingArray[wd][x].time_from_t) ||
									(time_start/3600 < oCheckBookingArray[wd][x].time_to_t && time_end/3600 >= oCheckBookingArray[wd][x].time_to_t) ||
									(time_start/3600 >= oCheckBookingArray[wd][x].time_from_t && time_end/3600 <= oCheckBookingArray[wd][x].time_to_t))
								)
								{
									addschedule = 0;
								}

							}
															
							size = oSarray[wd][c].nrofbookings;
								
							// If there is a booking with type_id < 3 in the current cell, overwrite
							if(oSarray[wd][c][size-1].type_id<3 && addschedule==1)
							{
								i=size-1;
							}
							else if(typeid>=3 && addschedule==1)
							{
								// If type is not 3, create a new booking object
								// if the booking has a type_id >= 3
								i=size;

								oSarray[wd][c][i] = new oBooking;
								size = i+1;
							}
							// Ignore bookings with type_id < 3 where there already is a booking in previous cell
							else
							{
								addschedule = 0;
							}
								
							if(addschedule == 1)
							{
								// Fill information about the booking
								if(!oBarray[scheduleid])
								{
									oBarray[scheduleid] = new oBookingInfo;
									oBarray[scheduleid].type_id = typeid;
									oBarray[scheduleid].time_from = displayTime(time_start);
									oBarray[scheduleid].time_to = displayTime(time_end);
									// Changed from taking time_from_t to oSarray[wd][c].time_from
									oBarray[scheduleid].time_from_t = t;
									oBarray[scheduleid].time_to_t = time_end/3600;
									oBarray[scheduleid].duration = time_end - time_start;
									oBarray[scheduleid].descr = descr;
									oBarray[scheduleid].jobbnamn = jobbnamn;
									oBarray[scheduleid].jobbid = jobbid;
									oBarray[scheduleid].status = status;
									oBarray[scheduleid].mappingid = mappingid;
									oBarray[scheduleid].antal = antal;
									oBarray[scheduleid].antalreserver = antalreserver;
									oBarray[scheduleid].platser = platser;

									// Save all bookings the user has subscribed to, used in the check above
									// This works, since all subscribed bookings are gathered from the database first
									
									if(status == 'Anmäld')
									{
										x = oCheckBookingArray[wd].length;
										oCheckBookingArray[wd][x] = new oBookingInfo;
										oCheckBookingArray[wd][x].scheduleid = scheduleid;
										oCheckBookingArray[wd][x].time_from_t = c;
										oCheckBookingArray[wd][x].time_to_t = time_end/3600;
									}
								}

								// Set the reference to the booking id, set the new nrofbookings
								oSarray[wd][c][i].type_id = typeid;
								oSarray[wd][c][i].type = arrayType[typeid];
								oSarray[wd][c][i].history_type_id = typeid;
								oSarray[wd][c][i].scheduleid = scheduleid;
								oSarray[wd][c].nrofbookings = size;

								// Calculate the new colspan of the day.
								oSarray[wd].nrofbookings = Math.max(parseFloat(oSarray[wd].nrofbookings), parseFloat(size));
								
								oSarray[wd].colspan = oSarray[wd].nrofbookings;

								for(g=1; g<oSarray[wd].nrofbookings; g++)
								{
									oSarray[wd].colspan=oSarray[wd].colspan*g/gcd([oSarray[wd].colspan, g]);
								}
								
							}
						}
					}
				});
			}
			
			// make the schedule appear on screen

			drawSchedule();
		}
	});
}

// Draw schedule object

function drawSchedule() {
	
	d = new Date();
	
	//var html = '<table id="kalender" cellpadding="0" cellspacing="0"><tr><td><img src="../bilder/ikon_soln_16x16.png" onClick="changeBlockType(7,0);" class="img_link"><img src="../bilder/ikon_sol_16x16.png" onClick="changeBlockType(7 ,1);" class="img_link"><img src="../bilder/ikon_soln_16x16.png" onClick="changeBlockType(7 ,2);" class="img_link"><img src="../bilder/ikon_mane_16x16.png" onClick="changeBlockType(7 ,3);" class="img_link"><br>Hela veckan</td>';
	var html = '<table id="kalender" cellpadding="0" cellspacing="0"><tr><td>';

	if(oSchedule.monday>=getMonday(d))
	{

		if(oSchedule.user != 'foretag')
		{
			html += '<input type="button" id="btn_kalender_spara" name="btn_kalender_spara" onClick="putSchedule();" class="form_disabled" disabled value="Spara"><br>';
		}
		if(oSchedule.user == 'admin_foretag')
		{
			if(oSchedule.mode == 'draw')
			{
				//html += '<input type="button" id="btn_kalender_boka" name="btn_kalender_boka" onClick="initiateSchedule(oSchedule.week, oSchedule.monday, oSchedule.user, oSchedule.jobbid, oSchedule.userid, ' + String.fromCharCode(39) + 'booking' + String.fromCharCode(39) + ');" value="Ny bokning">';
				html += '<input type="button" id="btn_kalender_boka" name="btn_kalender_boka" onClick="oSchedule.mode=' + String.fromCharCode(39) + 'booking' + String.fromCharCode(39) + '; makeSchedule(oSchedule.week, oSchedule.monday);" value="Ny bokning">';
			}
			else
			{
				//html += '<input type="button" id="btn_kalender_boka" name="btn_kalender_boka" onClick="initiateSchedule(oSchedule.week, oSchedule.monday, oSchedule.user, oSchedule.jobbid, oSchedule.userid, ' + String.fromCharCode(39) + 'draw' + String.fromCharCode(39) + ');" value="Visa tider">';
				html += '<input type="button" id="btn_kalender_boka" name="btn_kalender_boka" onClick="oSchedule.mode=' + String.fromCharCode(39) + 'draw' + String.fromCharCode(39) + '; makeSchedule(oSchedule.week, oSchedule.monday);" value="Visa tider">';
			}
		}
	}

	html += '</td>';

	// Set the header	
	for(d=0; d<7; d++)
	{
	
		html += '<td colspan=' + oSarray[d].colspan + ' class="meny">';
		html += '<img src="../bilder/ikon_soln_16x16.png" onClick="changeBlockType(' + d + ',0);" class="img_link"><img src="../bilder/ikon_sol_16x16.png" onClick="changeBlockType(' + d + ',1);" class="img_link"><img src="../bilder/ikon_soln_16x16.png" onClick="changeBlockType(' + d + ',2);" class="img_link"><img src="../bilder/ikon_mane_16x16.png" onClick="changeBlockType(' + d + ',3);" class="img_link"><br>';
		html += arrayDays[new Date(oSarray[d].date*1000).getDay()] + '<br>' + displayDate(oSarray[d].date) + '</td>';	

		//html += '<td colspan=' + oSarray[d].colspan + ' class="meny"><img src="../bilder/ikon_soln_16x16.png" onClick="changeBlockType(' + d + ',0);" class="img_link"><img src="../bilder/ikon_sol_16x16.png" onClick="changeBlockType(' + d + ',1);" class="img_link"><img src="../bilder/ikon_soln_16x16.png" onClick="changeBlockType(' + d + ',2);" class="img_link"><img src="../bilder/ikon_mane_16x16.png" onClick="changeBlockType(' + d + ',3);" class="img_link"><br>' + arrayDays[new Date(oSarray[d].date*1000).getDay()] + '<br>' + displayDate(oSarray[d].date) + '</td>';
	}
	
	html += '</tr>';
	
	// Loop through the schedule object
	
	for(t=oPreferences.workday_start; t<oPreferences.workday_end; t=t+parseFloat(oPreferences.workday_interval))
	{
		var c = t/(oPreferences.workday_interval);
	
		html += '<tr><td class="time">' + displayTime(t*3600) + '</td>';
		for(d=0; d<7; d++)
		{
			// Types blank, nonbookable, bookable and booked
			
			for(i=0; i<oSarray[d][c].nrofbookings; i++)
			{
				colspan = parseFloat(oSarray[d].colspan)/Math.max(parseFloat(oSarray[d][c].nrofbookings), 1);
							
				html += '<td colspan=' + colspan + ' id='+ d + '_' + c + '_' + i + ' class="' + oSarray[d][c][i].type + '">'; // width="' + colspan / oSarray[d].colspan * 100/8 + '%">'; // 8 columns, 100% max, this td:s colspan / total colspan
				
				if(oSarray[d][c].nrofbookings==1)
				{
					html += oSarray[d][c].time_from_text + ' - ' + oSarray[d][c].time_to_text;
				}
				else
				{
					html += '&nbsp;';
				}
				
				html += '</td>';
			}
		}
		html += '</tr>';
	}
	
	html += '</html>';
	
	$('div#div_kalender').html(html);
		
	$('.blank')
	.css('background-color', 'white')
	.hover(function() {
		$(this).css('background-color', '#ffcccc').css('color', '#999999');
		}, function() {
		 	$(this).css('background-color', 'white').css('color', 'white');
	}).each(function(){ 
		$(this).click(function() { 
			changeType(this.id);
		})
	});
	
	$('.nonbookable')
	.css('background-color', '#eeffee')
	.hover(function() {
			$(this).css('background-color', '#ffcccc').css('color', '#999999');
			if(isMouseDown == true)
			{
				changeType(this.id);
			}
		}, function() {
			 	$(this).css('background-color', '#eeffee').css('color', 'white');
	}).each(function(){ 
		$(this).mousedown(function(){
			isMouseDown = true;
			changeType(this.id);
		}).mouseup(function(){
			isMouseDown = false;
		});
	})

	$('.bookable')
	.css('background-color', '#eeff88')
	.hover(function() {
			$(this).css('background-color', '#ffcccc').css('color', '#999999');
			if(isMouseDown == true)
			{
				changeType(this.id);
			}
		}, function() {
			 	$(this).css('background-color', '#eeff88').css('color', 'white');
	}).each(function(){ 
		$(this).mousedown(function(){
			isMouseDown = true;
			changeType(this.id);
		}).mouseup(function(){
			isMouseDown = false;
		});
	});

	$('.booked')
	.css('background-color', '#7ed959')
	.hover(function() {

		highlightMultipleCells(this.id, '#ffcccc', '#999999');
	
	}, function() {
		
		highlightMultipleCells(this.id, '#7ed959', '#ffffff');
	
	}).each(function(){ 
		$(this).click(function(e) { 

			var html_popup = getPopUp(this.id, 'booked', e.pageX, e.pageY);
			
			$('#div_kalender_popup_info').html(html_popup);

		})
	});
	
	$('.subscribe')
	.css('background-color', '#bbbbff')
	.hover(function() {
		highlightMultipleCells(this.id, '#ffcccc', '#999999');
			
	}, function() {
	
		highlightMultipleCells(this.id, '#bbbbff', '#ffffff');
	
	}).each(function(){ 

		$(this).click(function(e) { 

			var html_popup = getPopUp(this.id, 'subscribe', e.pageX, e.pageY);
			
			$('#div_kalender_popup_info').html(html_popup);

		})

	});

	$('.full')
	.css('background-color', '#ffaa99')
	.hover(function() {

		highlightMultipleCells(this.id, '#ffcccc');
			
	}, function() {
	
		highlightMultipleCells(this.id, '#ffaa99', '#ffffff');
	
	}).each(function(){ 
		$(this).click(function(e) { 

			var html_popup = getPopUp(this.id, 'full', e.pageX, e.pageY);
			
			$('#div_kalender_popup_info').html(html_popup);
		})
	});

	$('.reserv')
	.css('background-color', '#aaff88')
	.hover(function() {
		highlightMultipleCells(this.id, '#ffcccc', '#999999');
			
	}, function() {
	
		highlightMultipleCells(this.id, '#aaff88', '#ffffff');
	
	}).each(function(){ 

		$(this).click(function(e) { 

			var html_popup = getPopUp(this.id, 'booked', e.pageX, e.pageY);
			
			$('#div_kalender_popup_info').html(html_popup);

		})

	});
	
	// Disable ordinary mouse select function
	var kalender = document.getElementById('kalender');
	
	// FF
	kalender.onmousedown=new Function ("return false");
	kalender.onmouseup=new Function ("return true");
	
	// IE
	kalender.onselectstart = function () { return false; };
}

// Make XML, in order to put saved schedule in database
function putSchedule() {

	jobbid = oSchedule.jobbid;
	
	changeAttribute('#btn_popup_close', 'disabled', 'disabled');
	$('#btn_popup_close').removeClass().addClass('form_disabled');

	obj = document.getElementById("btn_kalender_spara");

	xy = findPos(obj);

	if($("#txta_booking_beskrivning").length > 0 && $("#sel_booking_antal").length > 0)
	{
		var descr = $("#txta_booking_beskrivning").val();
		var antal = $("#sel_booking_antal").val();
	}
	else
	{
		var descr = '';
		var antal = '';
	}
	
	if($("#txt_booking_aterkommande").length > 0)
	{
		var aterkommande = $("#txt_booking_aterkommande").val();
	}
	else
	{
		var aterkommande = '';
	}
	
	if($("#cb_booking_lopande").length > 0)
	{
		var lopande = $("#cb_booking_lopande:checked").val();
	}
	else
	{
		var lopande = '';
	}
	
	if($("#cb_booking_koppla").length > 0)
	{
		var koppla = $("#cb_booking_koppla:checked").val();
	}
	else
	{
		var koppla = '';
	}

	var height = $('#div_kalender_popup').height();
	var width = $('#div_kalender_popup').width();
	//calculating offset for displaying popup message
	leftVal=xy[0]+"px";
	topVal=xy[1]-height+"px";
	//show the popup message
	$('#div_kalender_popup').css({left:leftVal,top:topVal}).fadeIn(500);

	html_popup = '<center><h3 style="margin-top: 50px;">Vänligen vänta. Dina tider sparas.</h3><p><img src="../bilder/kalender/kalender_ajax-loader.gif"></p></center>';
	$('#div_kalender_popup_info').html(html_popup);

	xml = '<?xml version="1.0" encoding="iso-8859-15"?>';
	xml += '<schedule>';
	
	// Default
	save_type_id = 1;
	
	for(d=0; d<7; d++)
	{
		prev_typeid = 1;
		sent = 1;
		
		for(t=oPreferences.workday_start; t<oPreferences.workday_end; t=t+parseFloat(oPreferences.workday_interval))
		{
			// calculate time to suit an array
			var c = t/(oPreferences.workday_interval);
			
			type_id = oSarray[d][c][0].type_id;
			history_type_id = oSarray[d][c][0].history_type_id;
			
			// Type bookable is always in the first cell
			if(type_id==2)
			{
				// Check in order to save several bookable times after one another in the same <booking>
				if(prev_typeid != type_id)
				{
					// Save last xml booking, if there is one
					if(sent == 0)
					{
						xml += '<booking>';
						xml += '<date>' + oSarray[d].date_ymd + '</date>';
						xml += '<date_epoch>' + oSarray[d].date + '</date_epoch>';
						xml += '<time_start>' + time_from + '</time_start>';
						xml += '<time_end>' + time_to + '</time_end>';
						xml += '<type_id>' + save_type_id + '</type_id>';
						xml += '<descr>' + descr + '</descr>';
						xml += '<antal>' + antal + '</antal>';
						xml += '<jobbid>' + jobbid + '</jobbid>';
						xml += '<aterkom>' + aterkommande + '</aterkom>';
						xml += '<lopande>' + lopande + '</lopande>';
						xml += '<koppla>' + koppla + '</koppla>';
						xml += '</booking>';
						sent = 1;
						oSarray[d].save = 0;
					}
					time_from = oSarray[d][c].time_from;
					time_to = oSarray[d][c].time_to;
					save_type_id = type_id;
					oSarray[d].save = 0;
					sent = 0;
					
				}
				else
				{
					time_to = oSarray[d][c].time_to;
					sent = 0;
				}
				
			}
			else
			{
				// Save booking, since new type_id and last type_id hasn't been sent
				if(sent == 0)
				{
					xml += '<booking>';
					xml += '<date>' + oSarray[d].date_ymd + '</date>';
					xml += '<date_epoch>' + oSarray[d].date + '</date_epoch>';
					xml += '<time_start>' + time_from + '</time_start>';
					xml += '<time_end>' + time_to + '</time_end>';
					xml += '<type_id>' + save_type_id + '</type_id>';
					xml += '<descr>' + descr + '</descr>';
					xml += '<antal>' + antal + '</antal>';
					xml += '<jobbid>' + jobbid + '</jobbid>';
					xml += '<aterkom>' + aterkommande + '</aterkom>';
					xml += '<lopande>' + lopande + '</lopande>';
					xml += '<koppla>' + koppla + '</koppla>';
					xml += '</booking>';
					sent = 1;
				}
			}
			prev_typeid = type_id;
		}
		
		// Save last booking before entering new day
		if(sent == 0 || oSarray[d].save == 1)
		{
			xml += '<booking>';
			xml += '<date>' + oSarray[d].date_ymd + '</date>';
			xml += '<date_epoch>' + oSarray[d].date + '</date_epoch>';
			
			// set time_from and time_to to - only if type is 1 or 2
			if(oSarray[d].save == 1 && save_type_id <3)
			{
				time_from = '-';
				time_to = '-';
			}
			xml += '<time_start>' + time_from + '</time_start>';
			xml += '<time_end>' + time_to + '</time_end>';
			xml += '<type_id>' + save_type_id + '</type_id>';
			xml += '<descr>' + descr + '</descr>';
			xml += '<antal>' + antal + '</antal>';
			xml += '<jobbid></jobbid>';
			xml += '<aterkom>' + aterkommande + '</aterkom>';
			xml += '<lopande>' + lopande + '</lopande>';
			xml += '<koppla>' + koppla + '</koppla>';
			xml += '</booking>';			
		}
		
	}
	
	xml += '</schedule>';

	requrl = getXMLURL(xml);
	
	$.ajax({
	type: "GET",
	url: requrl,
	error: function(XMLHttpRequest, textStatus, errorThrown) {
		  alert(XMLHttpRequest);
		  alert(textStatus);
		  alert(errorThrown);
		},
	success: function(resultSet){

			html_popup = '<center><h3 style="margin-top: 50px;">Tack! Dina tider är nu sparade.</h3><p>Gå vidare till nästa vecka för att fylla i fler tider du kan arbeta.</p></center>';
			
			$('#div_kalender_popup_info').html(html_popup);

			changeAttribute('#btn_popup_close', 'disabled', 'remove');
			$('#btn_popup_close').removeClass().addClass('form_border');
			
			oSchedule.save = 0;
			changeButtonClass();
		}
	
	});	
}

// Functions used for specific users, but disabled for others, why they are still in the general script
function signUp(scheduleid, type) {
	
	requrl = getSignUpURL(scheduleid, type);
		
	$.ajax({
	type: "GET",
	url: requrl,
	error: function(XMLHttpRequest, textStatus, errorThrown) {
		  alert(XMLHttpRequest);
		  alert(textStatus);
		  alert(errorThrown);
		},
	success: function(resultSet){
			// Subscribe as ordinary (=2) or reserv (=1)
			if(resultSet=='1' || resultSet=='2')
			{
				// Refresh schedule
				makeSchedule(oSchedule.week, oSchedule.monday);
				
				if(resultSet=='1')
					var html = '<b>som reserv</b>';
				else
					var html = '';

				$('#div_kalender_popup_info').html('<center><h3>Tack!</h3><p> Du har nu anmält dig ' + html + ' till tiden.</p></center>');
			}
			// Cancel booking
			else if(resultSet=='3')
			{
				makeSchedule(oSchedule.week, oSchedule.monday);
					
				$('#div_kalender_popup_info').html('<center><p>Du har nu avbokat dig på tiden.</p></center>');
			}
			else
			{
				$('#div_kalender_popup_info').html('<center><p>Tiden är tyvärr fullbokad. Du kan anmäla dig som reserv.</p></center>');
			}
		}
	
	});
	
}

function signOff(mappingid) {
	
	requrl = getSignOffURL(mappingid);
		
	$.ajax({
	type: "GET",
	url: requrl,
	error: function(XMLHttpRequest, textStatus, errorThrown) {
		  alert(XMLHttpRequest);
		  alert(textStatus);
		  alert(errorThrown);
		},
	success: function(resultSet){
			if(resultSet=='1')
			{
				// Refresh schedule
				makeSchedule(oSchedule.week, oSchedule.monday);

				$('#div_kalender_popup_info').html('<center><p>Bokningen avanmäld.</p></center>');
			}
			else
			{
				$('#div_kalender_popup_info').html('<center><p>Avanmälningen gick inte igenom.</p></center>');
			}
		}
	
	});
	
}

function removeBooking(scheduleid) {

	requrl = getRemoveBookingURL(scheduleid);
		
	$.ajax({
	type: "GET",
	url: requrl,
	error: function(XMLHttpRequest, textStatus, errorThrown) {
		  alert(XMLHttpRequest);
		  alert(textStatus);
		  alert(errorThrown);
		},
	success: function(resultSet){
			if(resultSet=='1')
			{
				// Refresh schedule
				makeSchedule(oSchedule.week, oSchedule.monday);

				$('#div_kalender_popup_info').html('<center><p>Tiden är borttagen.</p></center>');
			}
			else
			{
				$('#div_kalender_popup_info').html('<center><p>Tiden kunde ej tas bort.</p></center>');
			}
		}
	
	});	

}

// Change type on a whole block
function changeBlockType(day, block) {

	type_id = oSarray[day].block_type_id[block];
	start = oSarray[day].block_start[block];
	end = oSarray[day].block_end[block];
	
	if(type_id == 1)
	{
		type_id_new = 2;
	}
	else if(type_id == 2)
	{
		type_id_new = 1;
	}
	
	oSarray[day].block_type_id[block] = type_id_new;
	
	// Logic where a block has a duration over another block, 1 = day-block (8 - 22)
	if(block == 1)
	{
		oSarray[day].block_type_id[0] = type_id_new;
		oSarray[day].block_type_id[2] = type_id_new;
		oSarray[day].block_type_id[3] = type_id_new;
	}

	for(t=start; t<end; t=t+parseFloat(oPreferences.workday_interval))
	{
		// calculate time to suit an array
		var c = t/(oPreferences.workday_interval);
		
		for(i=0; i<oSarray[day][c].nrofbookings; i++)
		{
			// Do not change type on "real" bookings
			if(oSarray[day][c][i].type_id<3)
			{
				oSarray[day][c][i].type = arrayType[type_id_new];
				oSarray[day][c][i].type_id = type_id_new;

				changeClass(day + '_' + c + '_' + i, type_id_new);
				changeHover(day + '_' + c + '_' + i, type_id_new);
			}
		}
	}

	oSchedule.save = 1;
	oSarray[day].save = 1;
	changeButtonClass();

}

// Change type on just one cell
function changeType(id, force_typeid) {

	//type = ('#' + id).attr("class");

	id_array = id.split('_');
	
	type_id = oSarray[id_array[0]][id_array[1]][id_array[2]].type_id;
	
	type_id++;

	// Change type_id, look at arrayType to see which the new type is. You cannot change type to "booked"
	if(type_id == 3)
	{
		type_id = 1;
	}
	if(force_typeid>0)
	{
		type_id = force_typeid;
	}
	
	// Store the new type and type_id in the schedule object
	oSarray[id_array[0]][id_array[1]][id_array[2]].type = arrayType[type_id];
	oSarray[id_array[0]][id_array[1]][id_array[2]].type_id = type_id;

	changeClass(id, type_id);
	changeHover(id, type_id);
	
	oSchedule.save = 1;
	oSarray[id_array[0]].save = 1;
	changeButtonClass();
	
}

// Change class on the cell
function changeClass(id, type_id){

	$('#' + id).removeClass().addClass(arrayType[type_id]);
	$('#' + id).css('background-color', arrayTypeColors[type_id]);

}

// Change hover-out color
function changeHover(id, type_id){

	if(type_id == 1)
	{
		$('#' + id).hover(function()
		{
			$(this).css('background-color', '#ffcccc');
		}, function()
		{
			 	$(this).css('background-color', '#eeffee');
		});
	}
	if(type_id == 2)
	{
		$('#' + id).hover(function()
		{
			$(this).css('background-color', '#ffcccc');
		}, function()
		{
				$(this).css('background-color', '#eeff88');
		});	
	}

}

function changeButtonClass(){
	// ändra så att när man sparat att knappen
	if(oSchedule.save==0)
	{
		changeAttribute('#btn_kalender_spara', 'disabled', 'disabled');
		$('#btn_kalender_spara').removeClass().addClass('form_disabled');
	}
	else
	{
		changeAttribute('#btn_kalender_spara', 'disabled', 'remove');
		$('#btn_kalender_spara').removeClass().addClass('form_border');
	}
	
}

// Changes background color and font color on cells beloning to the same booking
function highlightMultipleCells(id, bgcolor, fontcolor)
{

	b = getBookingId(id);
	d = getDayId(id);
	c = getTimeId(id);

	type_id = oSarray[d][c][b].type_id;
	scheduleid = oSarray[d][c][b].scheduleid;

	// Highlight cells belonging to the same booking
	for(t=oBarray[scheduleid].time_from_t; t<oBarray[scheduleid].time_to_t; t=t+parseFloat(oPreferences.workday_interval))
	{
		var c = t/(oPreferences.workday_interval);	

		// Booking doesn't necessary have be in the same bookingcolumn as the clicked cell (if split)
		for(i=0; i<oSarray[d][c].nrofbookings;i++)
		{	
			if(oSarray[d][c][i].scheduleid == scheduleid)
			{
				$('#' + d + '_' + c + '_' + i).css('background-color', bgcolor).css('color', fontcolor);
			}
		}
	}
}

// Makes a popup
function getPopUp(id, type, pageX, pageY){

	d = getDayId(id);
	t = getTimeId(id);
	b = getBookingId(id);

	//getting height and width of the message box
	var height = $('#div_kalender_popup').height();
	var width = $('#div_kalender_popup').width();
	//calculating offset for displaying popup message
	leftVal=Math.max(pageX-(width/2),0)+"px";
	if(oSchedule.user == 'admin_konsult' || oSchedule.user == 'admin_foretag')
	{
		height = 0;
	}
	topVal=pageY-height+"px";

	//show the popup message
	$('#div_kalender_popup').css({left:leftVal,top:topVal}).fadeIn(500);

	var html_popup = getHTML(d,t,b, type);

	return html_popup;
}