<?php


namespace CCDN\Helpers\Caching;


use CCDN\Helpers\Settings;
use FilesystemIterator;

/**
 * Class Cache
 * This class save cache only in file and save only string data
 *
 * @package CCDN\Helpers
 */
class FileCache implements CacheInterface
{
    /**
     * @var string Path to DLE cache folder
     */
    private $folder = ENGINE_DIR.'/cache';

    /**
     * @var string
     */
    private $fileExtension = '.bin';

    /**
     * @var string
     */
    private $prefix;

    /**
     * @var FilesystemIterator
     */
    private $filesystemIterator;

    /**
     * Cache constructor.
     */
    public function __construct()
    {
        $version = str_replace('.', '_', Settings::PLUGIN_VERSION);
        $this->prefix = Settings::PLUGIN_NAME.'_'.$version.'_';
        $this->filesystemIterator = new FilesystemIterator($this->folder);
    }

    /**
     * @inheritDoc
     */
    public function get($key, $default = null)
    {
        $cacheFile = $this->getFilePath($key);

        if (@filemtime($cacheFile) > time()) {
            $fp = @fopen($cacheFile, 'rb');
            if ($fp !== false) {
                @flock($fp, LOCK_SH);
                $cacheValue = @stream_get_contents($fp);
                @flock($fp, LOCK_UN);
                @fclose($fp);
                return $cacheValue !== false ? $cacheValue : $default;
            }
        }
        return $default;
    }

    /**
     * @inheritDoc
     */
    protected function getFilePath($key)
    {
        $key = $this->buildKey($key);

        return $this->folder.'/'.$key.$this->fileExtension;
    }

    /**
     * @param  string  $key
     * @return string
     */
    protected function buildKey($key)
    {
        return $this->prefix.md5($key);
    }

    /**
     * @inheritDoc
     */
    public function set($key, $value, $ttl = 0)
    {
        $this->gc();
        $cacheFile = $this->getFilePath($key);
        if (is_file($cacheFile)) {
            @unlink($cacheFile);
        }
        if (@file_put_contents($cacheFile, $value, LOCK_EX) !== false) {
            @chmod($cacheFile, 0666);
            if ($ttl <= 0) {
                $ttl = 31536000;
            }
            return @touch($cacheFile, $ttl + time());
        }

        return false;
    }

    /**
     * Garbage collector Removing expired cache files under a directory.
     *
     * @return void
     */
    protected function gc()
    {
        $time = time();
        foreach ($this->filesystemIterator as $file) {
            if ($file->isDir() || strpos($file->getFilename(), $this->prefix) === false) {
                continue;
            }
            if ($file->getMTime() < $time) {
                @unlink($file->getRealPath());
            }
        }
    }

    /**
     * @inheritDoc
     */
    public function has($key)
    {
        return @filemtime($this->getFilePath($key)) > time();
    }

    /**
     * @inheritDoc
     */
    public function clear()
    {
        foreach ($this->filesystemIterator as $file) {
            if ($file->isDir() || strpos($file->getFilename(), $this->prefix) === false) {
                continue;
            }
            @unlink($file->getPathname());
        }

        return true;
    }

    /**
     * @inheritDoc
     */
    public function delete($key)
    {
        return @unlink($this->getFilePath($key));
    }

}
