namespace Illuminate\Filesystem;

use Closure;
use Aws\S3\S3Client;
use OpenCloud\Rackspace;
use Illuminate\Support\Arr;
use InvalidArgumentException;
use League\Flysystem\AdapterInterface;
use League\Flysystem\FilesystemInterface;
use League\Flysystem\Filesystem as Flysystem;
use League\Flysystem\Adapter\Ftp as FtpAdapter;
use League\Flysystem\Rackspace\RackspaceAdapter;
use League\Flysystem\Adapter\Local as LocalAdapter;
use League\Flysystem\AwsS3v3\AwsS3Adapter as S3Adapter;
use Illuminate\Contracts\Filesystem\Factory as FactoryContract;
// so many namespace
class FilesystemManager implements FactoryContract
{// a Files system Manager can be design by a factory contract
/**
* The application instance.
*
* @var \Illuminate\Contracts\Foundation\Application
*/
protected $app;// a protected attr be use as an instance of application.

/**
* The array of resolved filesystem drivers.
*
* @var array
*/
protected $disks = [];// drivers like a store array

/**
* The registered custom driver creators.
*
* @var array
*/
protected $customCreators = [];// normal creator be registered

/**
* Create a new filesystem manager instance.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @return void
*/
public function __construct($app)
{
$this->app = $app;
}// use this special method to create a app about instance of this application
// shit ,it is a foreigner! use a app instance. so we will pay attention to it.

/**
* Get a filesystem instance.
*
* @param string $name
* @return \Illuminate\Contracts\Filesystem\Filesystem
*/
public function drive($name = null)
{
return $this->disk($name);// a wrap or a alias
}// Get a filesystem instance

/**
* Get a filesystem instance.
*
* @param string $name
* @return \Illuminate\Contracts\Filesystem\Filesystem
*/
public function disk($name = null)
{
$name = $name ?: $this->getDefaultDriver();// if has a drivers use it ,or use this default

return $this->disks[$name] = $this->get($name);// set the name.
}// get file system instance in this disks

/**
* Get a default cloud filesystem instance.
*
* @return \Illuminate\Contracts\Filesystem\Filesystem
*/
public function cloud()
{
$name = $this->getDefaultCloudDriver();// so better ! use a cloud ,so cool

return $this->disks[$name] = $this->get($name); // same to disk and drive
}// Get a default cloud filesystem instance

/**
* Attempt to get the disk from the local cache.
*
* @param string $name
* @return \Illuminate\Contracts\Filesystem\Filesystem
*/
protected function get($name)
{
return isset($this->disks[$name]) ? $this->disks[$name] : $this->resolve($name);
}// get disk. if you found it ,it a loop with a judge,
// this important method is who, that is resolve()

/**
* Resolve the given disk.
*
* @param string $name
* @return \Illuminate\Contracts\Filesystem\Filesystem
*
* @throws \InvalidArgumentException
*/
protected function resolve($name)
{
$config = $this->getConfig($name);// first get config by name

if (isset($this->customCreators[$config['driver']])) {
return $this->callCustomCreator($config);
}// if set this customCreators driver , this like to set config is better then set.

$driverMethod = 'create'.ucfirst($config['driver']).'Driver';// get the default method

if (method_exists($this, $driverMethod)) {// if has this method
return $this->{$driverMethod}($config);// use it, {} will more better
} else {// can't found so throw Exception
throw new InvalidArgumentException("Driver [{$config['driver']}] is not supported.");
}
}// resolve is a real function to get this disk

/**
* Call a custom driver creator.
*
* @param array $config
* @return \Illuminate\Contracts\Filesystem\Filesystem
*/
protected function callCustomCreator(array $config)
{
$driver = $this->customCreators[$config['driver']]($this->app, $config);// get a driver

if ($driver instanceof FilesystemInterface) {
return $this->adapt($driver);
}// use a driver ,if it is a instanceof the File stemInterface

return $driver;
}// Call a custom driver creator