<?php
namespace Newland\Toubiz\Sync\Neos\Domain\Model;

/*
 * This file is part of the "toubiz-sync-neos" package.
 *
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
 */

use Doctrine\ORM\Mapping as ORM;
use Neos\Flow\Annotations as Flow;
use Newland\Toubiz\Api\Service\StringCleaner;

/**
 * An attribute for an article, tour, etc.
 *
 * @Flow\Entity
 * @ORM\Table(indexes={
 *      @ORM\Index(name="identificationHash", columns={"identificationHash"})
 * })
 */
class Attribute implements \JsonSerializable
{
    const TYPE_STRING = 'string';
    const TYPE_NUMBER = 'number';
    const TYPE_BOOL = 'bool';
    const TYPE_JSON = 'json';
    const BOOL_TRUE = 'true';
    const BOOL_FALSE = 'false';

    public static function generateIdentificationHash(string $articleOriginalId, string $name, $data): string
    {
        return md5((string) json_encode([ $articleOriginalId, $name, $data ]));
    }

    /**
     * @ORM\ManyToOne(inversedBy="attributes")
     * @var Article
     */
    protected $article;

    /**
     * @var string
     */
    protected $name = '';

    /**
     * @ORM\Column(type="text", nullable=true)
     * @var string
     */
    protected $data;

    /**
     * @ORM\Column(type="string", length=10, nullable=true)
     * @var string
     */
    protected $type;

    /**
     * @ORM\Column(type="string", length=32, nullable=true)
     * @var string
     */
    protected $identificationHash;

    /**
     * @return Article|null
     */
    public function getArticle()
    {
        return $this->article;
    }

    public function setArticle(Article $article)
    {
        $this->article = $article;
    }

    public function getName(): string
    {
        return $this->name;
    }

    public function setName(string $name)
    {
        $this->name = $name;
    }

    public function getData()
    {
        switch ($this->type) {
            case static::TYPE_NUMBER:
                return (float) $this->data;

            case static::TYPE_BOOL:
                if (is_string($this->data) && strtolower($this->data) === static::BOOL_TRUE) {
                    return true;
                }
                if (is_string($this->data) && strtolower($this->data) === static::BOOL_FALSE) {
                    return false;
                }
                return (bool) $this->data;

            case static::TYPE_JSON:
                return json_decode($this->data, true);

            case static::TYPE_STRING:
            default:
                return (string) $this->data;
        }
    }

    public function setData($data)
    {
        if (is_string($data)) {
            $this->type = static::TYPE_STRING;
            $data = StringCleaner::asString((string) $data);
        } elseif (is_numeric($data)) {
            $this->type = static::TYPE_NUMBER;
        } elseif (is_bool($data)) {
            $data = $data ? static::BOOL_TRUE : static::BOOL_FALSE;
            $this->type = static::TYPE_BOOL;
        } else {
            $this->type = static::TYPE_JSON;
            $data = json_encode($data);
        }

        $this->data = $data;
    }

    public function getIdentificationHash()
    {
        return $this->identificationHash;
    }

    public function getType()
    {
        return $this->type;
    }

    public function setIdentificationHash(string $identificationHash)
    {
        $this->identificationHash = $identificationHash;
    }

    public function jsonSerialize()
    {
        return get_object_vars($this);
    }
}
