Index: trunk/prototype/modules/calendar/interceptors/DBMapping.php
===================================================================
--- trunk/prototype/modules/calendar/interceptors/DBMapping.php	(revision 5682)
+++ trunk/prototype/modules/calendar/interceptors/DBMapping.php	(revision 5715)
@@ -7,22 +7,21 @@
 class DBMapping extends Helpers {	
            
-    public function encodeCreateSchedulable( &$uri , &$params , &$criteria , $original ){			
-        $params['type_id'] = EVENT_ID;
-	
-	
-		if(!is_numeric($params['startTime']) )
-			$params['startTime'] =  strtotime( $params['startTime'] . ' ' .$params['timezone']).'000';
+    public function encodeCreateSchedulable( &$uri , &$params , &$criteria , $original ){
+	$params['type_id'] = EVENT_ID;
+
+	if(!is_numeric($params['startTime']) )
+	  $params['startTime'] =   self::parseTimeDate( $params['startTime'], $params['timezone'] ); 
 		
-		if (!is_numeric($params['endTime'])){
-			$params['endTime'] =   strtotime( $params['endTime'] . ' ' .$params['timezone']).'000';
-			
-			if($params['allDay'])
-				$params['endTime'] =  $params['endTime']  + 86400000;
-		}
+	if (!is_numeric($params['endTime'])){
+	  $params['endTime'] =    self::parseTimeDate( $params['endTime'], $params['timezone'] ); 
+
+	  if($params['allDay'])
+	    $params['endTime'] =  $params['endTime']  + 86400000;
+	}
     //        if( !isset( $new['repeat'] ))
     //            $new['range_end'] = '7287926400'; // 12/12/2200
     //        else
             $params['rangeEnd'] = $params['endTime'];
-			$params['rangeStart'] =  $params['startTime'];
+	    $params['rangeStart'] =  $params['startTime'];
 
             ///////////////////////////////////////////////////////////////////
@@ -32,6 +31,9 @@
             $params['type'] = EVENT_ID;
             $params['uid'] = isset($params['uid']) ? $params['uid'] : $this->_makeUid();
-            
-        }	
+    }
+
+    static function parseTimeDate($time, $timezone){
+	return strtotime( $time . ' ' .$timezone).'000';         
+   }	
 		
     public function encodeCreateAlarm( &$uri , &$params , &$criteria , $original ){
@@ -89,17 +91,240 @@
            if(isset($params['isExternal']) && $params['isExternal'] == '1')
                 $uri['service'] = 'PostgreSQL'; 
-    }  
+    }
+
+    public function prepareRepeat(&$uri , &$params , &$criteria , $original ){
+
+	  $timezone = Controller::read( array( 'concept' => 'schedulable', 'id' => $params['schedulable'] ), array('timezone') );
+	  $params['startTime'] = self::parseTimeDate( $params['startTime'], $timezone['timezone'] );
+	  $params['endTime'] = self::parseTimeDate( $params['endTime'], $timezone['timezone'] );
+    }
       
