<?php
/**
 * FIT Fixture: Summary
 * 
 * $Id$
 * 
 * @author gERD Schaufelberger <gerd@php-tools.net>
 * @author Daniel Jahnke <jahnke.daniel@web.de>
 * @package FIT
 * @subpackage Fixture
 * @license LGPL http://www.gnu.org/copyleft/lesser.html
 */

/**
 * FIT Fixture: Summary
 * 
 * Summery fixture summs up the results of the tables. Hence it is not
 * a table holding test data but a place to put results.
 *
 * @version 0.1.1
 * @package FIT
 * @subpackage Fixture
 */
class Testing_FIT_Fixture_Summary extends Testing_FIT_Fixture 
{

   /**
    * summary of tables
    * @var array
    */
    private $_summary;

   /**
    * number of rows
    * @var int
    */
    private $_rows;

   /**
    * number of cols
    * @var int
    */
    private $_cols;
    
   /**
    * parser object
    * @var object
    */
    private $_parser;

   /**
    * integer-object to validate cell-values
    * @var object
    */
    private $_integer;

   /**
    * actual summary
    * @var int
    */
    private static $_actualSummary = 0;

   /**
    * before summary
    * @var int
    */
    private static $_beforeSummary = 0;

   /**
    * node
    * @var object 
    */
    private $_node;

   /**
    * resultMarks contain the right, wrong, ... values
    * @var array
    */
    private $_resultMarks;

   /**
    * constructor
    *
    * creates neede type-filter to validate cell-values
    */
    public function __construct()
    {
        $this->_integer = Testing_FIT_TypeFilter::create( 'Integer' );
    }

   /**
    * iterate through table 
    * 
    * @param object $node
    * @return boolean true on success
    * @see doRows()
    */
    public function doRows( Testing_FIT_Node $node )
    {
        $this->_node    = $node;
        $this->_summary = $node->getSummary();
        $this->_parser  = $node->getParser();

        $this->_tableCount          = $this->_summary->countChildNodes() - 1;

        for( $i = 0; $i <= $this->_tableCount; $i++ ) {
            $tableName = $this->_summary->getNodeValue( 'attributes', $i, 0, 0 );
            if( !$tableName['noSummary']  && ( $i > self::$_actualSummary ) ) {
                self::$_beforeSummary = self::$_actualSummary;
                self::$_actualSummary = $i;
                break;
            }
        }

        $this-> _buildSummaryTable();

        $beginTest = 0;
        $endTest   = 0;

        $this->_resultMarks = $this->_createSummary( $beginTest, $endTest );

        $i = 0;
        foreach( $this->_resultMarks as $key =>  $value ) {
            // set right wrong ignore exception headeline
            $this->_parser->setNodeValue( 'cData', $key, self::$_actualSummary, 1, ++$i );
            // set values 
            $this->_parser->setNodeValue( 'cData', $this->_integer->out( $value ), self::$_actualSummary, 2, $i );
        }

        // set elapsed time
        $duration = $endTest - $beginTest;
        $duration = round( $duration * 1000, 6 );
        $this->_parser->setNodeValue( 'cData', $duration . ' ms', self::$_actualSummary, 3, 1 );

        // set date
        $this->_parser->setNodeValue( 'cData', gmdate( 'Y-m-d H:i:s' ), self::$_actualSummary, 4, 1 );

        if( !$this->doRow( $this->_node ) ) {
            return false;
        }

        return true;
    }

   /**
    * process cells
    *
    * Generic processing of all upcoming cells. Actually, this method
    * just iterates through them and mark the cells on summary dependency
    * 
    * @param object $node 
    * @return boolean true on success
    */
    public function doCells( Testing_FIT_Node $node ) 
    {
        // jump over first two rows
        $this->_node->next();
        $this->_node->next();

        $cells  = $node->getRowIterator();
        foreach( $cells as $no => $cdata ) {
            // to jump over description row
            if( $no == 0 ) {
                continue;
            }

            switch( $no ) {
                case 1: // right cell
                    $cdata > 0 ? $cells->mark( 'right' ) : $cells->mark( 'wrong', $cdata );
                    break;
                case 2: // wrong cell
                    $cdata == 0 ? $cells->mark( 'right' ) : $cells->mark( 'wrong' );
                    break;
                case 3: // error cell
                    $cdata == 0 ? $cells->mark( 'right' ) : $cells->mark( 'error' );
                    break;
                case 4: // ignore cell
                    $cdata == 0 ? $cells->mark( 'right' ) : $cells->mark( 'ignore' );
                    break;
                case 5:
                    $cdata == 0 ? $cells->mark( 'right' ) : $cells->mark( 'exception' );
                    break;
                default:
                    return false;
            }
        }

        return true;
    }

