<?php

    /**

     * @package     Freemius

     * @copyright   Copyright (c) 2015, Freemius, Inc.

     * @license     https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3

     * @since       1.1.6

     */



    if ( ! defined( 'ABSPATH' ) ) {

        exit;

    }



    class FS_Cache_Manager {

        /**

         * @var FS_Option_Manager

         */

        private $_options;

        /**

         * @var FS_Logger

         */

        private $_logger;



        /**

         * @var FS_Cache_Manager[]

         */

        private static $_MANAGERS = array();



        /**

         * @author Vova Feldman (@svovaf)

         * @since  1.1.3

         *

         * @param string $id

         */

        private function __construct( $id ) {

            $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_cach_mngr_' . $id, WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );



            $this->_logger->entrance();

            $this->_logger->log( 'id = ' . $id );



            $this->_options = FS_Option_Manager::get_manager( $id, true, true, false );

        }



        /**

         * @author Vova Feldman (@svovaf)

         * @since  1.1.6

         *

         * @param $id

         *

         * @return FS_Cache_Manager

         */

        static function get_manager( $id ) {

            $id = strtolower( $id );



            if ( ! isset( self::$_MANAGERS[ $id ] ) ) {

                self::$_MANAGERS[ $id ] = new FS_Cache_Manager( $id );

            }



            return self::$_MANAGERS[ $id ];

        }



        /**

         * @author Vova Feldman (@svovaf)

         * @since  1.1.6

         *

         * @return bool

         */

        function is_empty() {

            $this->_logger->entrance();



            return $this->_options->is_empty();

        }



        /**

         * @author Vova Feldman (@svovaf)

         * @since  1.1.6

         */

        function clear() {

            $this->_logger->entrance();



            $this->_options->clear( true );

        }



        /**

         * Delete cache manager from DB.

         *

         * @author Vova Feldman (@svovaf)

         * @since  1.0.9

         */

        function delete() {

            $this->_options->delete();

        }



        /**

         * Check if there's a cached item.

         *

         * @author Vova Feldman (@svovaf)

         * @since  1.1.6

         *

         * @param string $key

         *

         * @return bool

         */

        function has( $key ) {

            $cache_entry = $this->_options->get_option( $key, false );



            return ( is_object( $cache_entry ) &&

                     isset( $cache_entry->timestamp ) &&

                     is_numeric( $cache_entry->timestamp )

            );

        }



        /**

         * Check if there's a valid cached item.

         *

         * @author Vova Feldman (@svovaf)

         * @since  1.1.6

         *

         * @param string   $key

         * @param null|int $expiration Since 1.2.2.7

         *

         * @return bool

         */

        function has_valid( $key, $expiration = null ) {

            $cache_entry = $this->_options->get_option( $key, false );



            $is_valid = ( is_object( $cache_entry ) &&

                          isset( $cache_entry->timestamp ) &&

                          is_numeric( $cache_entry->timestamp ) &&

                          $cache_entry->timestamp > WP_FS__SCRIPT_START_TIME

            );



            if ( $is_valid &&

                 is_numeric( $expiration ) &&

                 isset( $cache_entry->created ) &&

                 is_numeric( $cache_entry->created ) &&

                 $cache_entry->created + $expiration < WP_FS__SCRIPT_START_TIME

            ) {

                /**

                 * Even if the cache is still valid, since we are checking for validity

                 * with an explicit expiration period, if the period has past, return

                 * `false` as if the cache is invalid.

                 *

                 * @since 1.2.2.7

                 */

                $is_valid = false;

            }



            return $is_valid;

        }



        /**

         * @author Vova Feldman (@svovaf)

         * @since  1.1.6

         *

         * @param string $key

         * @param mixed  $default

         *

         * @return mixed

         */

        function get( $key, $default = null ) {

            $this->_logger->entrance( 'key = ' . $key );



            $cache_entry = $this->_options->get_option( $key, false );



            if ( is_object( $cache_entry ) &&

                 isset( $cache_entry->timestamp ) &&

                 is_numeric( $cache_entry->timestamp )

            ) {

                return $cache_entry->result;

            }



            return is_object( $default ) ? clone $default : $default;

        }



        /**

         * @author Vova Feldman (@svovaf)

         * @since  1.1.6

         *

         * @param string $key

         * @param mixed  $default

         *

         * @return mixed

         */

        function get_valid( $key, $default = null ) {

            $this->_logger->entrance( 'key = ' . $key );



            $cache_entry = $this->_options->get_option( $key, false );



            if ( is_object( $cache_entry ) &&

                 isset( $cache_entry->timestamp ) &&

                 is_numeric( $cache_entry->timestamp ) &&

                 $cache_entry->timestamp > WP_FS__SCRIPT_START_TIME

            ) {

                return $cache_entry->result;

            }



            return is_object( $default ) ? clone $default : $default;

        }



        /**

         * @author Vova Feldman (@svovaf)

         * @since  1.1.6

         *

         * @param string $key

         * @param mixed  $value

         * @param int    $expiration

         * @param int    $created Since 2.0.0 Cache creation date.

         */

        function set( $key, $value, $expiration = WP_FS__TIME_24_HOURS_IN_SEC, $created = WP_FS__SCRIPT_START_TIME ) {

            $this->_logger->entrance( 'key = ' . $key );



            $cache_entry = new stdClass();



            $cache_entry->result    = $value;

            $cache_entry->created   = $created;

            $cache_entry->timestamp = $created + $expiration;

            $this->_options->set_option( $key, $cache_entry, true );

        }



        /**

         * Get cached record expiration, or false if not cached or expired.

         *

         * @author Vova Feldman (@svovaf)

         * @since  1.1.7.3

         *

         * @param string $key

         *

         * @return bool|int

         */

        function get_record_expiration( $key ) {

            $this->_logger->entrance( 'key = ' . $key );



            $cache_entry = $this->_options->get_option( $key, false );



            if ( is_object( $cache_entry ) &&

                 isset( $cache_entry->timestamp ) &&

                 is_numeric( $cache_entry->timestamp ) &&

                 $cache_entry->timestamp > WP_FS__SCRIPT_START_TIME

            ) {

                return $cache_entry->timestamp;

            }



            return false;

        }



        /**

         * Purge cached item.

         *

         * @author Vova Feldman (@svovaf)

         * @since  1.1.6

         *

         * @param string $key

         */

        function purge( $key ) {

            $this->_logger->entrance( 'key = ' . $key );



            $this->_options->unset_option( $key, true );

        }



        /**

         * Extend cached item caching period.

         *

         * @author Vova Feldman (@svovaf)

         * @since  2.0.0

         *

         * @param string $key

         * @param int    $expiration

         *

         * @return bool

         */

        function update_expiration( $key, $expiration = WP_FS__TIME_24_HOURS_IN_SEC ) {

            $this->_logger->entrance( 'key = ' . $key );



            $cache_entry = $this->_options->get_option( $key, false );



            if ( ! is_object( $cache_entry ) ||

                 ! isset( $cache_entry->timestamp ) ||

                 ! is_numeric( $cache_entry->timestamp )

            ) {

                return false;

            }



            $this->set( $key, $cache_entry->result, $expiration, $cache_entry->created );



            return true;

        }



        /**

         * Set cached item as expired.

         *

         * @author Vova Feldman (@svovaf)

         * @since  1.2.2.7

         *

         * @param string $key

         */

        function expire( $key ) {

            $this->_logger->entrance( 'key = ' . $key );



            $cache_entry = $this->_options->get_option( $key, false );



            if ( is_object( $cache_entry ) &&

                 isset( $cache_entry->timestamp ) &&

                 is_numeric( $cache_entry->timestamp )

            ) {

                // Set to expired.

                $cache_entry->timestamp = WP_FS__SCRIPT_START_TIME;

                $this->_options->set_option( $key, $cache_entry, true );

            }

        }



        #--------------------------------------------------------------------------------

        #region Migration

        #--------------------------------------------------------------------------------



        /**

         * Migrate options from site level.

         *

         * @author Vova Feldman (@svovaf)

         * @since  2.0.0

         */

        function migrate_to_network() {

            $this->_options->migrate_to_network();

        }



        #endregion

    }