namespace Illuminate\Cache;

use Closure;
use DateTime;
use ArrayAccess;
use Carbon\Carbon;
use BadMethodCallException;
use Illuminate\Contracts\Cache\Store;
use Illuminate\Support\Traits\Macroable;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Contracts\Cache\Repository as CacheContract;
// a namespace be used enough
class Repository implements CacheContract, ArrayAccess
{// two interface that should be implements by Repository
use Macroable {
__call as macroCall;
}// use Macroable that we will be a __call

/**
* The cache store implementation.
* The cache store
* @var \Illuminate\Contracts\Cache\Store
*/
protected $store;// a Cache Store instance of the implementation

/**
* The event dispatcher implementation.
*
* @var \Illuminate\Contracts\Events\Dispatcher
*/
protected $events;// The event dispatcher implementation a events interface

/**
* The default number of minutes to store items.
*
* @var int
*/
protected $default = 60; // a normal time[minutes]or[seconds] to set the value into the store items .
// normal set it is 60 second

/**
* Create a new cache repository instance.
*
* @param \Illuminate\Contracts\Cache\Store $store
* @return void
*/
public function __construct(Store $store)
{
$this->store = $store;
}// a big __set to Create a new instance about Cache, repository
// a library to store.

/**
* Set the event dispatcher instance.
*
* @param \Illuminate\Contracts\Events\Dispatcher $events
* @return void
*/
public function setEventDispatcher(Dispatcher $events)
{
$this->events = $events;
}// Set the event dispatcher instance.
// a big set to the events.

/**
* Fire an event for this cache instance.
*
* @param string $event
* @param array $payload
* @return void
*/
// Fire an event for this cache instance.
protected function fireCacheEvent($event, $payload)// fire cache event
{
if (! isset($this->events)) {
return;
}// check this is a normal events

switch ($event) {// this->events is a instance about a class, then the events is a way or a type
case 'hit':// case hit:
if (count($payload) == 2) {
$payload[] = [];
}

return $this->events->fire(new Events\CacheHit($payload[0], $payload[1], $payload[2]));
case 'missed':// case missed:
if (count($payload) == 1) {
$payload[] = [];
}

return $this->events->fire(new Events\CacheMissed($payload[0], $payload[1]));
case 'delete':// case delete:
if (count($payload) == 1) {
$payload[] = [];
}

return $this->events->fire(new Events\KeyForgotten($payload[0], $payload[1]));
case 'write':// cache write:
if (count($payload) == 3) {
$payload[] = [];
}

return $this->events->fire(new Events\KeyWritten($payload[0], $payload[1], $payload[2], $payload[3]));
}
}// a switch way to change the result

/**
* Determine if an item exists in the cache.
*
* @param string $key
* @return bool
*/
public function has($key)
{
return ! is_null($this->get($key));
}// determine[check] the item has exists in the cache.

/**
* Retrieve an item from the cache by key. Retrieve an item from the cache by key.
*
* @param string $key
* @param mixed $default
* @return mixed
*/
public function get($key, $default = null)// get item by key.
{
if (is_array($key)) {
return $this->many($key);
}// the key is a array ,will back a item array by many.

$value = $this->store->get($this->itemKey($key));// get item[value] by key

if (is_null($value)) {// null the value
$this->fireCacheEvent('missed', [$key]);//missed

$value = value($default);
} else {
$this->fireCacheEvent('hit', [$key, $value]);// hit
}

return $value;
}

/**
* Retrieve multiple items from the cache by key.// Retrieve multiple items from the cache
*
* Items not found in the cache will have a null value.// items not found in the cache will have a null value
*
* @param array $keys
* @return array
*/
public function many(array $keys)
{
$normalizedKeys = [];

foreach ($keys as $key => $value) {
$normalizedKeys[] = is_string($key) ? $key : $value;
}

$values = $this->store->many($normalizedKeys);

foreach ($values as $key => &$value) {
if (is_null($value)) {
$this->fireCacheEvent('missed', [$key]);

$value = isset($keys[$key]) ? value($keys[$key]) : null;
} else {
$this->fireCacheEvent('hit', [$key, $value]);
}
}

return $values;
}