<?php

/**
 * Encode our data so that it can be serialised
 */
namespace App\Traits;

use Illuminate\Support\Arr;

trait EncodeUTF8
{
	private array $_encoded = [];		// Remember what we've decoded - when calling getAttribute()

	private function decode(array $values): void
	{
		$properties = (new \ReflectionClass($this))->getProperties();

		$class = get_class($this);

		foreach ($properties as $property) {
			if ($property->isStatic())
				continue;

			$name = $property->getName();
			$decode = in_array($name,self::cast_utf8);

			if ($property->isPrivate())
				$name = "\0{$class}\0{$name}";
			elseif ($property->isProtected())
				$name = "\0*\0{$name}";

			if (! array_key_exists($name,$values))
				continue;

			$property->setAccessible(true);

			try {
				$property->setValue(
					$this,$decode ? utf8_decode($values[$name]) : $values[$name]
				);

			} catch (\Exception $e) {
				dd(['e'=>$e->getMessage(),'name'=>$name,'values'=>$values[$name],'decode'=>$decode]);
			}
		}
	}

	private function encode(): array
	{
		$values = [];

		$properties = (new \ReflectionClass($this))->getProperties();

		$class = get_class($this);

		foreach ($properties as $property) {
			// Dont serialize the validation error
			if (($property->name === 'errors') || $property->isStatic())
				continue;

			$property->setAccessible(true);

			if (! $property->isInitialized($this))
				continue;

			$name = $property->getName();
			$encode = in_array($name,self::cast_utf8);

			if ($property->isPrivate())
				$name = "\0{$class}\0{$name}";
			elseif ($property->isProtected())
				$name = "\0*\0{$name}";

			$property->setAccessible(true);
			$value = $property->getValue($this);
			$values[$name] = $encode ? utf8_encode($value) : $value;
		}

		return $values;
	}

	public function getAttribute($key)
	{
		if (in_array($key,self::cast_utf8) && Arr::get($this->attributes,$key) && (! Arr::get($this->_encoded,$key))) {
			// We need to get it from the parent first, taking into account any casting
			$this->attributes[$key] = utf8_decode(parent::getAttribute($key));
			$this->_encoded[$key] = TRUE;

			return $this->attributes[$key];
		}

		return parent::getAttribute($key);
	}

	public function setAttribute($key,$value)
	{
		return parent::setAttribute($key,in_array($key,self::cast_utf8) ? utf8_encode($value) : $value);
	}
}