<?php

namespace App\AlbumSources;

use App\Photo;
use Guzzle\Http\EntityBody;
use Guzzle\Http\Exception\ClientErrorResponseException;
use Illuminate\Support\Facades\Log;
use OpenCloud\ObjectStore\Exception\ObjectNotFoundException;
use OpenCloud\OpenStack;
use Symfony\Component\HttpFoundation\File\File;

/**
 * Driver for managing files on an OpenStack Keystone+Swift compatible platform.
 * @package App\AlbumSources
 */
class OpenStackSource extends AlbumSourceBase implements IAlbumSource
{
    /**
     * Deletes an entire album's media contents.
     * @return void
     */
    public function deleteAlbumContents()
    {
        // Because all photos live in a single container, there is nothing "global" to delete for the entire album
        // The delete routine will have already removed all photos
    }

    /**
     * Deletes a thumbnail file for a photo.
     * @param Photo $photo Photo to delete the thumbnail from.
     * @param string $thumbnail Thumbnail to delete (or null to delete the original.)
     * @return void
     */
    public function deleteThumbnail(Photo $photo, $thumbnail = null)
    {
        $photoPath = $this->getPathToPhoto($photo, $thumbnail);

        try
        {
            $this->getContainer()->deleteObject($photoPath);
        }
        catch (ClientErrorResponseException $ex)
        {
            // Don't worry if the file no longer exists
            Log::warning('Failed deleting image from OpenStack.', ['error' => $ex->getMessage(), 'path' => $photoPath]);
        }
    }

    /**
     * Fetches the contents of a thumbnail for a photo.
     * @param Photo $photo Photo to fetch the thumbnail for.
     * @param string $thumbnail Thumbnail to fetch (or null to fetch the original.)
     * @return EntityBody
     */
    public function fetchPhotoContent(Photo $photo, $thumbnail = null)
    {
        $object = $this->getContainer()->getObject($this->getPathToPhoto($photo, $thumbnail));

        return $object->getContent();
    }

    /**
     * Gets the name of this album source.
     * @return string
     */
    public function getName()
    {
        return 'global.album_sources.openstack';
    }

    /**
     * Gets the absolute URL to the given photo file.
     * @param Photo $photo Photo to get the URL to.
     * @param string $thumbnail Thumbnail to get the image to.
     * @return string
     */
    public function getUrlToPhoto(Photo $photo, $thumbnail = null)
    {
        $cdnUrl = $this->configuration->cdn_url;
        if (strlen($cdnUrl) > 0)
        {
            if (substr($cdnUrl, strlen($cdnUrl) - 1, 1) == '/')
            {
                $cdnUrl = substr($cdnUrl, 0, strlen($cdnUrl) - 1);
            }

            return sprintf('%s/%s', $cdnUrl, $this->getPathToPhoto($photo, $thumbnail));
        }

        // Not using a CDN - use the standard download controller
        $photoUrl = route('downloadPhoto', [
            'albumUrlAlias' => $this->album->url_alias,
            'photoFilename' => $photo->storage_file_name
        ]);

        if (!is_null($thumbnail))
        {
            $photoUrl .= sprintf('?t=%s', urlencode($thumbnail));
        }

        return $photoUrl;
    }

    /**
     * Saves a generated thumbnail to its permanent location.
     * @param Photo $photo Photo the image relates to.
     * @param string $tempFilename Filename containing the image.
     * @param string $thumbnail Name of the thumbnail (or null for the original.)
     * @return mixed
     */
    public function saveThumbnail(Photo $photo, $tempFilename, $thumbnail = null)
    {
        $photoPath = $this->getPathToPhoto($photo, $thumbnail);

        $container = $this->getContainer();
        $container->uploadObject($photoPath, fopen($tempFilename, 'r+'));
    }

    protected function getClient()
    {
        return new OpenStack($this->configuration->auth_url, [
            'username' => $this->configuration->username,
            'password' => decrypt($this->configuration->password),
            'tenantName' => $this->configuration->tenant_name,
        ]);
    }

    protected function getContainer()
    {
        return $this->getStorageService()->getContainer($this->configuration->container_name);
    }

    protected function getStorageService()
    {
        return $this->getClient()->objectStoreService(
            $this->configuration->service_name,
            $this->configuration->service_region,
            'publicURL'
        );
    }

    protected function getOriginalsFolder()
    {
        return '_originals';
    }

    protected function getPathToPhoto(Photo $photo, $thumbnail = null)
    {
        return sprintf(
            '%s/%s/%s',
            $this->album->url_alias,
            is_null($thumbnail) ? $this->getOriginalsFolder() : $thumbnail,
            $photo->storage_file_name
        );
    }
}