<?php

namespace Velis\Session\Serializer;

use Serializable;

/**
 * @author Damian Kurek <damian.kurek@velis.pl>
 */
abstract class AbstractSerializer implements Serializable
{

    /**
     * @var mixed
     */
    private $data;


    /**
     * Check if the data requires serialization
     * @param mixed $data
     * @return bool
     */
    protected function isSerializable($data): bool
    {
        if (!$data || is_bool($data) || is_numeric($data)) {
            return false;
        }

        return true;
    }

    public function setData($data)
    {
        $this->data = $data;
    }


    public function getData()
    {
        return $this->data;
    }

    /**
     * {@inheritDoc}
     */
    public function serialize()
    {
        if (!$this->isSerializable($this->data)) {
            return $this->postSerialize($this->data);
        }

        $result = '';

        foreach ($this->data as $key => $value) {
            $result .= $key . '|' . serialize($value);
        }

        return $this->postSerialize($result);
    }


    /**
     * {@inheritDoc}
     */
    public function unserialize($data)
    {
        $data = $this->preUnserialize($data);
        if (!$this->isSerializable($data)) {
            $this->data = $data;
        } else {
            $result = [];
            $sessionValueKeys = [];
            preg_match_all('/\w+\|/', $data, $sessionValueKeys);
            $sessionData = str_replace($sessionValueKeys[0], '||', $data);
            $sessionData = trim($sessionData, "||");
            $sessionValues = explode('||', $sessionData);

            foreach ($sessionValueKeys[0] as $count => $key) {
                $key = trim($key, '|');
                $result[$key] = unserialize($sessionValues[$count]);
            }

            $this->data = $result;
        }
    }

    /**
     * Do after serialize
     * @param string $data
     * @return string
     */
    abstract protected function postSerialize($data);

    /**
     * Do before unserialize
     * @param string $data
     * @return string
     */
    abstract protected function preUnserialize($data);
}
