/*
 * jQuery.weekCalendar v1.1.2
 * http://www.redredred.com.au/
 *
 * Requires:
 * - jquery.weekcalendar.css
 * - jquery 1.3.x
 * - jquery-ui 1.7.x (drag, drop, resize)
 *
 * Copyright (c) 2009 Rob Monie
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *   
 *   Special thanks to Adam Shaw who's fullcalendar plugin (http://arshaw.com/fullcalendar/)
 *   inspired the creation of this plugin. 
 */
(function($) {
    
    var MILLIS_IN_DAY = 86400000;
    var MILLIS_IN_WEEK = MILLIS_IN_DAY * 7;

    $.fn.weekCalendar = function(options) {
        
        if (typeof options == 'string') {
            var args = Array.prototype.slice.call(arguments, 1);
            this.each(function() {
                $.data(this, 'weekCalendar')[options].apply(this, args);
            });
            return this;
        }
        
        options = $.extend({
            date: new Date(),
            startParam : "start",
            endParam : "end",
            
			// buisness hours mis 10 comme pour les heures de reservation...
            businessHours : {start: 0, end: 10},
            newEventText : "New Event",
            buttons : true,
            buttonText : {
                today : "today",
                lastWeek : "&nbsp;&lt;&nbsp;",
                nextWeek : "&nbsp;&gt;&nbsp;"
            },
            scrollToHourMillis : 500,
            allowCalEventOverlap : false,
            
            draggable : function(calEvent, element) { return true;},
            resizable : function(calEvent, element) { return true;},
            eventClick : function(){},
            eventRender : function(calEvent, element) { return element;},
            eventDrop : function(calEvent, element){},
            eventResize : function(calEvent, element){},
            eventNew : function(calEvent, element) {},
            eventMouseover : function(calEvent, $event) {},
            eventMouseout : function(calEvent, $event) {},
            calendarBeforeLoad : function(calendar) {},
            calendarAfterLoad : function(calendar) {},
            noEvents : function() {}
            
        }, options);
        
        options.timeslotsPerDay = timeslotsPerHour * NombreHeureAgendaAvecMidi;
        options.millisPerTimeslot = MILLIS_IN_DAY / options.timeslotsPerDay ;

        return this.each(function() {
        
            var $calendar = $(this);
            
            function refreshWeek() {
                clearCalendar($calendar);
                loadCalEvents($calendar, $calendar.data("startDate")); //reload with existing week
            }
        
            function today() {
                clearCalendar($calendar);
                loadCalEvents($calendar, new Date()); 
            }
        
            function prevWeek() {
                //minus more than 1 day to be sure we're in previous week - account for daylight savings or other anomolies
                var newDate = new Date($calendar.data("startDate").getTime() - (MILLIS_IN_WEEK / 6));
                clearCalendar($calendar);   
                loadCalEvents($calendar, newDate);
            }
        
            function nextWeek() {
                //add 8 days to be sure of being in prev week - allows for daylight savings or other anomolies
                var newDate = new Date($calendar.data("startDate").getTime() + MILLIS_IN_WEEK + (MILLIS_IN_WEEK / 7));
                clearCalendar($calendar);
                loadCalEvents($calendar, newDate); 
            }
        
            function gotoWeek(date) {
                clearCalendar($calendar);
                loadCalEvents($calendar, date);
            }
            
            function removeEvent(eventId) {
                $calendar.find(".cal-event").each(function(){
                    if($(this).data("calEvent").id === eventId) {
                        $(this).fadeOut(function(){
                            $(this).remove();
                        });
                        return false;
                    }
                });
            }
            
            function removeUnsavedEvents() {
                $calendar.find(".new-cal-event").fadeOut(function(){
                    $(this).remove();
                });
            }
            
            function updateEvent(calEvent) {
                updateEventInCalendar(calEvent, $calendar);
            }
            
            $(this).data('weekCalendar', {
                today: today,
                prevWeek: prevWeek,
                nextWeek: nextWeek,
                gotoWeek: gotoWeek,
                refresh: refreshWeek,
                removeEvent: removeEvent,
                updateEvent: updateEvent,
                removeUnsavedEvents : removeUnsavedEvents
            }).data('options', options);
    
            setupEventDelegation($calendar);
            renderCalendar($calendar);
            scrollToHour($calendar, new Date().getHours());
            loadCalEvents($calendar);
            resizeCalendar($calendar);
            
            $(window).unbind("resize.weekcalendar");
            $(window).bind("resize.weekcalendar", function(){
                resizeCalendar($calendar);
            });
            
            return $(this);
        });
    };
    
    function resizeCalendar($calendar) {
        var options = $calendar.data("options");
        if(options && $.isFunction(options.height)) {
            var calendarHeight = options.height($calendar);
            var headerHeight = $calendar.find(".week-calendar-header").outerHeight();
            var navHeight = $calendar.find(".calendar-nav").outerHeight();
            $calendar.find(".calendar-scrollable-grid").height(calendarHeight - navHeight - headerHeight);
        }
    }
    
    // Setup event delgation for standard click & mouseover events for calEvents and columns
    function setupEventDelegation($calendar) {
        
        $calendar.click(function(event) {
            var options = $calendar.data("options");
            var $target = $(event.target);
            if($target.data("preventClick")) {
                return;
            }
            if($target.hasClass("cal-event")) {
                options.eventClick($target.data("calEvent"), $target, event);
            } else if($target.parent().hasClass("cal-event")) {
                options.eventClick($target.parent().data("calEvent"), $target.parent(), event);
            }
        }).mouseover(function(event){
            var options = $calendar.data("options");
            var $target = $(event.target);
            
            if(isDraggingOrResizing($target)) {
                return;
            }
            
            if($target.hasClass("cal-event") ) {
                options.eventMouseover($target.data("calEvent"), $target, event);
            } 
        }).mouseout(function(event){
            var options = $calendar.data("options");
            var $target = $(event.target);
            if(isDraggingOrResizing($target)) {
                return;
            }
            if($target.hasClass("cal-event")) {
                if($target.data("sizing")) return;
                options.eventMouseout($target.data("calEvent"), $target, event);
            } 
        });
    } 
    
    function isDraggingOrResizing($target) {
        return $target.hasClass("ui-draggable-dragging") || $target.hasClass("ui-resizable-resizing");
    }
    
    //Render the main calendar layout
    function renderCalendar($calendar) {
        var options, $calendarContainer, calendarNavHtml, calendarHeaderHtml, calendarBodyHtml, $weekDayColumns;
        
        options = $calendar.data("options");
        $calendarContainer = $("<div class=\"week-calendar\">").appendTo($calendar);
        
        if(options.buttons) {
            calendarNavHtml = "<div class=\"calendar-nav\">\
                <button class=\"prev\">" + options.buttonText.lastWeek + "</button>\
				<button class=\"today\">" + options.buttonText.today + "</button>\
                <button class=\"next\">" + options.buttonText.nextWeek + "</button>\
                </div>";
                
            $(calendarNavHtml).appendTo($calendarContainer);
            
            $calendarContainer.find(".calendar-nav .today").click(function(){
                $calendar.weekCalendar("today");
                return false;
            });
            
            $calendarContainer.find(".calendar-nav .prev").click(function(){
                $calendar.weekCalendar("prevWeek");
                return false;
            });
            
            $calendarContainer.find(".calendar-nav .next").click(function(){
                $calendar.weekCalendar("nextWeek");
                return false;
            });
        }
        
        //render calendar header
        calendarHeaderHtml = "<table class=\"week-calendar-header\" cellepadding='0' cellespacing='0'><tbody><tr><td class=\"time-column-header\"></td>"; 
		for(var i=1 ; i<=7; i++) {
			calendarHeaderHtml += "<td class=\"day-column-header day-" + i + " day-header-" + i + "\"></td>";
		}
        calendarHeaderHtml += "<td class=\"scrollbar-shim\"></td></tr></tbody></table>";
                    
        //render calendar body
		if(dimacheDesactive == true){
			calendarBodyHtml = "<div class=\"calendar-scrollable-grid\">\
				<table class=\"week-calendar-time-slots\">\
				<tbody>\
				<tr>\
				<td class=\"grid-timeslot-header\"></td>\
				<td colspan=\"6\">\
				<div class=\"time-slot-wrapper\">\
				<div class=\"time-slots\">";
		}
		else{
			calendarBodyHtml = "<div class=\"calendar-scrollable-grid\">\
				<table class=\"week-calendar-time-slots\">\
				<tbody>\
				<tr>\
				<td class=\"grid-timeslot-header\"></td>\
				<td colspan=\"7\">\
				<div class=\"time-slot-wrapper\">\
				<div class=\"time-slots\">";
		}
            
        for(var i=0 ; i<NombreHeureAgendaAvecMidi; i++) {
            for(var j=0;j<timeslotsPerHour - 1; j++) {
                calendarBodyHtml += "<div class=\"time-slot\"></div>";
            }   
            calendarBodyHtml += "<div class=\"time-slot hour-end\"></div>"; 
        }
        
        calendarBodyHtml += "</div></div></td></tr><tr><td class=\"grid-timeslot-header\">";
    
        for(var i=0 ; i<NombreHeureAgendaAvecMidi; i++) {

            var bhClass = (options.businessHours.start <= i && options.businessHours.end > i) ? "business-hours" : "";                 
            calendarBodyHtml += "<div class=\"hour-header hour-header" + i + ' ' + bhClass + "\">\
                    <div class=\"time-header-cell\">" + hourForIndex(i) + "<span class=\"am-pm\">" + amOrPm(i) + "</span></div></div>";
        }
        
        calendarBodyHtml += "</td>";
        
        for(var i=1 ; i<=7; i++) {
            calendarBodyHtml += "<td class=\"day-column day-" + i + "\"><div class=\"day-column-inner\"></div></td>"
        }
        
        calendarBodyHtml += "</tr></tbody></table></div>";
        
        //append all calendar parts to container            
        $(calendarHeaderHtml + calendarBodyHtml).appendTo($calendarContainer);
        
        $weekDayColumns = $calendarContainer.find(".day-column-inner");
        $weekDayColumns.each(function(i, val) {
            $(this).height(timeslotHeight * options.timeslotsPerDay);  
            addDroppableToWeekDay($calendar, $(this), options);
            setupEventCreationForWeekDay($calendar, $(this));
        });
        
        $calendarContainer.find(".time-slot").height(timeslotHeight -1); //account for border
        
        $calendarContainer.find(".time-header-cell").css({
			height :  (timeslotHeight * timeslotsPerHour) - 11,
			padding: 5
        });
    }
    
    function setupEventCreationForWeekDay($calendar, $weekDay) {
        $weekDay.mousedown(function(event) {
            var options = $calendar.data("options");
            var $target = $(event.target);
			
            if($target.hasClass("day-column-inner")) {
				var $newEvent = $("<div class=\"cal-event new-cal-event new-cal-event-creating\"></div>");
			
				$newEvent.css({lineHeight: (timeslotHeight - 2) + "px", fontSize: (timeslotHeight / 2) + "px"});
				$target.append($newEvent);
				
				var columnOffset = $target.offset().top;
				var clickY = event.pageY - columnOffset;
				var clickYRounded = (clickY - (clickY % timeslotHeight)) / timeslotHeight;
				var topPosition = clickYRounded * timeslotHeight;
				$newEvent.css({top: topPosition});
				
				//par défault quand on click sur l'agenda pour creer un rdv, ce dernier est crée meme si y a un rdv juste apres (le nouveau se met par dessus ce dernier), donc ajout d'une variable et d'un check up pour changer ce comportement ...
				if(checkAuClick == 1){
					$target.children().each(function(i){
						if( (topPosition < $(this).css("top").replace("px","")) && ((topPosition + (timeslotHeight * defaultEventLength)) > ($(this).css("top").replace("px",""))) && ((topPosition + (timeslotHeight * defaultEventLength)) <= ($(this).css("top").replace("px","")+$(this).css("height").replace("px",""))) || (topPosition < $(this).css("top").replace("px","")) && ((topPosition + (timeslotHeight * defaultEventLength)) >= ($(this).css("top").replace("px","")+$(this).css("height").replace("px",""))) || (topPosition + (timeslotHeight * defaultEventLength)) > $target.css("height").replace("px","") ){
							OkCreeDate = 0;
							return false;
						}
						else{OkCreeDate = 1;}
					});
				}
				
				//par défault on peut selectionner une hauteur qu'on veut avec la souris quand on click et qu'on reste appuyé dessus, mise en place d'une var pour désactivation
				if(selectFreeSizeEvent == 1){
					$target.bind("mousemove.newevent", function(event){
						$newEvent.show();
						$newEvent.addClass("ui-resizable-resizing");
						var height = Math.round(event.pageY - columnOffset - topPosition);
						var remainder = height % timeslotHeight;
						//snap to closest timeslot
						if(remainder < (height / 2)) { 
							var useHeight = height - remainder;
							$newEvent.css("height", useHeight < timeslotHeight ? timeslotHeight : useHeight);
						} else {
							$newEvent.css("height", height + (timeslotHeight - remainder));
						}
					 }).mouseup(function(){
						$target.unbind("mousemove.newevent");
						$newEvent.addClass("ui-corner-all");
					 });
				}
              }
        
          }).mouseup(function(event) {
            var options = $calendar.data("options");
            var $target = $(event.target);
			
            if($target.hasClass("day-column-inner") || $target.hasClass(".new-cal-event-creating")) {
				var $weekDay = $target.hasClass(".new-cal-event-creating") ? $target.closest(".day-column-inner") : $target;
				
				var $newEvent = $weekDay.find(".new-cal-event-creating");
				 //if even created from a single click only, default height
				 if(!$newEvent.hasClass("ui-resizable-resizing")) {
					$newEvent.css({height: timeslotHeight * defaultEventLength}).show();
				 }
	
				 if($newEvent.length) {
					 	
					var top = parseInt($newEvent.css("top"));
					var eventDuration = getEventDurationFromPositionedEventElement($weekDay, $newEvent, top, options);
					$newEvent.remove();
					var newCalEvent = {start: eventDuration.start, end: eventDuration.end, title: options.newEventText};
					var $renderedCalEvent = renderEvent(newCalEvent, $weekDay, options);
					
					options.eventNew(eventDuration, $renderedCalEvent);
				 }
             }
        });
    }
    
    function loadCalEvents($calendar, dateWithinWeek) {
        
        var options, date, weekStartDate, endDate, $weekDayColumns;
        
        options = $calendar.data("options");
        date = dateWithinWeek || options.date;
        weekStartDate = dateFirstDayOfWeek(date);
        weekEndDate = dateLastMilliOfWeek(date);
        
        options.calendarBeforeLoad($calendar);

        $calendar.data("startDate", weekStartDate);
        $calendar.data("endDate", weekEndDate);
        
        $weekDayColumns = $calendar.find(".day-column-inner");
        updateDayColumnHeader($calendar, $weekDayColumns);
        
        //load events by chosen means        
        if (typeof options.data == 'string') {
            if (options.loading) options.loading(true);
            var jsonOptions = {};
            jsonOptions[options.startParam || 'start'] = Math.round(weekStartDate.getTime() / 1000);
            jsonOptions[options.endParam || 'end'] = Math.round(weekEndDate.getTime() / 1000);
            $.getJSON(options.data, jsonOptions, function(data) {
                renderEvents(data, $weekDayColumns, $calendar);
                if (options.loading) options.loading(false);
            });
        }
        else if ($.isFunction(options.data)) {
            options.data(weekStartDate, weekEndDate,
                function(data) {
                    renderEvents(data, $weekDayColumns, $calendar);
                });
        }
        else if (options.data) {
            renderEvents(options.data, $weekDayColumns, $calendar);
        }
        
        disableTextSelect($weekDayColumns);
    }
    
    function updateDayColumnHeader($calendar, $weekDayColumns) {
        var currentDay = cloneDate($calendar.data("startDate"));

        $calendar.find(".week-calendar-header td.day-column-header").each(function(i, val) {
                $(this).html(dayNames[i] + "<br/>" + currentDay.getDate() + " " + monthNames[currentDay.getMonth()] + " " + currentDay.getFullYear());
                if(isToday(currentDay)) {
                    $(this).addClass("today");
                } else {
                    $(this).removeClass("today");
                }
				
				//ajout d'une condition pour détecter si c'est une vieille date...
				if( (currentDay.getTime() <= new Date().getTime()) && !($(this).hasClass("today")) ){
					$(this).addClass("oldDateHead");
				}
				
				else{
					$(this).removeClass("oldDateHead");
				}
                currentDay = addDays(currentDay, 1);
        });
        
        currentDay = dateFirstDayOfWeek(cloneDate($calendar.data("startDate")));
        
        $weekDayColumns.each(function(i, val) {
            $(this).data("startDate", cloneDate(currentDay));
            $(this).data("endDate", new Date(currentDay.getTime() + (MILLIS_IN_DAY - 1)));          
            if(isToday(currentDay)) {
                $(this).parent().addClass("today");
            } else {
                $(this).parent().removeClass("today");
            }
			//ajout d'une condition pour détecter si c'est une vieille date...
			if( (currentDay.getTime() <= new Date().getTime()) && !($(this).parent().hasClass("today")) ){
				$(this).parent().addClass("oldDateCell");
			}
			else{
				$(this).parent().removeClass("oldDateCell");
			}
            
            currentDay = addDays(currentDay, 1);
        });
    }
    
    function renderEvents(events, $weekDayColumns, $calendar) {
        var options = $calendar.data("options");
        var eventsToRender;
        
        if($.isArray(events)) {
            eventsToRender = cleanEvents(events);
        } else if(events.events) {
             eventsToRender = cleanEvents(events.events);
        }
		
        if(events.options) {
            
            var updateLayout = false;
            //check if any options have actually changed
            $.each(events.options, function(key, value){
                if(value !== options[key]) {
                    updateLayout = true;
                    return false;
                }
            });
            
            options = $.extend(options, events.options);
            options.timeslotsPerDay = timeslotsPerHour * NombreHeureAgendaAvecMidi;
            options.millisPerTimeslot = MILLIS_IN_DAY / options.timeslotsPerDay;
            
            if(updateLayout) {
                $calendar.empty();
                renderCalendar($calendar);
                $weekDayColumns = $calendar.find(".week-calendar-time-slots .day-column-inner");
                updateDayColumnHeader($calendar, $weekDayColumns);
                resizeCalendar($calendar);
            }
            
            $calendar.data("options", options);
        }
         
        $.each(eventsToRender, function(i, calEvent){
            
            var $weekDay = findWeekDayForEvent(calEvent, $weekDayColumns);
            
            if($weekDay) {
                renderEvent(calEvent, $weekDay, options);
            }
        }); 
        
        options.calendarAfterLoad($calendar);
        
        if(!eventsToRender.length) {
            options.noEvents();
        }
    }
    
    function renderEvent(calEvent, $weekDay, options) {
        
        if(calEvent.start.getTime() > calEvent.end.getTime()) {
            return; // can't render a negative height
        }
        
        var eventClass, eventHtml, $calEvent, $modifiedEvent;
        
		//ajout d'une class en plus comportant le numero id
        eventClass = calEvent.id ? "cal-event event"+calEvent.id : "cal-event new-cal-event";
		
		//Ajout d'une class pour les pseudo RDV (affichage de "non disponible")
		
		if(calEvent.fake == 1){
			eventHtml = "<div class=\"" + eventClass + " ui-corner-all non_dispo\" id=\"event"+calEvent.id+"\" >\
            <div class=\"title\"></div>";
		}
		else if(calEvent.old == 1){
			if(calEvent.collab){
				eventHtml = "<div class=\"" + eventClass + " collab" + calEvent.collab + " pending" + calEvent.pending + " ui-corner-all old_rdv\" id=\"event"+calEvent.id+"\" >\
				<div class=\"title\"></div>";
			}
			else{
				eventHtml = "<div class=\"" + eventClass + " ui-corner-all old_rdv\" id=\"event"+calEvent.id+"\" >\
				<div class=\"title\"></div>";
			}
		}
		else{
			// Ajout ci-dessous d'un div pour un boutton supprimer...
			if(calEvent.collab){
				eventHtml = "<div class=\"" + eventClass + " collab" + calEvent.collab + " pending" + calEvent.pending + " ui-corner-all\" id=\"event"+calEvent.id+"\" >\
				<a href='javascript:void(null);' class=\"deleteEvent\" onclick=\"delIt($(this));\"></a><div class=\"time ui-corner-all\"></div>\
				<div class=\"title\"></div></div>";
			}
			else{
				eventHtml = "<div class=\"" + eventClass + " ui-corner-all\" id=\"event"+calEvent.id+"\" >\
				<a href='javascript:void(null);' class=\"deleteEvent\" onclick=\"delIt($(this));\"></a><div class=\"time ui-corner-all\"></div>\
				<div class=\"title\"></div></div>";
			}
		}
		
        $calEvent = $(eventHtml);
        $modifiedEvent = options.eventRender(calEvent, $calEvent);
        $calEvent = $modifiedEvent ? $modifiedEvent.appendTo($weekDay) : $calEvent.appendTo($weekDay);
        $calEvent.css({lineHeight: (timeslotHeight - 2) + "px", fontSize: (timeslotHeight / 2) + "px"});
        
        positionEvent($weekDay, $calEvent, calEvent);
        refeshEventDetails(calEvent, $calEvent);
        $calEvent.show();
        
        if(options.resizable(calEvent, $calEvent)) {
            addResizableToCalEvent(calEvent, $calEvent, $weekDay, options)
        }
        if(options.draggable(calEvent, $calEvent)) {
            addDraggableToCalEvent(calEvent, $calEvent, options);
        }
        
        return $calEvent;
    }
    
    function findWeekDayForEvent(calEvent, $weekDayColumns) {
    
        var $weekDay;
        $weekDayColumns.each(function(){
			//ajout d'une condition car après suppression d'un RDV, on insert une ligne vide dans notre tableau des RDV, dc pb ici
			if(calEvent.start != undefined){
				if($(this).data("startDate").getTime() <= calEvent.start.getTime() && $(this).data("endDate").getTime() >= calEvent.end.getTime()) {
					$weekDay = $(this);
					return false;
				} 
			}
        }); 
        
        return $weekDay;
    }
    
    function updateEventInCalendar(calEvent, $calendar) {
        var options = $calendar.data("options");
        cleanEvent(calEvent);
        var $calEvent;
        if(calEvent.id) {
            $calendar.find(".cal-event").each(function(){
                if($(this).data("calEvent").id === calEvent.id || $(this).hasClass("new-cal-event")) {
                    $(this).remove();
                    return false;
                }
            });
        }
        
        var $weekDay = findWeekDayForEvent(calEvent, $calendar.find(".week-calendar-time-slots .day-column-inner"));
        if($weekDay) {
            renderEvent(calEvent, $weekDay, options);
        }
    }
    
    function positionEvent($weekDay, $calEvent, calEvent) {
		// modification, certaines valeurs étaient en dur alors qu'il faut tenir compte de timeslotsPerHour et de timeslotHeight
        var pxPerMillis = (24*timeslotsPerHour*timeslotHeight) / MILLIS_IN_DAY;
        var startMillis = calEvent.start.getTime() - new Date(calEvent.start.getFullYear(), calEvent.start.getMonth(), calEvent.start.getDate()).getTime();
        var eventMillis = calEvent.end.getTime() - calEvent.start.getTime();  
        var pxTop = pxPerMillis * (startMillis - (MILLIS_IN_DAY / 24 * HeureDebutAgenda));
        var pxHeight = pxPerMillis * eventMillis;
        $calEvent.css({top: pxTop, height: pxHeight});
    }

    function getEventDurationFromPositionedEventElement($weekDay, $calEvent, top, options) {
		// tout comme la fonction d'au dessus, cette fonction a été modifiée ...
        var start = new Date($weekDay.data("startDate").getTime()+ (MILLIS_IN_DAY / 24 * HeureDebutAgenda) + (Math.round(top) / (24*timeslotsPerHour*timeslotHeight) * MILLIS_IN_DAY));
        var end = new Date(start.getTime() + ($calEvent.height() / (24*timeslotsPerHour*timeslotHeight) * MILLIS_IN_DAY));
        return {start: start, end: end};
    }
    
    function adjustForEventCollisions($weekDay, $calEvent, newCalEvent, oldCalEvent, options, maintainEventDuration) {
        if(options.allowCalEventOverlap) {
            return;
        }
        var adjustedStart, adjustedEnd;

        $weekDay.find(".cal-event").not($calEvent).each(function(){
            var currentCalEvent = $(this).data("calEvent");
            
            //has been dropped onto existing event overlapping the end time
            if(newCalEvent.start.getTime() < currentCalEvent.end.getTime() 
                && newCalEvent.end.getTime() >= currentCalEvent.end.getTime()) {
			  adjustedStart = oldCalEvent.start;
			  adjustedEnd = oldCalEvent.end;
			  return false;
            }
            
            //has been dropped onto existing event overlapping the start time
            if(newCalEvent.end.getTime() > currentCalEvent.start.getTime() 
                && newCalEvent.start.getTime() <= currentCalEvent.start.getTime()) {
			  adjustedStart = oldCalEvent.start;
			  adjustedEnd = oldCalEvent.end;
			  return false;
            }
            //has been dropped inside existing event with same or larger duration
            if(newCalEvent.end.getTime() <= currentCalEvent.end.getTime() 
                && newCalEvent.start.getTime() >= currentCalEvent.start.getTime()) {
                adjustedStart = oldCalEvent.start;
                adjustedEnd = oldCalEvent.end;
                return false;
            }
        });
        
        newCalEvent.start = adjustedStart || newCalEvent.start;
        
        if(adjustedStart && maintainEventDuration) {
            newCalEvent.end = new Date(adjustedStart.getTime() + (oldCalEvent.end.getTime() - oldCalEvent.start.getTime()));
            adjustForEventCollisions($weekDay, $calEvent, newCalEvent, oldCalEvent, options);
        } else {
            newCalEvent.end = adjustedEnd || newCalEvent.end;
        }
        
        //reset if new cal event has been forced to zero size
        if(newCalEvent.start.getTime() >= newCalEvent.end.getTime()) {
            newCalEvent.start = oldCalEvent.start;
            newCalEvent.end = oldCalEvent.end;
        }
        
        $calEvent.data("calEvent", newCalEvent);
    }
    
    function addDraggableToCalEvent(calEvent, $calEvent, options) {
		// Drag and drop rendu configurable...
		if ( (DragDropActif == 1) && (calEvent.fake != 1) ){
			$calEvent.draggable({
				handle : ".time",
				containment: ".calendar-scrollable-grid",
				opacity: 0.5,
				grid : [$calEvent.outerWidth() + 1, timeslotHeight ]
			});
		}
    }
    
    function addDroppableToWeekDay($calendar, $weekDay, options) {
        $weekDay.droppable({
            accept: ".cal-event",
            drop: function(event, ui) {
                var $calEvent = ui.draggable;
                var top = Math.round(parseInt(ui.position.top));
                var eventDuration = getEventDurationFromPositionedEventElement($weekDay, $calEvent, top, options);
                var calEvent = $calEvent.data("calEvent");
                var newCalEvent = $.extend(true, {start: eventDuration.start, end: eventDuration.end}, calEvent);
                adjustForEventCollisions($weekDay, $calEvent, newCalEvent, calEvent, options, true);
                var $weekDayColumns = $calendar.find(".day-column-inner");
                var $newEvent = renderEvent(newCalEvent, findWeekDayForEvent(newCalEvent, $weekDayColumns), options);
                $calEvent.hide();
                
                //trigger drop callback
                options.eventDrop(newCalEvent, calEvent, $newEvent);
                $calEvent.data("preventClick", true);
                setTimeout(function(){
                    $calEvent.remove(); 
                }, 500);    
            }
        });
    }
    
    function addResizableToCalEvent(calEvent, $calEvent, $weekDay, options) {
        $calEvent.resizable({
            grid: timeslotHeight,
            containment : $weekDay,
            handles: "s",
            minHeight: timeslotHeight,
            stop :function(event, ui){
                var $calEvent = ui.element;  
                var newEnd = new Date($calEvent.data("calEvent").start.getTime() + ($calEvent.height() / (24*timeslotsPerHour*timeslotHeight) * MILLIS_IN_DAY));
                var newCalEvent = $.extend(true, {start: calEvent.start, end: newEnd}, calEvent);
                adjustForEventCollisions($weekDay, $calEvent, newCalEvent, calEvent, options);
                positionEvent($weekDay, $calEvent, newCalEvent);
                refeshEventDetails(newCalEvent, $calEvent);
                
                //trigger resize callback
                options.eventResize(newCalEvent, calEvent, $calEvent);
                $calEvent.data("preventClick", true);
                setTimeout(function(){
                    $calEvent.removeData("preventClick");
                }, 500);
            }
        });
    }
    
    function refeshEventDetails(calEvent, $calEvent) {
        $calEvent.find(".time").text();
        $calEvent.find(".title").text(calEvent.title);
        $calEvent.data("calEvent", calEvent);
    }
    
    function clearCalendar($calendar) {
        $calendar.find(".day-column-inner div").remove();
    }
    
    function scrollToHour($calendar, hour) {
        var options = $calendar.data("options");
        var $scrollable = $calendar.find(".calendar-scrollable-grid");
        var $target = $calendar.find(".grid-timeslot-header .hour-header:eq(" + hour + ")");
        
        $scrollable.animate({scrollTop: 0}, 0, function(){
            var targetOffset = $target.offset().top;
            var scroll = targetOffset - $scrollable.offset().top - $target.outerHeight();
            $scrollable.animate({scrollTop: scroll}, options.scrollToHourMillis);
        });
    }
    
    function formatAsTime(date) {
        return zeroPad(hourForIndex2(date.getHours()), 2) + ":" + zeroPad(date.getMinutes(), 2) + " " + amOrPm(date.getHours());
    }

    function hourForIndex(index) {
		//rajout de "+HeureDebutAgenda" car on ne commence plus à 0h ! ...
		index = index + HeureDebutAgenda;
		
		if (AmPm == true){
			if(index === 0 ) { //midnight
				return 12; 
			} else if(index < 13) { //am
				return index;
			} else { //pm
				return index - 12;
			}
		}
		else{
			return index;
		}
    }
	
	// nouvelle fonction car si on utilise l'ancienne, les rdv sont aussi à "+HeureDebutAgenda" ...
	function hourForIndex2(index) {
		if (AmPm == true){
			if(index === 0 ) { //midnight
				return 12; 
			} else if(index < 13) { //am
				return index;
			} else { //pm
				return index - 12;
			}
		}
		else{
			return index;
		}
    }
    
    function amOrPm(hourOfDay) {
		if (AmPm == true){
        	return hourOfDay < 12 ? "AM" : "PM";
		}
		else{
			return "H";
		}
    }
    
    function isToday(date) {
        var clonedDate = cloneDate(date);
        clearTime(clonedDate);
        var today = new Date();
        clearTime(today);
        return today.getTime() === clonedDate.getTime();
    }

    function cleanEvents(events) {
        $.each(events, function(i, event) {
            cleanEvent(event);
        });
        return events;
    }
    
    function cleanEvent(event) {
        if (event.date) event.start = event.date;
        event.start = cleanDate(event.start);
        event.end = cleanDate(event.end);
        if (!event.end) event.end = addDays(cloneDate(event.start), 1);
    }

    function disableTextSelect($elements) {
        $elements.each(function(){
            if($.browser.mozilla){//Firefox
                $(this).css('MozUserSelect','none');
            }else if($.browser.msie){//IE
                $(this).bind('selectstart',function(){return false;});
            }else{//Opera, etc.
                $(this).mousedown(function(){return false;});
            }
        });
    }

    function dateFirstDayOfWeek(date) {
        var midnightCurrentDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
            var currentDayOfWeek = midnightCurrentDate.getDay();
            var millisToSubtract = currentDayOfWeek * 86400000;
            var dateTimeZoneCheck = new Date(midnightCurrentDate.getTime() - millisToSubtract);
            // workaround for daylight saving time
            if (dateTimeZoneCheck.getHours()==23) {
              dateTimeZoneCheck = new Date(dateTimeZoneCheck.getTime() + 3600000);
            }
            return dateTimeZoneCheck;

    }
    
    function dateLastDayOfWeek(date) {
        var midnightCurrentDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
        var currentDayOfWeek = midnightCurrentDate.getDay();
        var millisToAdd = (6 - currentDayOfWeek) * MILLIS_IN_DAY;
        return new Date(midnightCurrentDate.getTime() + millisToAdd);
    }
    
    function dateLastMilliOfWeek(date) {
        var lastDayOfWeek = dateLastDayOfWeek(date);
        return new Date(lastDayOfWeek.getTime() + (MILLIS_IN_DAY));
    }
    
    function zeroPad(number, size) {
        var length = ("" + number).length;
        var strNumber = "" + number;
        for(var i = 0; i<size - length; i++) {
            strNumber = "0" + strNumber;
        }
        return strNumber;
    }
    
    function clearTime(d) {
        d.setHours(0); 
        d.setMinutes(0);
        d.setSeconds(0); 
        d.setMilliseconds(0);
        return d;
    }
    
    function addDays(d, n, keepTime) {
        d.setDate(d.getDate() + n);
        if (keepTime) return d;
        return clearTime(d);
    }
    
    function cloneDate(d) {
        return new Date(+d);
    }
    
    function cleanDate(d) {
        if (typeof d == 'string')
            return $.parseISO8601(d, true) || Date.parse(d) || new Date(parseInt(d));
        if (typeof d == 'number')
            return new Date(d);
        return d;
    }
    
    $.parseISO8601 = function(s, ignoreTimezone) {
        // derived from http://delete.me.uk/2005/03/iso8601.html
        var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
            "(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" +
            "(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
        var d = s.match(new RegExp(regexp));
        if (!d) return null;
        var offset = 0;
        var date = new Date(d[1], 0, 1);
        if (d[3]) { date.setMonth(d[3] - 1); }
        if (d[5]) { date.setDate(d[5]); }
        if (d[7]) { date.setHours(d[7]); }
        if (d[8]) { date.setMinutes(d[8]); }
        if (d[10]) { date.setSeconds(d[10]); }
        if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
        if (!ignoreTimezone) {
            if (d[14]) {
                offset = (Number(d[16]) * 60) + Number(d[17]);
                offset *= ((d[15] == '-') ? 1 : -1);
            }
            offset -= date.getTimezoneOffset();
        }
        return new Date(Number(date) + (offset * 60 * 1000));
    };

    $.ISO8601String = function(date) {
        // derived from http://delete.me.uk/2005/03/iso8601.html
        var zeropad = function (num) { return ((num < 10) ? '0' : '') + num; }
        return date.getUTCFullYear() +
            "-" + zeropad(date.getUTCMonth() + 1) +
            "-" + zeropad(date.getUTCDate()) +
            "T" + zeropad(date.getUTCHours()) +
            ":" + zeropad(date.getUTCMinutes()) +
            ":" + zeropad(date.getUTCSeconds()) +
            "Z";
    };

})(jQuery);
