Index: trunk/prototype/modules/calendar/js/calendar.contentMenu.js
===================================================================
--- trunk/prototype/modules/calendar/js/calendar.contentMenu.js	(revision 5592)
+++ trunk/prototype/modules/calendar/js/calendar.contentMenu.js	(revision 5746)
@@ -6,22 +6,41 @@
 	$('.fullcalendar-context-menu').bind('contextmenu', function(event){
 		event.preventDefault();
+                
 		var classes = $(this).attr('class').split(" ");
-		var idCalendar = false;
 		var idEvent = false;
-		
+                var idRecurrence = false;
+                
 		//recupera o id do calendar eo id do evento para tratamento
 		for(var i = 0; i < classes.length; i++){
-			if(classes[i].indexOf("calendar-") >= 0 ){
-				idCalendar = classes[i].replace(/[a-zA-Z-]+/g, '');
-			}else if (classes[i].indexOf("event-id-") >= 0 ){
-				idEvent = classes[i].replace(/[a-zA-Z-]+/g, '');
-			}
-			if(idCalendar && idEvent)
-				break;
-		};
-		
-		var template = DataLayer.render( 'templates/menu_context_event.ejs', {event: idEvent,top: (event.clientY - 135), left: (event.clientX - 445), signature: Calendar.signatureOf[idCalendar], calendars: Calendar.calendars});
+                    if (classes[i].indexOf("event-id-") >= 0 ){
+                        idEvent = classes[i].replace(/[a-zA-Z-]+/g, '');
+                        continue;
+                    }else if (classes[i].indexOf("Recurrence-id-") >= 0 ){
+                        idRecurrence = classes[i].replace(/[a-zA-Z-]+/g, '');
+                        continue;
+                    }
+                }
+
+                var schedulable = DataLayer.get('schedulable', idEvent);
+                
+		var template = DataLayer.render( 'templates/menu_context_event.ejs', {event: schedulable.id ,
+                    top: (event.clientY - 135), left: (event.clientX - 445), 
+                    signature: Calendar.signatureOf[schedulable.calendar],
+                    calendars: Calendar.calendars, isRecurrence: (!!parseInt(schedulable.repeat)),
+                    idRecurrence: idRecurrence
+                });
 		
 		$('#context-menu-event').html(template);
+                
+                var method = function(value){
+                    switch (value){
+                        case "ocurrency":
+                            return '2'
+                        case "copy":
+                            return '1';
+                        case "move": 
+                            return '0';
+                    }
+                }
 		
 		$('#context-menu-event').find('li.menu-item').hover(
@@ -30,5 +49,5 @@
 				if($(this).hasClass('copy') || $(this).hasClass('move')) {
 					
-					$(this).parents().find('.calendar-copy-move input[name="typeEvent"]').val( ($(this).hasClass('copy') ? '0' : '1' ));
+					$(this).parents().find('.calendar-copy-move input[name="typeEvent"]').val( method($(this).attr('class').split(" ")[0]));
 					$(this).parents().find('.calendar-copy-move').show();
 				
Index: trunk/prototype/modules/calendar/js/calendar.codecs.js
===================================================================
--- trunk/prototype/modules/calendar/js/calendar.codecs.js	(revision 5737)
+++ trunk/prototype/modules/calendar/js/calendar.codecs.js	(revision 5746)
@@ -75,5 +75,4 @@
 			   borderColor: '#' + signature.borderColor || User.preferences.borderColor,
 			   textColor: '#' + signature.fontColor || User.preferences.fontColor,
-			   className: 'calendar-' + signature.calendar.id,
 			   editable:  signature.isOwner }
 	       });
@@ -179,5 +178,6 @@
 
 		if(force){
-			delete Calendar.currentViewKey;
+                        delete Calendar.currentViewKey;
+                        
 			$('#calendar').fullCalendar( 'refetchEvents' );
 		}
@@ -189,4 +189,6 @@
 
 		$('#calendar').fullCalendar( 'refetchEvents' );	
+                
+                contentMenu();
 	}
 }
