<?php
/***************************************************************************
 *                                                                          *
 *   (c) 2004 Vladimir V. Kalynyak, Alexey V. Vinokurov, Ilya M. Shalnev    *
 *                                                                          *
 * This  is  commercial  software,  only  users  who have purchased a valid *
 * license  and  accept  to the terms of the  License Agreement can install *
 * and use this program.                                                    *
 *                                                                          *
 ****************************************************************************
 * PLEASE READ THE FULL TEXT  OF THE SOFTWARE  LICENSE   AGREEMENT  IN  THE *
 * "copyright.txt" FILE PROVIDED WITH THIS DISTRIBUTION PACKAGE.            *
 ****************************************************************************/

namespace Tygh\Backend\Cache;

use Tygh\Registry;
use Tygh\Tygh;
use Tygh\Exceptions\DatabaseException;

class Database extends ABackend
{
    /** @var \Tygh\Database\Connection */
    protected $db;

    /**
     * Database constructor.
     *
     * @param array $config
     *
     * @throws \Tygh\Exceptions\DatabaseException
     */
    public function __construct($config)
    {
        $this->db = Tygh::$app['db'];

        $this->db->raw = true;

        if (!$this->db->getField("SHOW TABLES LIKE '?:cache'")) {
            Registry::set('runtime.database.skip_errors', true);
            $this->db->raw = true;
            $res = $this->db->query('
                CREATE TABLE ?:cache (
                    name varchar(255),
                    company_id int(11) unsigned not null default \'0\',
                    data mediumtext,
                    expiry int,
                    tags varchar(255),
                    PRIMARY KEY(name, company_id),
                    KEY (tags),
                    KEY (name, company_id, expiry),
                    KEY (company_id)
                ) Engine=MyISAM DEFAULT CHARSET UTF8
            ');

            Registry::set('runtime.database.skip_errors', false);

            if ($res == false) {
                throw new DatabaseException('Database cache data storage is not supported. Please choose another one.');
            }
        }

        parent::__construct($config);

        return true;
    }

    /** @inheritDoc */
    public function set($name, $data, $condition, $cache_level = null, $ttl = null)
    {
        $fname = $name . '.' . $cache_level;

        if (!empty($data)) {
            $this->db->raw = true;
            $this->db->query('REPLACE INTO ?:cache ?e', [
                'name'       => $fname,
                'company_id' => $this->_company_id,
                'data'       => serialize($data),
                'tags'       => $name,
                'expiry'     => $this->getCacheExpiryTime($condition, $cache_level, $ttl, 0)
            ]);
        }
    }

    /** @inheritDoc */
    public function get($name, $cache_level = null)
    {
        $fname = $name . '.' . $cache_level;

        $expiry_condition = $this->db->quote('AND (expiry = ?i OR expiry > ?i)', 0, TIME);

        $this->db->raw = true;
        $res = $this->db->getRow(
            'SELECT data, expiry FROM ?:cache WHERE name = ?s AND company_id = ?i ?p',
            $fname, $this->_company_id, $expiry_condition
        );

        if (!empty($name) && !empty($res)) {
            $cache_data = !empty($res['data']) ? @unserialize($res['data']) : false;

            if ($cache_data !== false) {
                return [$cache_data];
            }

            // clean up the cache
            $this->db->raw = true;
            $this->db->query('DELETE FROM ?:cache WHERE name = ?s AND company_id = ?i', $fname, $this->_company_id);
        }

        return false;
    }

    /** @inheritDoc */
    public function clear($tags)
    {
        if (!empty($tags)) {
            $this->db->raw = true;
            $this->db->query('DELETE FROM ?:cache WHERE tags IN (?a)', $tags);
        }

        return true;
    }

    /** @inheritDoc */
    public function cleanup()
    {
        Registry::set('runtime.database.skip_errors', true);

        $this->db->raw = true;
        $this->db->query('TRUNCATE ?:cache');

        Registry::set('runtime.database.skip_errors', false);

        return true;
    }
}
