= 1.6 * * @copyright (c) 2007-2012 OSI * @license Licensed under the CeCILL 2.0 * @link http://wiki.audean.com/fsm/fsm */ error_reporting(E_ALL|E_STRICT); /** * Base application class for an application able to perform background work * based on an OSInet FSM (finite state machine). * Concrete implementations should include a constructor defining the * backgroundGoals array along the FSM graph. */ abstract class BackgroundApplication { /** * Trace operation to stdout * * @var boolean */ public $backgroundTrace = FALSE ; /** * This is the FSM sequencing the background operation * @var Machine */ public $finiteStateMachine; /** * event name for background work along the FSM * @var string */ public $backgroundPath = NULL; /** * gtk::idle_add/idle_remove id * @var int */ protected $_backgroundId; /** * path/state pairs * * These define the various background trajectories available for background * work within the FSM graph. In each pair, the "path" is the constant event * string applying until a goal is reached, and the "goal" is the terminating * state for the background work. * Sample: * $backgroundGoals = array('up' => 'live', 'down' => 'final'); * * @var array */ public $backgroundGoals = NULL; /** * Perform background work. Must return TRUE to be invoked again. * Do NOT loop inside: this freezes the event loop. Return instead, the * function will be invoked again anyway. * * It has to be public, otherwise gtk can't invoke it after idle_add. * * Returning false disables background work without removing it. * * @throws Exception [if background work is requested without a goals array] * @return boolean */ public function backgroundDo() { $ret = TRUE; while(Gtk::events_pending()) Gtk::main_iteration(); if (!is_array($this->backgroundGoals)) throw new Exception('Background_Application needs an array of goals to be set before background work can run.'); $msg = "background work: "; $event = $this->backgroundPath; if (!array_key_exists($event, $this->backgroundGoals)) { $msg = "Nothing to do for now. Stop idling"; $ret = FALSE; } elseif ($this->finiteStateMachine->getState() != $this->backgroundGoals[$event]) { $msg .= "state " . $this->finiteStateMachine->getState() . "($event)"; $result = $this->finiteStateMachine->applyEvent($event); $msg .= "[$result->fsmReturn] => $result->fsmState"; if (!empty($result->fsmAction)) $msg .= " / $result->fsmAction"; } else { $msg .= "End of scheduled work"; $this->backgroundStop(); $ret = FALSE; } if ($this->backgroundTrace) echo $msg . PHP_EOL; return $ret; } /** * Activate background processing along an event path * * @throws Exception [if background work is requested without a goals array] * @param string $path * @return void */ function backgroundStart($path = NULL) { if (!is_array($this->backgroundGoals)) throw new Exception('Background_Application needs an array of goals to be set before background work can be started.'); $this->backgroundPath = $path; $this->_backgroundId = Gtk::idle_add(array($this, 'backgroundDo')); } /** * Stop idle processing and remove idle processor * @return void */ function backgroundStop() { Gtk::idle_remove($this->_backgroundId); $this->_backgroundId = NULL; } }