-   public function findSchedulable( &$uri , &$params , &$criteria , $original )
+    public function findSchedulable( &$uri , &$params , &$criteria , $original )
    {
        if(isset($criteria['filter'][3][1]) && $criteria['filter'][3][1] == 'calendar')
        {
-         $select = 'calendar_object.id as id ,calendar_object.cal_uid as "uid" , calendar_object.type_id as "type", calendar_object.dtstart as "startTime", calendar_object.summary as "summary", calendar_object.description as "description", calendar_object.dtend as "endTime" , calendar_object.location as "location", calendar_object.allday as "allDay", calendar_object.transp as "transparent", calendar_object.class_id as "class", calendar_object.repeat as "repeat", calendar_object.range_start as "rangeStart",calendar_object.range_end as "rangeEnd", calendar_object.last_update as "lastUpdate", calendar_object.dtstamp as "dtstamp", calendar_object.sequence as "sequence",  calendar_object.tzid as "timezone" ,calendar_to_calendar_object.calendar_id as calendar';
-         $sql = " SELECT $select FROM calendar_to_calendar_object , calendar_object WHERE (range_start >= '".$criteria['filter'][1][2]."' AND range_end <= '".$criteria['filter'][2][2]."' AND calendar_to_calendar_object.calendar_id IN ('".  implode('\',\'', $criteria['filter'][3][2])."')) AND calendar_to_calendar_object.calendar_object_id = calendar_object.id";
-         $params = Controller::service('PostgreSQL')->execResultSql($sql);
+	  $start = $criteria['filter'][1][2];
+	  $end = $criteria['filter'][2][2];
+
+         $sql = ' SELECT calendar_object.id as id ,calendar_object.cal_uid as "uid", calendar_object.type_id as "type", calendar_object.dtstart as "startTime", calendar_object.summary as "summary", calendar_object.description as "description", calendar_object.dtend as "endTime" , calendar_object.location as "location", calendar_object.allday as "allDay", calendar_object.transp as "transparent", calendar_object.class_id as "class", calendar_object.repeat as "repeat", calendar_object.range_start as "rangeStart",calendar_object.range_end as "rangeEnd", calendar_object.last_update as "lastUpdate", calendar_object.dtstamp as "dtstamp", calendar_object.sequence as "sequence",  calendar_object.tzid as "timezone" ,calendar_to_calendar_object.calendar_id as calendar FROM calendar_to_calendar_object , calendar_object WHERE (range_start >= \''.$start.'\' AND range_end <= \''.$end.'\' AND calendar_to_calendar_object.calendar_id IN (\''.  implode('\',\'', $criteria['filter'][3][2]).'\')) AND calendar_to_calendar_object.calendar_object_id = calendar_object.id';
+         
+	 $params = Controller::service('PostgreSQL')->execResultSql($sql);
          $params = self::deepnessFindEvent( &$uri , &$params , &$criteria , $original);
+
+	 $occ = self::checkOccurrences( $criteria['filter'][1][2], $criteria['filter'][2][2], intval($criteria['deepness']) + 1 );
+
+	 if( $occ )
+	    $params = array_merge( $params, $occ );
+
          return false;
        }
    }
