<?php

/**
 * 
 * @property Coordinate topLeft
 * @property Coordinate topRight
 * @property Coordinate bottomLeft
 * @property Coordinate bottomRight
 * @property Coordinate center
 * 
 * @property number x
 * @property number y
 * @property number width
 * @property number height
 *
 * @property boolean isEmpty
 * 
 * @property Rectangle innerRect
 * @property Rectangle outerRect
 */
class Rectangle extends CComponent
{
  const TOP_LEFT = 0;
  const TOP_RIGHT = 1;
  const BOTTOM_LEFT = 2;
  const BOTTOM_RIGHT = 3;

  private $coordinates = array();

  public function __construct($topLeft, $bottomRight)
  {
    $this->topLeft = $topLeft;
    $this->bottomRight = $bottomRight;
    $this->topRight = new Coordinate($bottomRight->x, $topLeft->y);
    $this->bottomLeft = new Coordinate($topLeft->x, $bottomRight->y);
  }

  /**
   * @return Coordinate
   */
  public function getTopLeft()
  {
    return $this->coordinates[self::TOP_LEFT]; 
  }

  /**
   * @return Coordinate
   */
  public function getTopRight()
  {
    return $this->coordinates[self::TOP_RIGHT]; 
  }

  /**
   * @return Coordinate
   */
  public function getBottomLeft()
  {
    return $this->coordinates[self::BOTTOM_LEFT]; 
  }

  /**
   * @return Coordinate
   */
  public function getBottomRight()
  {
    return $this->coordinates[self::BOTTOM_RIGHT];
  }

  public function setTopLeft(Coordinate $coord)
  {
    $this->coordinates[self::TOP_LEFT] = $coord;
  }

  public function setTopRight(Coordinate $coord)
  {
    $this->coordinates[self::TOP_RIGHT] = $coord;
  }

  public function setBottomLeft(Coordinate $coord)
  {
    $this->coordinates[self::BOTTOM_LEFT] = $coord;
  }

  public function setBottomRight(Coordinate $coord)
  {
    $this->coordinates[self::BOTTOM_RIGHT] = $coord;
  }

  /**
   * 
   * @return number
   */
  public function getHeight()
  {
    return abs(max(($this->bottomLeft->y - $this->topLeft->y), ($this->bottomRight->y - $this->topRight->y)));
  }

  /**
   * 
   * @return number
   */
  public function getWidth()
  {
    return abs(max(($this->topRight->x - $this->topLeft->x), ($this->bottomRight->x - $this->bottomLeft->x)));
  }
  
  public function getIsEmpty()
  {
    return $this->width == 0 && $this->height == 0;
  }

  public function inflate($top, $left, $bottom, $right)
  {
  	$this->coordinates[self::TOP_LEFT]->y = $this->coordinates[self::TOP_LEFT]->y - $top;
  	$this->coordinates[self::TOP_LEFT]->x = $this->coordinates[self::TOP_LEFT]->x - $left;
  	
  	$this->coordinates[self::BOTTOM_RIGHT]->y = $this->coordinates[self::BOTTOM_RIGHT]->y + $bottom;
  	$this->coordinates[self::BOTTOM_RIGHT]->x = $this->coordinates[self::BOTTOM_RIGHT]->x + $right;
  	
  	
  	$this->coordinates[self::TOP_RIGHT]->y = $this->coordinates[self::TOP_LEFT]->y;
  	$this->coordinates[self::TOP_RIGHT]->x = $this->coordinates[self::BOTTOM_RIGHT]->x;

  	
  	$this->coordinates[self::BOTTOM_LEFT]->y = $this->coordinates[self::BOTTOM_RIGHT]->y;
  	$this->coordinates[self::BOTTOM_LEFT]->x = $this->coordinates[self::TOP_LEFT]->x;
  	
  }
  
  public function __toString()
  {
    return "[".$this->getTopLeft().",W=$this->width,H=$this->height]";
    //return "[".$this->getTopLeft().",".$this->getBottomRight()."]";
  }

  /**
   * @return Rectangle
   */
  public function getInnerRect()
  {
    $tl = clone $this->getTopLeft();
    $br = clone $this->getBottomRight();
    $tl->X += 1;
    $tl->Y += 1;
    $br->X -= 1;
    $br->Y -= 1;
    return new Rectangle($tl,$br);
  }

  /**
   * @return Rectangle
   */
  public function getOuterRect()
  {
    $tl = clone $this->getTopLeft();
    $br = clone $this->getBottomRight();
    $tl->X -= 1;
    $tl->Y -= 1;
    $br->X += 1;
    $br->Y += 1;
    return new Rectangle($tl,$br);
  }

  /**
   * @return number
   */
  public function getX()
  {
    return $this->getTopLeft()->getX();
  }

  /**
   * @return number
   */
  public function getY()
  {
    return $this->getTopLeft()->getY();
  }
  
  /**
   * @return Coordinate
   */
  public function getCenter()  
  {
    $w = $this->width/2;
    $h = $this->height/2;
    return new Coordinate($this->X+$w, $this->Y+$h);
  }

  /**
   *
   * @param number $x
   * @param number $y
   * @param number $w
   * @param number $h
   */
  public static function fromXYWH($x,$y,$w,$h)
  {
    return new Rectangle(new Coordinate($x, $y), new Coordinate($x+$w, $y+$h));
  }
  
  /**
   * 
   * @param Rectangle $rectOriginal
   * @param array $fix left|right|top|bottom, default to 0
   * @return Rectangle
   */
  public static function applyFix(Rectangle $rectOriginal, $fix=array())
  {
    $fix = is_array_ex($fix) ? $fix : array();
    
    array_ensure_value($fix, 'top', 0);
    array_ensure_value($fix, 'left', 0);
    array_ensure_value($fix, 'right', 0);
    array_ensure_value($fix, 'bottom', 0);
    
    $x = $rectOriginal->getX() - $fix['left'];
    $y = $rectOriginal->getY() - $fix['top'];
    $w = $rectOriginal->getWidth() + $fix['left'] + $fix['right'];
    $h = $rectOriginal->getHeight() + $fix['top'] + $fix['bottom'];
    
    $rect = self::fromXYWH($x, $y, $w, $h);
    
    return $rect;
  }
}