@@ -271,6 +273,5 @@
 		DataLayer.commit( false, false, function(){	
 			if((typeof($tabs) != "undefined") && $tabs.tabs('option' ,'selected') == 0){
-				Calendar.rerenderView(true);
-				contentMenu();
+                                Calendar.rerenderView(true);
 			}else if((typeof($tabs) != "undefined") && $tabs.tabs('option' ,'selected') != 0)
 				pageselectCallback($('.events-list-win.active [name=keyword]').val(), 0);
@@ -603,5 +604,5 @@
 						return(null);
 					
-					var attend = DataLayer.get('participant', participant);
+					var attend = DataLayer.get('participant', (participant.id || participant));
 					attend.user = DataLayer.get('user', attend.user);
 					
@@ -612,5 +613,5 @@
 							id: attend.id,
 							status : attend.status,
-							delegatedFrom: attend.delegatedFrom,
+							delegatedFrom: attend.delegatedFrom || '0',
 							acl: attend.acl,
 							receiveNotification : attend.receiveNotification,
@@ -947,5 +948,5 @@
 		var calendar = DataLayer.get('calendar', evt.calendar);
 		
-		var eventEditable = function(idEvent, isRecurrence){
+		var eventEditable = function(idEvent, isRecurrence, Recurrence){
 			if(Calendar.signatureOf[calendar.id].isOwner == "1"){
 				var attendee = {};
@@ -953,5 +954,5 @@
 					attendee = DataLayer.get('participant', evt.participants[i]);
 						if(attendee.user == User.me.id)
-							return (attendee.acl.indexOf('w') >= 0 || attendee.acl.indexOf('o') >= 0 ) ? {selectable: true, className: 'fullcalendar-context-menu  event-id-'+idEvent, editable: !isRecurrence} : { editable: false, selectable: true ,className: 'blocked-event-permision  fullcalendar-not-context-menu event-id-'+idEvent};
+							return (attendee.acl.indexOf('w') >= 0 || attendee.acl.indexOf('o') >= 0 ) ? {selectable: true, className: 'fullcalendar-context-menu  event-id-'+idEvent+ (isRecurrence ? ' isRecurrence Recurrence-id-'+Recurrence : '')} : { editable: false, selectable: true ,className: 'blocked-event-permision  fullcalendar-not-context-menu event-id-'+idEvent};
 				}
 				return {editable: false, className: 'blocked-event-permision  fullcalendar-not-context-menu event-id-'+idEvent,  selectable: true, disableDragging: isRecurrence };
@@ -963,5 +964,5 @@
 					var returns = ""
 					returns += acl['write'] ? "" :  'blocked-event-permision ';
-					returns += acl['busy'] ? 'fullcalendar-not-context-menu ' : (acl['read']  ?  'fullcalendar-context-menu ' : '');
+					returns += acl['busy'] ? 'fullcalendar-not-context-menu ' : (acl['read']  ?  'fullcalendar-context-menu '+ idEvent + (isRecurrence ? ' isRecurrence Recurrence-id-'+Recurrence : '') : '');
 					returns += 'event-id-'+idEvent;
 					return returns;
@@ -992,9 +993,11 @@
 		  
 		for( var i = 0; i < occurrences.length; i++ )
-		    grouped[ evt.calendar ].push( DataLayer.merge({ id: evt.URI || evt.id,
-						    title: Encoder.htmlDecode(evt.summary),
-						    start: Timezone.getDateCalendar(new Date( parseInt( occurrences[i] ) ), calendar.timezone,  !!evt.DayLigth ? evt.DayLigth.calendar.startTime : Timezone.daylightSaving),
-						    end:   Timezone.getDateCalendar(new Date( parseInt( occurrences[i] ) + duration - (!!parseInt(evt.allDay) ? 86400000 : 0)), calendar.timezone, !!evt.DayLigth ? evt.DayLigth.calendar.startTime : Timezone.daylightSaving),
-						    allDay: parseInt( evt.allDay ) }, eventEditable(evt.id, isRepeat ) ) );
+		    grouped[ evt.calendar ].push( DataLayer.merge({ id: evt.URI || evt.id+ '-' + i,
+                    title: Encoder.htmlDecode(evt.summary),
+                    start: Timezone.getDateCalendar(new Date( parseInt( occurrences[i] ) ), calendar.timezone,  !!evt.DayLigth ? evt.DayLigth.calendar.startTime : Timezone.daylightSaving),
+                    end:   Timezone.getDateCalendar(new Date( parseInt( occurrences[i] ) + duration - (!!parseInt(evt.allDay) ? 86400000 : 0)), calendar.timezone, !!evt.DayLigth ? evt.DayLigth.calendar.startTime : Timezone.daylightSaving),
+                    allDay: parseInt( evt.allDay ),
+                    isRepeat: isRepeat,
+                    occurrence: i }, eventEditable(evt.id, isRepeat, i ) ) );
 	});
 
Index: trunk/prototype/modules/calendar/js/helpers.js
===================================================================
--- trunk/prototype/modules/calendar/js/helpers.js	(revision 5720)
+++ trunk/prototype/modules/calendar/js/helpers.js	(revision 5746)
@@ -59,5 +59,11 @@
 */
 
-function eventDetails( objEvent, decoded, path, isMail)
+/*
+ * TODO - repeat foi adicionado pois melhorias devem ser feitas no rollback do
+ *DataLayer, repeat somente é usado quando se trata da criação de um evento
+ *pela edição de uma ocorrência.
+ */
+
+function eventDetails( objEvent, decoded, path, isMail, repeat)
 {
 	attendees = {};
@@ -318,8 +324,10 @@
 										*/
 										var ids = [];
-										$.each($('.attachment-list input'), function (i, input) { ids.push(input.value); });
+										$.each($('.attachment-list input'), function (i, input) {ids.push(input.value);});
 										if(ids.length > 0)
 											DataLayer.remove('attachment', {filter: ['IN', 'id', ids]});
 										
+                                                                                DataLayer.rollback();
+                                                                                
 										UI.dialogs.addEvent.dialog('close');
 									}else{
@@ -649,6 +657,15 @@
 			canDiscardEventDialog = true;
 			
-			UI.dialogs.addEvent.children().find('form.form-addevent').submit();
-			UI.dialogs.addEvent.dialog("close");
+                        var exit = function(){
+                            UI.dialogs.addEvent.children().find('form.form-addevent').submit();
+                            UI.dialogs.addEvent.dialog("close");
+                        }
+                        
+                        if(repeat){
+                               DataLayer.remove('repeat', false);
+                               DataLayer.put('repeat', repeat);
+                               DataLayer.commit('repeat', false, exit);
+                        }else
+                            exit();
 	    }).end()
 		
@@ -703,8 +720,10 @@
 		});
 
