<?php
namespace App\Helper;

class Color
{
  protected $color;

  public function __construct()
  {
    $args = func_get_args();
    switch (count($args)) {
      case 1:
        if (is_array($args[0])) {
          $this->color = $args[0];
          break;
        }
        $this->color = $this->hex2dec($this->hex2array($args[0]));
        break;
      case 2:
        if (is_array($args[0])) {
          $this->color = $args[0];
          $this->color []= $args[1];
          break;
        }
        $color = $this->hex2array($args[0]);
        $color []= $args[1];
        $this->color = $this->hex2dec($color);
        break;
      case 3:
      case 4:
        if (is_numeric($args[0])) {
          $this->color = $args;
          break;
        }
        $this->color = $this->hex2dec($args);
        break;
    }
  }
  protected function hex2dec(array $hex)
  {
    return array_map('hexdec', $hex);
  }
  protected function dec2hex(array $bin)
  {
    return array_map('dechex', $bin);
  }
  protected function hex2array(string $hex)
  {
    switch (strlen($hex)) {
      case 3:
      case 4:
      case 6:
      case 7:
        return str_split($hex, 2);
      default:
        throw new OutOfBoundsException('The string ' . $hex . ' is not a correct color code.');
    }
  }
  protected function array2hex(array $arr)
  {
    return implode('', $arr);
  }

  public function convertTo($type)
  {
    switch (strtolower($type)) {
      case 'hex':
        if (is_numeric($this->color[0])) {
          $this->color = $this->dec2hex($this->color);
        }
        break;
      case 'dec':
        if (!is_numeric($this->color[0])) {
          $this->color = $this->hex2dec($this->color);
        }
        break;
      default:
        throw new InvalidArgumentException($type . ' is not a valid argument.');
    }
  }
  public function add($base_color, $amount)
  {
    $changed = false;
    if (!is_numeric($this->color)) {
      $this->convertTo('dec');
      $changed = true;
    }
    switch (strtolower($base_color)) {
      case 'r':
        $base_color = 0;
        break;
      case 'g':
        $base_color = 1;
        break;
      case 'b':
        $base_color = 2;
        break;
      case 'a':
        $base_color = 3;
        break;
      default:
        throw new OutOfBoundsException("Base color '" . $base_color . "' does not exist.");
    }
    $this->color[$base_color] += $amount;
    if ($changed) {
      $this->convertTo('hex');
    }
  }
  public function print()
  {
    $this->convertTo('hex');
    return implode('', $this->color);
  }
  public function toRGB()
  {
    $changed = false;
    $this->convertTo('dec');
    $str = 'rgb(' . implode(', ', array_map(function($a) {
      return round($a, 2);
    }, $this->color)) . ')';
    if ($changed) {
      $this->convertTo('hex');
    }
    return $str;
  }
  public function __toString()
  {
    return $this->print();
  }
  public function toArray()
  {
    return $this->color;
  }
  public function toVector()
  {
    $changed = false;
    $this->convertTo('dec');
    $arr = $this->toArray();
    if ($changed) {
      $this->convertTo('hex');
    }
    return $arr;
  }
  public function luminosity()
  {
    $changed = false;
    $this->convertTo('dec');
    //sqrt( 0.299*R^2 + 0.587*G^2 + 0.114*B^2 )
    $str = sqrt(0.299 * pow($this->color[0], 2) + 0.587 * pow($this->color[1], 2) + 0.114 * pow($this->color[2], 2)) / 255 * 100;
    if ($changed) {
      $this->convertTo('hex');
    }
    return $str;
  }
  public function isDark()
  {
    if ($this->luminosity() < 50) {
      return true;
    }
    return false;
  }
  public function isBright()
  {
    if ($this->luminosity() > 75) {
      return true;
    }
    return false;
  }
}
