<?php
/**
 * FIT Fixture: ActionFixture
 * 
 * $Id$
 * 
 * @author gERD Schaufelberger <gerd@php-tools.net>
 * @package FIT
 * @subpackage Fixture
 * @license LGPL http://www.gnu.org/copyleft/lesser.html
 */

/**
 * FIT Fixture: ActionFixture
 * 
 * An action fixture interprets rows as a sequence of commands to be performed 
 * in order. It interprets tables for which the first column contains one of a
 * small number of commands. Subsequent columns contain values interpreted by 
 * the particular command. The generic action fixture offers only four commands, 
 * but subclasses may extend this set.
 * 
 * @version 0.1.0
 * @package FIT
 * @subpackage Fixture
 */
class Testing_FIT_Fixture_Action extends Testing_FIT_Fixture 
{
   /**
    * column iterator
    * @var object
    */
    protected $_cells;

   /**
    * actor that has been startet
    * 
    * The actor is static to make HTML tables "interuptable"
    * This way a table may end, another start and you are still at the same 
    * fixture.
    * 
    * @var Fixture
    * @see start()
    * @todo is static actors the intended behavior?
    */
	protected static $actor = null;
	
   /**
    * Implements start fixture 
    * 
    * Start aClass - Subsequent commands are directed to an instance of 
    * aClass. This is similar to navigating to a particular GUI screen.
    * 
    * @return void
    */       
    public function start() 
    {
        $this->_cells->next();
        $aClass         = $this->_cells->current();
        self::$actor    = Testing_FIT_Fixture::loadFixture( $aClass );
    }
    
   /**
    * Implements enter fixture 
    * 
    * Enter aMethod anArgument - Invoke aMethod with anArgument (of type 
    * determined by aMethod.) This is similar to entering values into GUI fields.
    * 
    * @return void
    */       
    public function enter() 
    {
        $this->_cells->next();
        $aMethod    = $this->camel( $this->_cells->current() );
        
        $this->_cells->next();
        $anArgument = $this->_cells->current();
        
        self::$actor->$aMethod( $anArgument );
    }
    
   /**
    * Implements press fixture 
    * 
    * Press aMethod - Invoke aMethod with no arguments. This is 
    * similar to pressing a GUI button.
    * 
    * @return void
    */       
    public function press() 
    {
        $this->_cells->next();
        $aMethod    = $this->camel( $this->_cells->current() );
        
        self::$actor->$aMethod();
    }

   /**
    * Implements check fixture 
    * 
    * Check aMethod aValue - Invoke aMethod with no arguments. 
    * Compare the returned value with aValue. This is similar to reading 
    * values from a GUI screen.
    * 
    * @return void
    */       
    public function check() 
    {
        $this->_cells->next();
        $aMethod    = $this->camel( $this->_cells->current() );
        
        $result     = self::$actor->$aMethod();
        
        $this->_cells->next();
        $this->_checkCell( $this->_cells, $result );
    }
    
   /**
    * process cells
    *
    * In case of ActionFixture each row has to be interpreted as a command
    * Processing cells means to execute one command. 
    *
    * An action fixture interprets tables for which the first column contains 
    * one of a small number of commands. Subsequent columns contain values 
    * interpreted by the particular command. The generic action fixture offers 
    * only four commands, but subclasses may extend this set.
    * 
    * @param object $node
    * @return boole true on success
    */
	public function doCells( Testing_FIT_Node $node ) 
    {
        $this->_cells  = $node->getRowIterator();
        
        // first cell is the method to be called
        $method  = $this->_cells->current();
        
        try{ 
            if( !method_exists( $this, $method ) ) {
                throw new Exception( 'Action fixture cannot call the request command. Method ' 
                    . get_class( $this ) . '->' . $method . ' does not exist' );
            }
            $this->$method();            
		} 
        catch( Exception $e ) {
            $this->_cells->markException( $e );
        }
        
        $this->_cells->next();
        return true;
	}
}
?>