-		if(objEvent.me.id == User.me.id){
-			objEvent.me.id = DataLayer.put('participant', {user: objEvent.me.id, mail: objEvent.me.mail });
-			objEvent.organizer.id = objEvent.me.id;
-		}
+
+                if(!repeat)
+                    if(objEvent.me.id == User.me.id){
+                            objEvent.me.id = DataLayer.put('participant', {user: objEvent.me.id, mail: objEvent.me.mail});
+                            objEvent.organizer.id = objEvent.me.id;
+                    }
 
 		var attendeeHtml = DataLayer.render( path+'templates/attendee_add.ejs', {event:objEvent});		
@@ -783,5 +802,5 @@
 					var user = DataLayer.get('user', ["=", "mail", $(this).val()]);
 					if(!!user && user[0].id)
-						attendees[user[0].id] = { name: user[0].name };
+						attendees[user[0].id] = {name: user[0].name};
 					
 					/**
@@ -1069,5 +1088,5 @@
 				
 				var ids = [];
-				$.each($('.attachment-list input'), function (i, input) { ids.push(input.value); });
+				$.each($('.attachment-list input'), function (i, input) {ids.push(input.value);});
 				if(ids.length > 0){
 					DataLayer.remove('attachment', {filter: ['IN', 'id', ids]});
@@ -1597,5 +1616,37 @@
 			if(clicked == 'Sim'){
 				DataLayer.remove('schedulable', ''+eventId);
-				window.setTimeout(function() {DataLayer.commit();}, 500);
+				DataLayer.commit();
+			}
+		}
+	});	
+}
+
+function mount_exception(eventID, idException){
+    
+    var schedulable = DataLayer.get('schedulable', ''+eventID);
+    var edit = {repeat: (DataLayer.get('repeat', schedulable.repeat))};                                   
+
+    edit.repeat.startTime = new Date(parseInt(edit.repeat.startTime)).toString('yyyy-MM-dd HH:mm:00');
+    edit.repeat.endTime = new Date(parseInt(edit.repeat.endTime)).toString('yyyy-MM-dd HH:mm:00');
+    
+    edit.repeat.exceptions = (schedulable.occurrences[idException]);         
+    
+    return edit.repeat;
+
+}
+
+function remove_ocurrence(eventId, idRecurrence){
+	$.Zebra_Dialog('Tem certeza que deseja excluir esta ocorrência?', {
+		'type':     'question',
+		'overlay_opacity': '0.5',
+		'buttons':  ['Sim', 'Não'],
+		'onClose':  function(clicked) {
+			if(clicked == 'Sim'){
+                            var repeat = mount_exception(eventId, idRecurrence);
+                            DataLayer.remove('repeat', false);
+                            DataLayer.put('repeat', repeat);
+                            DataLayer.commit(false, false, function(data){
+                                Calendar.rerenderView(true);
+                            });
 			}
 		}
@@ -2139,15 +2190,25 @@
 }
 
-function copyAndMoveTo(calendar, eventId){
-
-    var type = $('.calendar-copy-move input[name="typeEvent"]').val();
-
-	var schedulable = DataLayer.get('schedulable' , ''+eventId);
-	
+function copyAndMoveTo(calendar, event, idRecurrence, type, evt){
+    /*
+     * Types
+     * 0 = Move
+     * 1 = Copy Event end Repet
+     * 2 = Copy Ocurrence
+     * 3 = Copy to edit ocurrence
+     * 
+     **/
+    if(!type)
+        type = $('.calendar-copy-move input[name="typeEvent"]').val();
+
+	var schedulable = DataLayer.get('schedulable', event+'');
+	
+        calendar = !!calendar ? calendar : schedulable.calendar;
+        
 	if(typeof(schedulable) == "array")
 		schedulable = schedulable[0];
 	
 	//Move eventos entre agendas