   /**
    * create summary
    *
    * walk through the tables and count the wrong,
    * right, ignore and exceptions
    * 
    * @return array resultMarks     result of counting the testresult
    */
    private function _createSummary( &$beginTest, &$endTest )
    {
        $resultMarks = array( 
                        'right'      => 0,
                        'wrong'      => 0,
                        'error'      => 0,
                        'ignore'     => 0,
                        'exception'  => 0,
                        'time'       => 0
                            );

        for( $table = self::$_beforeSummary ; $table < self::$_actualSummary; $table++ ) {

            // if fit summary then conitune
            $attrib = $this->_summary->getNodeValue( 'attributes', $table, 0, 0 );
            if( !isset( $attrib['noSummary'] ) && empty( $attrib['noSummary'] ) ) {
                continue;
            }

            $this->_rows     = $this->_summary->countChildNodes( $table );
            $this->_cols     = $this->_summary->countChildNodes( $table, $this->_rows-1 );

            for( $row = 0; $row < $this->_rows; $row++ ) {
            
                // the whole row is marked
                $att = $this->_summary->getNodeValue( 'attributes', $table, $row );
                if( isset( $att['results'] ) ) {
                    $result =   $att['results'];

                    if( isset( $result['time']['funcStart'] ) && $beginTest == 0 ) {
                        $beginTest = $result['time']['funcStart'];
                    }

                    if( isset( $result['time']['funcEnd'] ) ) {
                        $endTest = $result['time']['funcEnd'];
                    }

                    ++$resultMarks[$result['type']];
                }
                
                // check for marks of each cell
                for( $col = 0; $col < $this->_cols; $col++ ) {
                    $att = $this->_summary->getNodeValue( 'attributes', $table, $row, $col );
                    if( !isset( $att['results'] ) ) {
                        continue;
                    }

                    $result =   $att['results'];

                    if( isset( $result['time']['funcStart'] ) && $beginTest == 0 ) {
                        $beginTest = $result['time']['funcStart'];
                    }

                    if( isset( $result['time']['funcEnd'] ) ) {
                        $endTest = $result['time']['funcEnd'];
                    }

                    ++$resultMarks[$result['type']];
                }
            }
        }

        return $resultMarks;
    }

   /**
    * build summary table
    *
    * append five columns
    * append rows
    * - headline for testresult     <strong>right</strong>, <strong>wrong</strong>, <strong>ignore</strong>, <strong>error</strong>, <strong>exception</strong>
    * - count                       number of test that faild, right ...
    * - elapsed time                duration of test
    * - date                        date and time
    * @return void
    */
    private function _buildSummaryTable()
    {
        $rows = $this->_summary->countChildNodes( self::$_actualSummary ) - 1;
        $cols = $this->_summary->countChildNodes( self::$_actualSummary, $rows );

        // delete rows
        while( $this->_parser->countChildNodes( self::$_actualSummary ) > 1 ) {
            $this->_parser->deleteRow( self::$_actualSummary, 1 );
        }
        
        // delete cols
        while( $this->_parser->countChildNodes( self::$_actualSummary, 0 ) > 1 ) {
            $this->_parser->deleteBeforeColumn( self::$_actualSummary, 0, 2 );
        }

        // four rows are required, each having five columns
        $this->_parser->appendRow( self::$_actualSummary );
        $this->_parser->appendRow( self::$_actualSummary );
        // set count
        $this->_parser->setNodeValue( 'cData', 'count', self::$_actualSummary, 2, 0 );

        // append 2 rows
        for( $i = 0; $i < 2; $i++ ) {
            $this->_parser->appendRow( self::$_actualSummary );
        }

        // append 5 cols
        for( $i = 0; $i < 5; $i++ ) {
            $this->_parser->appendColumn( self::$_actualSummary );
        }

        $this->_parser->setNodeValue( 'cData', 'elapsed time', self::$_actualSummary, 3, 0 );
        $this->_parser->setNodeValue( 'cData', 'date', self::$_actualSummary, 4, 0 );
        
        for( $i = 6; $i > 2; --$i ) {
            $this->_parser->deleteBeforeColumn( self::$_actualSummary, 3, $i );
            $this->_parser->deleteBeforeColumn( self::$_actualSummary, 4, $i );
        }
        
        $this->_parser->setNodeValue( 'attributes', array( 'colspan' => '5' ), self::$_actualSummary, 3, 1 );
        $this->_parser->setNodeValue( 'attributes', array( 'colspan' => '5' ), self::$_actualSummary, 4, 1 );
    }
}
?>