src/Console/Drawing/Geometry.php
<?php namespace Cerbero\Workflow\Console\Drawing;
/**
* Geometry applied to the drawing.
*
* @author Andrea Marco Sartori
*/
class Geometry {
const BORDER_WIDTH = 1;
const MIN_SPACE_FROM_BORDER_X = 1;
const MIN_SPACE_FROM_BORDER_Y = 0;
const ARROW_WIDTH = 1;
const MIN_PIPE_LENGTH = 8;
const SPACE_FROM_ARROW = 1;
/**
* @author Andrea Marco Sartori
* @var string $core The name of the core.
*/
protected $core;
/**
* @author Andrea Marco Sartori
* @var array $pipes List of pipes.
*/
protected $pipes;
/**
* @author Andrea Marco Sartori
* @var integer $nesting Nesting level.
*/
protected $nesting = 0;
/**
* Set the name of the core.
*
* @author Andrea Marco Sartori
* @param string $core
* @return void
*/
public function setCore($core)
{
$this->core = $core;
}
/**
* Set the pipes.
*
* @author Andrea Marco Sartori
* @param array $pipes
* @return void
*/
public function setPipes(array $pipes)
{
$this->pipes = $pipes;
}
/**
* Calculate the half width of the drawing.
*
* @author Andrea Marco Sartori
* @param boolean $up
* @return integer
*/
public function getHalfWidth($up = false)
{
$number = $this->getTotalWidth();
return $this->roundHalf($number, $up);
}
/**
* Round the half of a number, either up or down.
*
* @author Andrea Marco Sartori
* @param integer $number
* @param boolean $up
* @return integer
*/
private function roundHalf($number, $up)
{
$round = $up ? 'ceil' : 'floor';
return $round($number / 2);
}
/**
* Calculate the total width of the drawing.
*
* @author Andrea Marco Sartori
* @return integer
*/
protected function getTotalWidth()
{
$borders = (static::BORDER_WIDTH + static::MIN_SPACE_FROM_BORDER_X) * 2;
if(empty($this->pipes))
{
return $borders + $this->getCoreLength();
}
$borders *= count($this->pipes);
$name = ($this->getLongestPipeLength() + static::SPACE_FROM_ARROW) * 2;
return $borders + $name + static::ARROW_WIDTH;
}
/**
* Calculate the length of the core name.
*
* @author Andrea Marco Sartori
* @return integer
*/
protected function getCoreLength()
{
return strlen($this->core);
}
/**
* Calculate the length of the longest pipe name.
*
* @author Andrea Marco Sartori
* @return integer
*/
protected function getLongestPipeLength()
{
if(empty($this->pipes)) return 0;
return array_reduce($this->pipes, function($carry, $pipe)
{
return strlen($pipe) > $carry ? strlen($pipe) : $carry;
}, static::MIN_PIPE_LENGTH);
}
/**
* Retrieve the spaced pipe and method pair.
*
* @author Andrea Marco Sartori
* @param string $pipe
* @param string $arrow
* @param string $method
* @return string
*/
public function getSpacedPipe($pipe, $arrow, $method)
{
$left = $this->getSpacesByWord($pipe);
$arrow = $this->addSpacesToArrow($arrow);
$right = $this->getSpacesByWord($method);
return $left.$pipe.$arrow.$method.$right;
}
/**
* Retrieve the blank spaces close to a word.
*
* @author Andrea Marco Sartori
* @param string $word
* @return string
*/
protected function getSpacesByWord($word)
{
$length = $this->getSideBordersLength() + static::SPACE_FROM_ARROW + static::ARROW_WIDTH;
$extra = $this->getHalfWidth(true) - $length - strlen($word);
return $extra > 0 ? str_repeat(' ', $extra) : '';
}
/**
* Retrieve the length of the borders of a side.
*
* @author Andrea Marco Sartori
* @return integer
*/
protected function getSideBordersLength()
{
$border = (static::BORDER_WIDTH + static::MIN_SPACE_FROM_BORDER_X);
return $border * $this->nesting;
}
/**
* Add spaces around the given arrow.
*
* @author Andrea Marco Sartori
* @param string $arrow
* @return string
*/
protected function addSpacesToArrow($arrow)
{
$spaces = str_repeat(' ', static::SPACE_FROM_ARROW);
return "{$spaces}{$arrow}{$spaces}";
}
/**
* Retrieve the left borders formatted with the given border.
*
* @author Andrea Marco Sartori
* @param string $border
* @return string
*/
public function getLeftBordersWith($border)
{
$border = str_repeat($border, static::BORDER_WIDTH);
$space = str_repeat(' ', static::MIN_SPACE_FROM_BORDER_X);
return str_repeat("{$border}{$space}", $this->nesting);
}
/**
* Retrieve the right borders formatted with the given border.
*
* @author Andrea Marco Sartori
* @param string $border
* @return string
*/
public function getRightBordersWith($border)
{
$space = str_repeat(' ', static::MIN_SPACE_FROM_BORDER_X);
$border = str_repeat($border, static::BORDER_WIDTH);
return str_repeat("{$space}{$border}", $this->nesting);
}
/**
* Increase the nesting level.
*
* @author Andrea Marco Sartori
* @return void
*/
public function increaseNesting()
{
$this->nesting++;
}
/**
* Calculate the width of the drawing without the borders.
*
* @author Andrea Marco Sartori
* @return integer
*/
public function getWidthButBorders()
{
return $this->getTotalWidth() - $this->getBordersLength();
}
/**
* Calculate the length of the borders.
*
* @author Andrea Marco Sartori
* @return integer
*/
protected function getBordersLength()
{
return $this->getSideBordersLength() * 2;
}
/**
* Retrieve the spaced core name.
*
* @author Andrea Marco Sartori
* @return string
*/
public function getSpacedCore()
{
$left = $this->getSpacesByCore();
$right = $this->getSpacesByCore(true);
return $left.$this->core.$right;
}
/**
* Retrieve the blank spaces close to the core.
*
* @author Andrea Marco Sartori
* @param boolean $up
* @return string
*/
protected function getSpacesByCore($up = false)
{
$free = $this->getTotalWidth() - $this->getBordersLength() - $this->getCoreLength();
return $free < 1 ? '' : str_repeat(' ', $this->roundHalf($free, $up));
}
/**
* Decrease the nesting level.
*
* @author Andrea Marco Sartori
* @return void
*/
public function decreaseNesting()
{
$this->nesting--;
}
}