-	if(!!parseInt(type)){
+	if(parseInt(type) == 0){
 		
 		schedulable.calendar = calendar;	
@@ -2164,16 +2225,39 @@
 		delete newSchedulable.sequence;
 		delete newSchedulable.dtstamp;
-		delete schedulable.calendar;
+		
 		delete schedulable.DayLigth;
 		delete schedulable.rangeStart
 		delete schedulable.rangeEnd;
 		delete schedulable.lastUpdate;
-		delete schedulable.repeat;
-	
-
+                
+                delete schedulable.calendar;
+                
+		if(schedulable.repeat && type == "1" ){
+                    var repeat = DataLayer.get('repeat', schedulable.repeat);
+                    delete repeat.schedulable;
+                    delete repeat.id;
+                    repeat.startTime = new Date(parseInt(repeat.startTime)).toString('yyyy-MM-dd HH:mm:00');
+                    repeat.endTime = new Date(parseInt(repeat.endTime)).toString('yyyy-MM-dd HH:mm:00');
+                    
+                    var exceptions = DataLayer.get('repeatOccurrence', {filter: ['AND', ['=','repeat', schedulable.repeat], ['=','exception','1']]}, true);
+                    if(exceptions){
+                        repeat.exceptions = '';
+                        for(var i in exceptions )
+                            repeat.exceptions += exceptions[i].occurrence + ((exceptions.length -1) == parseInt(i) ? '' : ',');
+                            
+                    }
+                    
+                    
+                    schedulable.repeat = repeat;
+                }else{
+                    if(!!idRecurrence){
+                        newSchedulable.endTime = parseInt(schedulable.occurrences[idRecurrence]) + (parseInt(newSchedulable.endTime) - parseInt(newSchedulable.startTime));
+                        newSchedulable.startTime = schedulable.occurrences[idRecurrence];
+                    }
+                    delete schedulable.repeat;
+                }
+                delete schedulable.occurrences;
+                
 		schedulable.calendar = DataLayer.copy(calendar);	
-	
-		newSchedulable.endTime = new Date(parseInt(newSchedulable.endTime) - (newSchedulable.allDay ? 86400000 : 0)).toString('yyyy-MM-dd hh:mm:00');
-		newSchedulable.startTime = new Date(parseInt(newSchedulable.startTime)).toString('yyyy-MM-dd hh:mm:00'); 
 		
 		var participants = DataLayer.copy(schedulable.participants);
@@ -2182,15 +2266,26 @@
 		schedulable.participants =  $.map( participants, function( attendee, i ){
 			
-			var participant = DataLayer.get('participant', attendee);
+			var participant = DataLayer.get('participant', attendee, false);
 			
 			if(typeof(participant) == 'array')
-				participant = participant[0];
-	
+                            participant = participant[0];
+	
+                        delete participant.delegatedFrom;
 			delete participant.id;
+                        delete participant.schedulable;
+                        
+                        participant.id = DataLayer.put('participant', participant);
 			
 			return participant ;
-        });
-	
-	
+                });
+                //Edit ocurrence
+                if(parseInt(type) == 3){
+                    newSchedulable.endTime = !!evt.end  ? evt.end.getTime() :  ((evt.start).getTime() + 86400000);
+                    newSchedulable.startTime = evt.start.getTime(); 
+                    
+                    return newSchedulable;
+                }
+                newSchedulable.endTime = new Date(parseInt(newSchedulable.endTime) - (newSchedulable.allDay ? 86400000 : 0)).toString('yyyy-MM-dd hh:mm:00');
+                newSchedulable.startTime = new Date(parseInt(newSchedulable.startTime)).toString('yyyy-MM-dd hh:mm:00'); 
 	
 		DataLayer.put('schedulable', newSchedulable);
