<?php

// Copyright (c) 2023 Timon Wimmer-Cuport
// This code is licensed under MIT license (see LICENSE.txt for details)

class Colors {
	private $H;
	private $S;
	private $L;
	// H = hue, S = saturation, L = lightness

	public $darkest;
	public $primary;
	public $primaryLight;
	public $primaryDark;
	public $complementary;

	function __construct($h = false, $s = false, $l = false) {
		if (!$h) $this->H = ($this->random() * 360);
		else $this->H = $h;
		if (!$s) $this->S = 40;
		else $this->S = $s;
		if (!$l) $this->L = 40;
		else $this->L = $l;
		$this->setColors();
	}

	function random() {
		return (float)rand()/(float)getrandmax();
	}

	function fHSL($n = false, $h, $s, $l, $rgb = true) {
		if ($n === false) return false;
		$s /= 100;
		$l /= 100;
		$a = $s * min($l, 1 - $l);
		$k = (($n + ($h / 30)) % 12);
		$x = $l - $a * max(min($k - 3, 9 - $k, 1), -1);
		if ($rgb) $x *= 255;
		return $x;
	}

	function HSLtoRGB($h = false, $s = false, $l = false) {
		if (!$h) return false;
		if (!$s) return false;
		if (!$l) return false;
		return [$this->fHSL(0, $h, $s, $l), $this->fHSL(8, $h, $s, $l), $this->fHSL(4, $h, $s, $l)];
	}

	function RGBtoHex($r, $g, $b) {
		$hex = sprintf("#%02x%02x%02x", $r, $g, $b);
		return $hex;
	}

	function contrastYIQ($rgb, $reverse = false) {
		$yiq = (($rgb[0] * 299) + ($rgb[1] * 587) + ($rgb[2] * 114)) / 1000;
		if (!$reverse) return ($yiq >= 128) ? "#000000" : "#ffffff";
		else return ($yiq >= 128) ? "#ffffff" : "#000000";
		
	}

	function hueToRGB($p, $q, $t) {
		if ($t < 0) $t += 1;
		if ($t > 1) $t -= 1;
		if ($t < 1/6) return $p + ($q - $p) * 6 * $t;
		if ($t < 1/2) return $q;
		if ($t < 2/3) return $p + ($q - $p) * (2/3 - $t) * 6;
		return $p;
	}

	function getComplementary($rgb) {
		$r = $rgb[0];
		$g = $rgb[1];
		$b = $rgb[2];
		$r /= 255.0;
		$g /= 255.0;
		$b /= 255.0;
		$max = max($r, $g, $b);
		$min = min($r, $g, $b);
		$h = ($max + $min) / 2.0;
		$s = ($max + $min) / 2.0;
		$l = ($max + $min) / 2.0;
		if ($max == $min) {
			$h = 0;
			$s = 0;
		}
		else {
			$d = $max - $min;
			$s = ($l > 0.5 ? $d / (2.0 - $max - $min) : $d / ($max + $min));
			if ($max == $r && $g >= $b) $h = 1.0472 * ($g - $b) / $d;
			else if ($max == $r && $g < $b) $h = 1.0472 * ($g - $b) / $d + 6.2832;
			else if ($max == $g) $h = 1.0472 * ($b - $r) / $d + 2.0944;
			else if ($max == $b) $h = 1.0472 * ($r - $g) / $d + 4.1888;
		}
		$h = $h / 6.2832 * 360.0 + 0;
		$h += 180;
		if ($h > 360) $h -= 360;
		$h /= 360;
		if ($s === 0) {
			$r = $g = $b = $l;
		}
		else {
			$q = $l < 0.5 ? $l * (1 + $s) : $l + $s - $l * $s;
			$p = 2 * $l - $q;
			$r = $this->hueToRGB($p, $q, $h + 1/3);
			$g = $this->hueToRGB($p, $q, $h);
			$b = $this->hueToRGB($p, $q, $h - 1/3);
		}
		$r = round($r * 255);
		$b = round($b * 255);
		$g = round($g * 255);
		return [$r, $g, $b];
	}

	function setColors() {
		$rgb = $this->HSLtoRGB($this->H, $this->S, $this->L);
		$this->primary = $rgb;
		$this->primaryText = $this->contrastYIQ($rgb);
		$this->primaryLight = $this->HSLtoRGB($this->H, $this->S, 85);
		$this->primaryDark = $this->HSLtoRGB($this->H, $this->S, 25);
		$this->darkest = $this->HSLtoRGB($this->H, 80, 6);
		$rgbComplementary = $this->HSLtoRGB($this->H, 55, 70);
		$this->complementary = $this->getComplementary($rgbComplementary);
	}

	function getColor($rgb, $alpha = false, $toHex = false) {
		if (!$rgb) return false;
		$rgbStr = "rgb(";
		if ($alpha) $rgbStr = "rgba(";
		$rgbStr .= $rgb[0] . ", " . $rgb[1] . ", " . $rgb[2];
		if ($alpha) $rgbStr .= ", " . $alpha;
		$rgbStr .= ")";
		return $rgbStr;
	}

}

$colors = new Colors(/* $h, $s, $l */);

echo 'Darkest: ' . $colors->getColor($colors->darkest);
echo 'Primary: ' . $colors->getColor($colors->primary);
echo 'Primary Light: ' . $colors->getColor($colors->primaryLight);
echo 'Primary Dark: ' . $colors->getColor($colors->primaryDark);
echo 'Secondary (Complementary): ' . $colors->getColor($colors->complementary);
Darkest: rgb(3.06, 27.54, 15.3)
Primary: rgb(61.2, 142.8, 102)
Check for inverse text color...
Primary Light: rgb(201.45, 232.05, 216.75)
Primary Dark: rgb(38.25, 89.25, 63.75)
Secondary (Complementary): rgb(221, 136, 179)