<?php
/**
 * Zend Framework (http://framework.zend.com/)
 *
 * @link      http://github.com/zendframework/zf2 for the canonical source repository
 * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
 * @license   http://framework.zend.com/license/new-bsd New BSD License
 */

namespace Zend\Text\Table;

use 
Zend\Text\Table\Decorator\DecoratorInterface as Decorator;

/**
 * Row class for Zend\Text\Table
 */
class Row
{
    
/**
     * List of all columns
     *
     * @var array
     */
    
protected $columns = array();

    
/**
     * Temporary stored column widths
     *
     * @var array
     */
    
protected $columnWidths null;

    
/**
     * Create a new column and append it to the row
     *
     * @param  string $content
     * @param  array  $options
     * @return Row
     */
    
public function createColumn($content, array $options null)
    {
        
$align    null;
        
$colSpan  null;
        
$encoding null;

        if (
$options !== null) {
            
extract($optionsEXTR_IF_EXISTS);
        }

        
$column = new Column($content$align$colSpan$encoding);

        
$this->appendColumn($column);

        return 
$this;
    }

    
/**
     * Append a column to the row
     *
     * @param  \Zend\Text\Table\Column $column The column to append to the row
     * @return Row
     */
    
public function appendColumn(Column $column)
    {
        
$this->columns[] = $column;

        return 
$this;
    }

    
/**
     * Get a column by it's index
     *
     * Returns null, when the index is out of range
     *
     * @param  integer $index
     * @return Column|null
     */
    
public function getColumn($index)
    {
        if (!isset(
$this->columns[$index])) {
            return 
null;
        }

        return 
$this->columns[$index];
    }

    
/**
     * Get all columns of the row
     *
     * @return array
     */
    
public function getColumns()
    {
        return 
$this->columns;
    }

    
/**
     * Get the widths of all columns, which were rendered last
     *
     * @throws Exception\UnexpectedValueException When no columns were rendered yet
     * @return integer
     */
    
public function getColumnWidths()
    {
        if (
$this->columnWidths === null) {
            throw new 
Exception\UnexpectedValueException('render() must be called before columnWidths can be populated');
        }

        return 
$this->columnWidths;
    }

    
/**
     * Render the row
     *
     * @param  array                               $columnWidths Width of all columns
     * @param  Decorator $decorator    Decorator for the row borders
     * @param  integer                             $padding      Padding for the columns
     * @throws Exception\OverflowException When there are too many columns
     * @return string
     */
    
public function render(array $columnWidthsDecorator $decorator$padding 0)
    {
        
// Prepare an array to store all column widths
        
$this->columnWidths = array();

        
// If there is no single column, create a column which spans over the
        // entire row
        
if (count($this->columns) === 0) {
            
$this->appendColumn(new Column(nullnullcount($columnWidths)));
        }

        
// First we have to render all columns, to get the maximum height
        
$renderedColumns = array();
        
$maxHeight       0;
        
$colNum          0;
        foreach (
$this->columns as $column) {
            
// Get the colspan of the column
            
$colSpan $column->getColSpan();

            
// Verify if there are enough column widths defined
            
if (($colNum $colSpan) > count($columnWidths)) {
                throw new 
Exception\OverflowException('Too many columns');
            }

            
// Calculate the column width
            
$columnWidth = ($colSpan array_sum(array_slice($columnWidths,
                                                                 
$colNum,
                                                                 
$colSpan)));

            
// Render the column and split it's lines into an array
            
$result explode("\n"$column->render($columnWidth$padding));

            
// Store the width of the rendered column
            
$this->columnWidths[] = $columnWidth;

            
// Store the rendered column and calculate the new max height
            
$renderedColumns[] = $result;
            
$maxHeight         max($maxHeightcount($result));

            
// Set up the internal column number
            
$colNum += $colSpan;
        }

        
// If the row doesnt contain enough columns to fill the entire row, fill
        // it with an empty column
        
if ($colNum count($columnWidths)) {
            
$remainingWidth = (count($columnWidths) - $colNum 1) +
                               
array_sum(array_slice($columnWidths,
                                                     
$colNum));
            
$renderedColumns[] = array(str_repeat(' '$remainingWidth));

            
$this->columnWidths[] = $remainingWidth;
        }

        
// Add each single column line to the result
        
$result '';
        for (
$line 0$line $maxHeight$line++) {
            
$result .= $decorator->getVertical();

            foreach (
$renderedColumns as $index => $renderedColumn) {
                if (isset(
$renderedColumn[$line]) === true) {
                    
$result .= $renderedColumn[$line];
                } else {
                    
$result .= str_repeat(' '$this->columnWidths[$index]);
                }

                
$result .= $decorator->getVertical();
            }

            
$result .= "\n";
        }

        return 
$result;
    }
}