PlotMgr.php 12.2 KB
<?php
/**
 * @class PlotMgr
 * @brief Interactive Plot session
 * @version $Id: PlotMgr.php 2412 2014-06-10 09:47:41Z natacha $
 *    
 */


   class PlotMgr  {
	
	protected $currentInt, $totalInt, $ttName;
	protected $TimeTableMgr;

//DD notation 'YYYY:DOY:HH:MM:SS' DOY => DOY-1
        protected function getDdTime($date) {
	    $ddStart = getdate(strtotime($date));
	    $DDTime = sprintf("%04d",$ddStart['year']).':'.sprintf("%03d", $ddStart['yday']).':'.
		      sprintf("%02d",$ddStart['hours']).':'.sprintf("%02d",$ddStart['minutes']).':'.
		      sprintf("%02d",$ddStart['seconds']);

	  return $DDTime;
       } 
 /* Stop Time from StartTime and Interval*/ 
	protected function getStopTime($startDate, $interval){
		$time = strtotime($startDate) + $interval;		 
		$stopTime =  date('Y-m-d',$time).'T'.date('H:i:s',$time);

		return $stopTime;
	  }
 /* StartTime from StopTime and Interval*/ 
	protected function getStartTime($stopDate, $interval){

		$time = strtotime($stopDate) - $interval;
 		$startTime =  date('Y-m-d',$time).'T'.date('H:i:s',$time);

		return $startTime;
	  }

/* get  Interval*/
//TODO make session info file ??? 
	protected function getTimeInt($requestName){

                    $requestFile = file($requestName);   		    
		    $nObjects = 2 + $requestFile[0]; 
                    $timeIntString = $requestFile[$nObjects]; 
                    $timeInt = explode(':', $timeIntString);

		    $interval = $timeInt[0]*86400 +
			    $timeInt[1]*3600 +
			    $timeInt[2]*60 + $timeInt[3];

		return $interval;
	  }


// Update StartTime in request 
          protected function updateStartTime($requestName, $start) {
	   
                $requestFile = file($requestName); 
                $request = fopen($requestName,'w');
         
		$nObjects = 1 + $requestFile[0]; 

		for ($k = 0; $k < $nObjects; $k++) fwrite($request,$requestFile[$k]);
		
		fwrite($request,$this->getDdTime($start).PHP_EOL);
		$timeIntString = $requestFile[$nObjects + 1];
	   	fwrite($request,$timeIntString);

                fclose($request);        
	}

	  protected function getNextTable($tabId, $step) {

	       $allTables = file('tt');

	       for ($i = 0; $i < count($allTables); $i++) {
		  $currTT = json_decode($allTables[$i]);
		  if ($currTT->id == $tabId) {
			  if (($i == count($allTables) - 1) && $step == 1) {
				  return null;
			  }
			  if (($i == 0) && $step == -1) {
				  return null;
			  }
			  $newTT = json_decode($allTables[$i+$step]);
			  $newTabId = $newTT->id;
			  $this->ttName = $newTT->timeTableName;
			  break;
		  }
		}
		$tt =$this->TimeTableMgr->loadIntervalsFromTT($newTabId);
		$intervals = $tt['intervals']; 
		$this->totalInt = $tt['totalCount'];
		 
		$ff = fopen('current', 'w');
		fwrite($ff, $this->totalInt.PHP_EOL);	   
		fwrite($ff,$allTables[$i+$step]);			     
		fclose($ff);
		return $intervals;
	  }

	  protected function getNewInterval($obj) {
 		 
		$currentInfo = file('current');
		$currInt = (int)$obj->action->arg1 - 1;
		$totalNum = $currentInfo[0];
		$ttObject = json_decode($currentInfo[1]);
		$this->TimeTableMgr = new TimeTableMgr();

                $ttType = (substr($ttObject->id,0,6) == 'shared') ?  'sharedtimeTable' : 'timeTable';
		$tt = $this->TimeTableMgr->loadIntervalsFromTT($ttObject->id, $ttType);
		$this->ttName = $ttObject->timeTableName;
	        $intervals = $tt['intervals'];

		$this->totalInt =  $tt['totalCount'];
		switch ($obj->action->name) {
		    case 'nextInt': 
			  $number = $currInt+1;
			  if ($number == $totalNum) {
			    $newIntervals =  $this->getNextTable($ttObject->id, 1);
			    if ($newIntervals) {
				      $number = 0;
				      $intervals = $newIntervals;
			    }
			    else
				    $number = $totalNum - 1;
			  }
			  break;
		    case 'backInt': 
			  $number = $currInt-1;
			  if ($number == -1) {
			    $newIntervals =  $this->getNextTable($ttObject->id,  -1);
			    if ($newIntervals) {
				      $intervals = $newIntervals;
				      $number = count($intervals)-1;  
				       
			    }
			    else
				    $number = 0;
			     
			  }
			  break;
		    case 'goto': 
			  $number = $currInt;
//TODO check another table ?
			  if ($number >= $totalNum) {
			    $number = $totalNum - 1;
			  }
			  break;
		    default:
		  }
		  $this->currentInt = $number+1;
		return  $intervals[$number];
	  }

// create file with 'zoom' intervals used in unzoom 
	protected function addZoomInterval($interval){
           $zoomFile = 'zoom_intervals';	   
	   $ff = fopen($zoomFile, 'a');
	   fwrite($ff,json_encode($interval).PHP_EOL);
	   fclose($ff);
	}

// remove 'zoom' intervals used in unzoom 
	protected function removeZoomInterval(){
           $zoomFile = 'zoom_intervals';
	   
	   $intervals = file($zoomFile);
	   if (!file_exists($zoomFile)) return null;

	   if (count($intervals) === 1) {
		  $currInt = json_decode($intervals[0]);
		  $interval['start'] = $currInt->start;
		  $interval['stop'] = $currInt->stop;
		   
		  return $interval;
	    }
	   $ff = fopen($zoomFile, 'w');
	   for  ($i = 0; $i < count($intervals)-1; $i++)
		      fwrite($ff,$intervals[$i]);
	   fclose($ff);
	   $currInt = json_decode($intervals[count($intervals)-2]);
	   $interval['start'] = $currInt->start;
	   $interval['stop'] = $currInt->stop;
	   return $interval;
	}

// reset start zoom on every action : next, back,...
	protected function resetZoomInterval($interval){
	    $ff = fopen('zoom_intervals','w');
	    fwrite($ff, json_encode($interval).PHP_EOL);
	    fclose($ff); 
	}

/*****************************************************************
*                           PUBLIC FUNCTIONS
*****************************************************************/

 public function rrmdir($dir){
		if (is_dir($dir)) {
		  $objects = scandir($dir);
	  
		  foreach ($objects as $object) { // Recursively delete a directory that is not empty and directorys in directory 
		    if ($object != "." && $object != "..") {  // If object isn't a directory recall recursively this function 
		      if (filetype($dir."/".$object) == "dir") 
			      $this->rrmdir($dir."/".$object);
		      else 
			      unlink($dir."/".$object);
		    }
		  }
		  reset($objects);
		  rmdir($dir);
		}
	      }  

// Delete 'interactive session' 
   public function deleteObject($obj) {
 
           $sessionID = substr($obj->id, 0, 5); 
 
           if (is_dir(USERWORKINGDIR.$sessionID.'_'))
                       $this->rrmdir(USERWORKINGDIR.$sessionID.'_');
 
             return array('id' => $sessionID);

   }

// interactive session
   public function execute($obj) {

	    $sessionID = $obj->resultId;	      

	    if (!is_dir(USERWORKINGDIR.$sessionID.'_'))
			return array('error' => 'interactive plot session was closed');

            $currDir = USERWORKINGDIR.$sessionID.'_/';
	    chdir($currDir);

// Interval or TimeTable session
	    if (file_exists('current')) {
			$isTimeTable = true;			
	    }
            else 
			$isTimeTable = false;

           if (!file_exists('request_.list'))
			return array('error' => 'interactive plot session was closed');

	   copy('request_.list', $sessionID);

           $action = $obj->action->name;
	   $interval = array();
           $reqMgr = new RequestMgr();
           $requestName = $sessionID;

	   $timeInt =  $this->getTimeInt($currDir.$requestName);
	   
		switch ($action) {
		    case 'next':   
			      $interval['start']  = $obj->action->arg1;			 
			      $interval['stop'] = $this->getStopTime($interval['start'], $timeInt);
			      $this->resetZoomInterval($interval);
			      $this->updateStartTime($currDir.$requestName, $interval['start']);
			    break;
		    case 'halfnext': 				 
			      $interval['stop'] = $this->getStopTime($obj->action->arg1, $timeInt/2);
			      $interval['start'] = $this->getStartTime($interval['stop'], $timeInt);
			      $this->resetZoomInterval($interval);
			      $this->updateStartTime($currDir.$requestName, $interval['start']);
			    break;
		    case 'back': 
			      $interval['stop']  = $obj->action->arg1;
			      $interval['start'] = $this->getStartTime($interval['stop'], $timeInt);
			      $this->resetZoomInterval($interval);
			      $this->updateStartTime($currDir.$requestName, $interval['start']);
			    break;
		    case 'halfback':			 
			      $interval['start'] = $this->getStartTime($obj->action->arg1, $timeInt/2);
			      $interval['stop']  = $this->getStopTime($interval['start'], $timeInt);
			      $this->resetZoomInterval($interval);
			      $this->updateStartTime($currDir.$requestName, $interval['start']);
			    break;
		    case 'nextInt':   			       
		    case 'backInt':   			       
		    case 'goto':
			      $interval = $this->getNewInterval($obj);
			      $this->resetZoomInterval($interval);
			      $reqMgr->updateTime($currDir.$requestName, $interval);
			    break;
		    case 'extend': 
			      $shift = $obj->action->arg1;
			      $interval['start'] = $this->getStartTime($obj->action->arg2, $shift);
			      $interval['stop']  = $this->getStopTime($obj->action->arg2, $timeInt+$shift);
			      $this->resetZoomInterval($interval);		      
			      $reqMgr->updateTime($currDir.$requestName, $interval);
			    break;
		    case 'shift': 
			      $shift = $obj->action->arg1;
			      $interval['start'] = $this->getStartTime($obj->action->arg2, (-1.)*$shift);
			      $interval['stop']  = $this->getStopTime($obj->action->arg2, $timeInt+$shift);
			      $this->resetZoomInterval($interval);		     
			      $reqMgr->updateTime($currDir.$requestName, $interval);
			      break;
		    case 'zoom': 
			      $requestName = 'zoom';
			      copy('request_.list', $requestName);
			      $interval['start'] = $obj->action->arg1;
			      $interval['stop'] = $obj->action->arg2;
			      $this->addZoomInterval($interval);
			      $reqMgr->updateTime($currDir.$requestName, $interval);
			    break;
		    case 'resetzoom': 
			      $interval = $this->removeZoomInterval();
			      copy('request_.list', $requestName);
			      if ($interval) 
				      $reqMgr->updateTime($currDir.$requestName, $interval);
			      else 
				    return array('warning' => 'to implement');
			    break;
		    case 'changetime': break;
		    default:
		      return array('error' => 'unknown action');
		  }
//TODO Delete *png ??? or use them ????
	  foreach (glob('Plot*.png') as $filename)  
					unlink($filename);
//TODO define user in AmdaAction constructor : SESSION_ID
	  $dd = new UserMgr();

	  if ($dd -> ddCheckUser() != 0)
	       return array('error' => 'sorry, your AMDA session was closed');

          $cmd = DDBIN."DD_Plot ".$requestName." ".$dd->user." ".$dd->IP." ".DDPROJECT." ".DDPROJLIB; 
          $pid =  $reqMgr->background($cmd);

	     $jobMgr = new JobsMgr(); 	    
//TODO return ERRORS also
            for ($cycle = 0; $cycle < PLOT_CYCLES_NUMBER; $cycle++) {
                    sleep(JOBTIMEOUT);

                    if ( is_dir(USERWORKINGDIR."CANCELPLOT") ) {
                    if (file_exists(USERWORKINGDIR."CANCELPLOT/".substr($sessionID,4,1)))
                                    rename(USERWORKINGDIR."CANCELPLOT/".substr($sessionID,4,1),$currDir."/cancelplot");

                    if (count(scandir(USERWORKINGDIR."CANCELPLOT")) == 2) rmdir(USERWORKINGDIR."CANCELPLOT");

                    }

                    if (file_exists($currDir."/cancelplot"))
                    {
                      if (!$jobMgr->isFinished($pid))
                      { 
                        $cmd = 'kill -9 '.$pid;
                        exec($cmd);
                      }
                      
                       if (file_exists($currDir."/cancelplot"))
                          unlink($currDir."/cancelplot");
 
                        return array('error' => "Plot canceled!");
                   }

		   if ($jobMgr->isFinished($pid)) {
			$cachekiller = time();
                        rename($requestName.'.png', $sessionID.'_'.$cachekiller.'.png');
			$arrayMain = array('pid' => '0', 'name' => $sessionID.'_'.$cachekiller, 
				     'id' => $sessionID, 'startDate' => $interval['start'], 'stopDate' => $interval['stop']);

			if ($isTimeTable) {
				$arrayTable = array( 
						 'intervalN' =>  $this->currentInt, 
						 'totalN' => $this->totalInt,
						 'tableName' => $this->ttName);
				return array_merge($arrayMain, $arrayTable); 
			}
			return $arrayMain; 
		    }
	     } 
 
        $cmd = 'kill -9 '.$pid;
        exec($cmd);

      return array('error' => "too long : Plot canceled!");
  }
 }
?>