Index: trunk/prototype/modules/calendar/js/init.js
===================================================================
--- trunk/prototype/modules/calendar/js/init.js	(revision 5592)
+++ trunk/prototype/modules/calendar/js/init.js	(revision 5746)
@@ -231,29 +231,92 @@
 		},
 
-		eventDrop: function( event ){
-			if(!event.disableDragging){
-				DataLayer.put( "schedulable:calendar", event );
+		eventDrop: function( evt, event, view  ){
+			evt.id = evt.id.split('-')[0];
+                        if(!evt.disableDragging){
+                            
+                             if(evt.isRepeat){
+                                 var schedulable = copyAndMoveTo(false , evt.id , false, "3", evt);
+                                 
+                                 var repeat = mount_exception(evt.id, evt.occurrence);
+                                 DataLayer.remove('repeat', false);
+                                 DataLayer.put('repeat', repeat);
+                                 DataLayer.commit('repeat', false, function(data){
+                                     
+                                    DataLayer.put('schedulable', schedulable);
+                                     
+                                 });
+
+                             }else{                                 
+                                DataLayer.put( "schedulable:calendar", evt );
 
 				event.editable = false;
 				event.className = "blocked-event";
-				calendar.fullCalendar( 'updateEvent', event );
+				calendar.fullCalendar( 'updateEvent', evt );
+                             }
+                             
+			}else
+                            Calendar.rerenderView(true);
+		},
+
+		eventResize: function( evt, event, view ){
+                        evt.id = evt.id.split('-')[0];
+			if(!evt.disableDragging){
+                             if(evt.isRepeat){
+                                 var schedulable = copyAndMoveTo(false , evt.id , false, "3", evt);
+                                 
+                                 //Normaliza a data para o backend
+                                 schedulable.startTime = new Date(parseInt(schedulable.startTime)).toString('yyyy-MM-dd hh:mm:00');
+                                 schedulable.endTime = new Date(parseInt(schedulable.endTime)).toString('yyyy-MM-dd hh:mm:00');
+                                 
+                                 var repeat = mount_exception(evt.id, evt.occurrence);
+                                 
+                                 DataLayer.remove('repeat', false);
+                                 DataLayer.put('repeat', repeat);
+                                 DataLayer.commit('repeat', false, function(data){
+                                     
+                                    DataLayer.put('schedulable', schedulable);
+                                     
+                                 });
+                             }else{                                 
+                                DataLayer.put( "schedulable:calendar", evt );   
+                                evt.editable = false;
+                                evt.className = "blocked-event";
+                                calendar.fullCalendar( 'updateEvent', evt );
+                             }
+                        
 			}else
 				Calendar.rerenderView(true);
 		},
 
-		eventResize: function( event ){
-			if(!event.disableDragging){
-			DataLayer.put( "schedulable:calendar", event );
-
-			event.editable = false;
-			event.className = "blocked-event";
-			calendar.fullCalendar( 'updateEvent', event );
-			}else
-				Calendar.rerenderView(true);
-		},
-
 		eventClick: function( evt, event, view ){
-			if(evt.selectable)
-				eventDetails( DataLayer.get( "schedulable", evt.id), true);
+			evt.id = evt.id.split('-')[0];
+                        if(evt.selectable){
+                            if(evt.isRepeat){
+                                $.Zebra_Dialog(evt.title + ' é um evento com repetição.', {
+                                        'type':     'question',
+                                        'overlay_opacity': '0.5',
+                                        'buttons':  ['Editar todas ocorrências', 'Editar essa ocorrência'],
+                                        'onClose':  function(clicked) {
+                                                if(clicked == 'Editar todas ocorrências') {
+                                                    eventDetails( DataLayer.get( "schedulable", evt.id), true);
+                                                }else{
+                                                    /*
+                                                    * TODO - repeat foi adicionado pois melhorias devem ser feitas no rollback do
+                                                    *DataLayer, repeat somente é usado quando se trata da criação de um evento
+                                                    *pela edição de uma ocorrência.
+                                                    */      
+                                                    var repeat = mount_exception(evt.id, evt.occurrence);
+                                                                                                  
+                                                    $('.calendar-copy-move input[name="typeEvent"]').val("3");
+                                                    
+                                                    eventDetails(copyAndMoveTo(false , evt.id , false, "3", evt), true, '', false, repeat);
+                                                }       
+                                        }
+                                });
+                                
+                            }else
+                                eventDetails( DataLayer.get( "schedulable", evt.id), true);
+                                
+                        }
 		}
 	}, dateCalendar));