+
+  public function deepnessFindRepeatOccurrence( &$uri , &$result , &$criteria , $original )
+  {
+
+    if( !isset($criteria['deepness']) || $criteria['deepness'] == 0 )
+	  return;
+
+      foreach( $result as $i => &$res )
+	  if( isset($res['repeat']) )
+	      $res['repeat'] = Controller::read( array( 'concept' => 'repeat', 'id' => $res['repeat'] ), false, array( 'deepness' => intval( $criteria['deepness'] ) - 1 ) );
+  }
+
+  public function deepnessRepeat( &$uri , &$result , &$criteria , $original )
+  {
+
+      if( !isset($criteria['deepness']) || $criteria['deepness'] == 0 )
+	  return;
+
+	$result['schedulable'] = Controller::find( array( 'concept' => 'schedulable' ), false, array( 'filter' => array( '=', 'id', $result['schedulable'] ), 'deepness' => intval( $criteria['deepness'] ) - 1 ) );
+	$result['schedulable'] = $result['schedulable'][0];
+  }
+
+public function saveOccurrences( &$uri , &$result , &$criteria , $original ){
+
+	$ranges = Controller::find( array( 'concept' => 'repeatRange' ), array( 'rangeStart', 'rangeEnd' ),  array( 'filter' => array( '=', 'user', Config::me("uidNumber") ) ) );
+
+	if( !is_array( $ranges ) || !isset( $ranges[0]['rangeStart'] ) || !isset( $ranges[0]['rangeEnd'] ) )
+	    return;
+
+	if( isset( $result['id'] ) )
+	     $id = $result['id'];
+	else
+	     $id = $uri['id']; 
+
+	$repeat = Controller::read( array( 'concept' => 'repeat', 'id' => $id ) );
+
+	unset( $repeat['schedulable'] );
+	unset( $repeat['id'] );
+
+	$params = self::decodeRepeat( $repeat, $ranges[0]['rangeStart'], $ranges[0]['rangeEnd'] );
+
+	Controller::delete( array( 'concept' => 'repeatOccurrence' ), false, array( 'filter' => array( '=', 'repeat', $id ) ) );
+
+	if( !empty($params) )
+	    Controller::service('PostgreSQL')->execResultSql( "INSERT INTO calendar_repeat_occurrence(repeat_id,occurrence)VALUES('".$id."', '".implode( "'),('".$id."','", $params )."')" );
+
+    }
+
+    public function checkOccurrences( $start, $end, $deep ){
+
+	$ranges = Controller::find( array( 'concept' => 'repeatRange' ), array( 'rangeStart', 'rangeEnd' ),  array( 'filter' => array( '=', 'user', Config::me("uidNumber") ) ) );
+	$ranges = $ranges[0];
+
+	$origStart = $start;
+	$origEnd = $end;
+
+	if( $initialized = (isset($ranges['rangeStart']) && isset($ranges['rangeEnd'])) )
+	{
+	    if( $ranges['rangeStart'] <= $start )
+		$start = false;
+	    if( $ranges['rangeEnd'] >= $end )
+		$end = false;
+	}
+
+	$repeats = self::findRepeats();
+
+	if( !is_array( $repeats ) || empty( $repeats ) )
+	    return( false );
+
+	$result = array();
+	$ids = array();
+
+	foreach( $repeats as $repeat )
+	{
+	    $ids[] = $id = $repeat['id']; unset( $repeat['id'] ); 
+
+	    if( !isset( $result[ $id ] ) )
+		$result[ $id ] = array();
+
+	    if( !$initialized )
+		$result[ $id ] = array_merge( $result[ $id ], self::decodeRepeat( $repeat, $start, $end ) );
+	    else
+	    {
+		if( $start )
+		    $result[ $id ] = array_merge( $result[ $id ], self::decodeRepeat( $repeat, $start, $ranges['rangeStart'] ) );
+
+		if( $end )
+		    $result[ $id ] = array_merge( $result[ $id ], self::decodeRepeat( $repeat, $ranges['rangeEnd'], $end ) );
+	    }
+
+	    if( empty( $result[ $id ] ) )
+		unset( $result[ $id ] );
+	}
+
+	if( $start || $end )
+	{
+	    Controller::begin( array( 'service' => 'PostgreSQL') );
+
+	    foreach( $result as $id => $res )
+		Controller::service('PostgreSQL')->execResultSql( "INSERT INTO calendar_repeat_occurrence(repeat_id,occurrence)VALUES('".$id."','".implode( "'),('".$id."', '", $res )."')" );
+
+	    $data = array();
+
+	    if( $start )
+		$data['rangeStart'] = $start;
+
+	    if( $end )
+		$data['rangeEnd'] = $end;
+
+	    if( !$initialized )
+		$data['user'] = Config::me( 'uidNumber' );
+
+	    Controller::call( ( $initialized ? 'replace' : 'create' ), array( 'concept' => 'repeatRange' ), $data, array( 'filter' => array( '=', 'user', Config::me('uidNumber') ) ) );
+
+	    Controller::commit( array( 'service' => 'PostgreSQL' ) );
+	}
+
+	$return = Controller::find( array( 'concept' => 'repeatOccurrence' ), false, array( 'filter' => array( 'AND', array( '>=', 'occurrence', $origStart ), array( '<=', 'occurrence', $origEnd ), array( 'IN', 'repeat', $ids ) ), 'deepness' => $deep ) );
+
+	if( !is_array( $return ) )
+	  return( false );
+
+	$result = array();
+	$params = array();
+
+	foreach( $return as $ret )
+	{
+	      $currentId = $ret['repeat']['schedulable']['id'];
+
+	      if( !isset( $result[ $currentId ] ) )
+	      {
+		    $result[ $currentId ] = $ret['repeat']['schedulable'];
+		    $result[ $currentId ][ 'occurrences' ] = array();
+  
+		    $calendarToCalendarObj = self::schedulable2calendarToObject( $currentId );
+
+		    $result[ $currentId ]['calendar'] = $calendarToCalendarObj[0]['calendar_id'];
+
+		    unset( $result[ $currentId ]['repeat'] );
+	      }
+      
+	      $result[ $currentId  ][ 'occurrences' ][] = $ret['occurrence'];
+
+	}
+
+	foreach( $result as $id => $res )
+	    $params[] = $res;
+
+	return( $params );
+    }
+
+    public static function findRepeats()
+    {
+	return Controller::service('PostgreSQL')->execResultSql( 'SELECT calendar_repeat.wkst as "wkst", calendar_repeat.byweekno as "byweekno", calendar_repeat.byminute as "byminute", calendar_repeat.bysecond as "bysecond", calendar_repeat.byyearday as "byyearday", calendar_repeat.bymonthday as "bymonthday", calendar_repeat.bysetpos as "bysetpos", calendar_repeat.byday as "byday", calendar_repeat.byhour as "byhour", calendar_repeat.interval as "interval", calendar_repeat.frequency as "frequency", calendar_repeat.until as "endTime", calendar_repeat.id as "id", calendar_repeat.count as "count", calendar_repeat.dtstart as "startTime" FROM calendar_repeat, calendar_participant WHERE calendar_repeat.object_id = calendar_participant.object_id AND calendar_participant.user_info_id = \''.Config::me('uidNumber').'\'' );
+    }
+	
+//HELPERS
+    public static function decodeRepeat( $repeat , $start , $end ) {
+
+    date_default_timezone_set( 'UTC' );
+
+    require_once ROOTPATH.'/plugins/when/When.php';
+
+    $r = new When();
+
+    if( $repeat['frequency'] === 'none' )
+	return( array() );
+
+    $start =  new DateTime( '@'.(int)( max( $start, $repeat['startTime']  ) / 1000 ), new DateTimeZone('UTC') );    
+
+    foreach($repeat as $rule => $value)
+    {
+	    if( !isset( $value ) || !$value || $value === "0" )
+		continue;
+
+            switch(strtolower($rule))
+            {
+		    case "starttime": break;
+		    case "frequency":
+			    $r->recur( $start, $value );
+			    break;
+		    case "endtime":
+                            $r->until( new DateTime( '@'.(int)( $value / 1000 ) ) );
+                            break;
+                    case "count": case "interval":  case "wkst":
+                            $r->$rule( $value );
+                            break;
+                    default :
+                            $r->$rule( !is_array( $value ) ? explode( ',' , $value ) : $value );
+                            break;
+            }
+    }
+
+    $return = array();
+
+    while($result = $r->next())
+    { 
+       $u = $result->format('U') * 1000;
+
+       if( $u  > $end ) //data da repetição atual maior que a data final da busca do usuario ?
+           break;
+
+      $return[] = $u;
+    }
+
+    return( $return );
+}
    
 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -200,5 +425,5 @@
      
 	 public function deepnessFindCalendarShared( &$uri , &$result , &$criteria , $original ){				
-		if(isset($original['criteria']['deepness']) && count($result) > 0){
+		if(isset($original['criteria']['deepness']) && $original['criteria']['deepness'] != '0' && count($result) > 0){
 			$calendarIds = array();
 			foreach($result as $key => $value)
@@ -234,5 +459,5 @@
     public function deepnessFindEvent( &$uri , &$result , &$criteria , $original ){		
 
-       if(isset($original['criteria']['deepness']))
+       if(isset($original['criteria']['deepness']) && $original['criteria']['deepness'] != 0)
        {
 			
@@ -286,16 +511,24 @@
 					
 					
-					
-					$attachmentRelation = Controller::find( array( 'concept' => 'schedulableToAttachment' ) , false ,array( 'filter' => array('=', 'schedulable'  ,  $v['id']) )); 
-					if(is_array($attachmentRelation)){
-						$attachments = array();
-						foreach($attachmentRelation as $key => $value)
-							if(isset($value['attachment']) || !!$value['attachment'])
-								$attachments[$key]  = $value['attachment'];
-						//Pega os anexos sem source
-						$result[$i]['attachments'] = Controller::find( array( 'concept' => 'attachment' ) , array('id', 'name', 'type', 'size') ,array( 'filter' => array('IN', 'id' , $attachments) )); 
-					}
-				
-				}               
+		    
+		    $attachmentRelation = Controller::find( array( 'concept' => 'schedulableToAttachment' ) , false ,array( 'filter' => array('=', 'schedulable'  ,  $v['id']) )); 
+		    if(is_array($attachmentRelation)){
+			    $attachments = array();
+			    foreach($attachmentRelation as $key => $value)
+				    if(isset($value['attachment']) || !!$value['attachment'])
+					    $attachments[$key]  = $value['attachment'];
+			    //Pega os anexos sem source
+			    $result[$i]['attachments'] = Controller::find( array( 'concept' => 'attachment' ) , array('id', 'name', 'type', 'size') ,array( 'filter' => array('IN', 'id' , $attachments) )); 
+		    }
+
+		    if(isset($result[$i]['repeat'])){
+		      $repeat = Controller::read( array( 'concept' => 'repeat', 'id' => $result[$i]['repeat'] ) );
+
+		      if( !is_array($repeat) )
+			  unset( $result[$i]['repeat'] );
+		      else
+			  $result[$i]['repeat'] = $repeat[0];
+		    }
+	    }               
                 
            }
@@ -309,5 +542,5 @@
     public function deepnessReadEvent( &$uri , &$result , &$criteria , $original ){		
        
-       if(isset($original['criteria']['deepness']))
+       if(isset($original['criteria']['deepness']) && $original['criteria']['deepness'] != 0)
        {
             if(isset($result['id']))
@@ -334,5 +567,5 @@
     public function deepnessReadParticipant( &$uri , &$result , &$criteria , $original ){		
        
-       if(isset($original['criteria']['deepness']))
+       if(isset($original['criteria']['deepness']) && $original['criteria']['deepness'] != 0)
        {
             if(isset($result['id']))
@@ -350,5 +583,5 @@
     public function deepnessFindParticipant( &$uri , &$result , &$criteria , $original ){		
        
-       if(isset($original['criteria']['deepness']))
+       if(isset($original['criteria']['deepness']) && $original['criteria']['deepness'] != 0)
        {
            foreach ($result as $i => $v)
@@ -369,5 +602,5 @@
     public function deepnessReadCalendarSignature( &$uri , &$result , &$criteria , $original ){		
        
-       if(isset($original['criteria']['deepness']))
+       if(isset($original['criteria']['deepness']) && $original['criteria']['deepness'] != 0)
             if(isset($result['calendar'])){
                 $result['calendar'] = Controller::read( array( 'concept' => 'calendar' , 'id' => $result['calendar'])); 
@@ -380,5 +613,5 @@
     public function deepnessFindCalendarSignature( &$uri , &$result , &$criteria , $original ){		
 
-	if(isset($original['criteria']['deepness']))
+	if(isset($original['criteria']['deepness']) && $original['criteria']['deepness'] != 0)
        {
            foreach ($result as $i => $v)
@@ -387,5 +620,5 @@
                     $result[$i]['calendar'] = Controller::read( array( 'concept' => 'calendar' , 'id' => $v['calendar']), false, false); 
 					$result[$i]['defaultAlarms'] = Controller::find( array( 'concept' => 'calendarSignatureAlarm' ) , false ,array( 'filter' => array('=', 'calendarSignature'  ,  $v['id']) ));    
-					//Caso não seja o dono da agenda retorna o objeto permission com as acls
+					//Caso nÃ£o seja o dono da agenda retorna o objeto permission com as acls
 					if($result[$i]['isOwner'] == 0){
 						$permission = Controller::find( array( 'concept' => 'calendarToPermission'), false ,array( 'filter' => array('AND', array('=', 'calendar' ,  $v['calendar']), array('=', 'user', Config::me('uidNumber') ) ) ) ); 
@@ -504,5 +737,5 @@
                      )));
             
-            return false; /* Mata o restante da execução */
+            return false; /* Mata o restante da execuÃ§Ã£o */
         } 
         
@@ -541,5 +774,5 @@
     public function createDefaultSignature( &$uri , &$result , &$criteria , $original ){
     		     
-    //Caso uma busca não retorne nenhum resultado e foi buscado pelas assinaturas do usuario logado apenas
+    //Caso uma busca nÃ£o retorne nenhum resultado e foi buscado pelas assinaturas do usuario logado apenas
     if(count($result) <= 0 && 
             ( $original['criteria']['filter'][0] == '=' &&
@@ -592,7 +825,7 @@
         else
         {
-         //Criaremos uma agenda parão
+         //Criaremos uma agenda parÃ£o
           $cal = array('name' => 'Calendario',
-                         'description' => 'Calendario Padrão',
+                         'description' => 'Calendario PadrÃ£o',
                          'timezone' =>  (date_default_timezone_get()) ? date_default_timezone_get() : 'America/Sao_Paulo',
                          'dtstamp' => time().'000'
@@ -681,5 +914,5 @@
                     continue;
                 
-                //Criação do ical
+                //CriaÃ§Ã£o do ical
                 $ical = null;
               	$ical = new vcalendar();
@@ -702,5 +935,5 @@
 				///////////////////////////////////////////////////////////////////////////
                 
-                //Criação do E-mail
+                //CriaÃ§Ã£o do E-mail
                 $mail = array();
                 $mail['isHtml'] = true;  
@@ -719,6 +952,6 @@
                                                         ),ROOTPATH.'/api/templates/notify_create_body.tpl');
                 
-                //TODO: Internacionalização do Subject
-                $mail['subject'] = 'Schedulableo do Calendário : '.$schedulable['summary'] .' @ '.date_format( $sTime , 'd/m/Y H:i') . ' - ' .  date_format( $eTime , 'd/m/Y H:i');
+                //TODO: InternacionalizaÃ§Ã£o do Subject
+                $mail['subject'] = 'Schedulableo do CalendÃ¡rio : '.$schedulable['summary'] .' @ '.date_format( $sTime , 'd/m/Y H:i') . ' - ' .  date_format( $eTime , 'd/m/Y H:i');
                 $mail['from'] =  $organizer['mail'];
                 $mail['to'] = $att[$i]['mail'];
@@ -759,74 +992,5 @@
         }
     }
-	
-//HELPERS
-    private static function decodeRepeat( $repeat , $start , $end ) {
-    require_once ROOTPATH.'/plugins/when/When.php';
-
-    $r = new When();
-    $r->recur( new DateTime( '@'.$start , new DateTimeZone('UTC') ), $repeat['frequency'] );
-
-    foreach($repeat as $rule => $value)
-    {                  
-            switch(strtoupper($rule))
-            {
-                    case "ENDTIME":
-                            $r->until( new DateTime( '@'.$value ) );
-                            break;
-                    case "COUNT":
-                            $r->count( $value );
-                            break;
-                    case "INTERVAL":
-                            $r->interval( $value );
-                            break;
-                    case "BYDAY":
-                            if( !is_array( $value ) )
-                                $value = explode( ',' , $value );
-                            $r->byday( $value );
-                            break;
-                    case "BYMONTHDAY":
-                           if( !is_array( $value ) )
-                                $value = explode(',' , $value );
-                            $r->bymonthday($value);
-                            break;
-                    case "BYYEARDAY":
-                              if( !is_array( $value ) )
-                                $value = explode(',', $value );
-                            $r->byyearday( $value );
-                            break;
-                    case "BYWEEKNO":
-                             if(!is_array( $value ))
-                                $value = explode( ',', $value );
-                            $r->byweekno( $value );
-                            break;
-                    case "BYMONTH":
-                             if( !is_array( $value ) )
-                                $value = explode( ',', $value );
-                            $r->bymonth( $value );
-                            break;
-                    case "BYSETPOS":
-                             if( !is_array( $value ) )
-                                $value = explode( ',' , $value );
-                            $r->bysetpos( $value );
-                            break;
-                    case "WKST":
-                            $r->wkst( $value );
-                            break;
-            }
-    }
-
-    $return = array();
-
-    while($result = $r->next())
-    { 
-       $u = $result->format('U');
-       if( $u  > $end ) //data da repetição atual maior que a data final da busca do usuario ?
-           break;
-
-      $return[] =  $u;
-    }
-
-    return $return;
-}
+
     private function _makeUid() {
 
@@ -888,5 +1052,5 @@
     private static function schedulable2calendarToObject($Schedulable)
     {
-      return Controller::service('PostgreSQL')->execResultSql('SELECT calendar_to_calendar_object.id as calendar_to_calendar_Object , calendar.name as calendar_name ,calendar.location as calendar_location FROM calendar_to_calendar_object , calendar , calendar_signature' 
+      return Controller::service('PostgreSQL')->execResultSql('SELECT calendar_to_calendar_object.id as calendar_to_calendar_Object , calendar.name as calendar_name ,calendar.location as calendar_location, calendar.id as calendar_id FROM calendar_to_calendar_object , calendar , calendar_signature' 
                 .' WHERE calendar_signature.user_uidnumber = '.$_SESSION['wallet']['user']['uidNumber']
                 .' AND calendar_signature.is_owner = 1'
