# Copyright (c) 2015, DjaoDjin inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
#    this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import logging, os

from django.core.files.storage import get_storage_class, FileSystemStorage
#pylint:disable=no-name-in-module,import-error
from django.utils.six.moves.urllib.parse import urljoin

from . import settings
from .compat import import_string
from .models import MediaTag, PageElement

LOGGER = logging.getLogger(__name__)


class AccountMixin(object):

    account_url_kwarg = settings.ACCOUNT_URL_KWARG

    @staticmethod
    def get_account():
        if settings.GET_CURRENT_ACCOUNT:
            return import_string(settings.GET_CURRENT_ACCOUNT)()
        return None


class UploadedImageMixin(object):

    @staticmethod
    def update_media_tag(tags, list_media):
        for item in list_media['results']:
            media_tags = MediaTag.objects.filter(location=item['location'])
            new_media_tags = []
            if tags:
                for tag in tags:
                    if tag != "":
                        new_media_tag, _ = MediaTag.objects.get_or_create(
                            tag=tag, location=item['location'])
                        new_media_tags += [new_media_tag]

            # compare new list and delete removed tags.
            for tag in media_tags:
                if not tag in new_media_tags:
                    tag.delete()

    @staticmethod
    def delete_media_items(storage, list_media):
        for item in list_media['results']:
            storage.delete(item['media'])

            # Delete all MediaTag and PageElement using this location
            MediaTag.objects.filter(location=item['location']).delete()
            PageElement.objects.filter(text=item['location']).delete()

    @staticmethod
    def build_filter_list(validated_data):
        items = validated_data.get('items')
        filter_list = []
        if items:
            for item in items:
                filter_list = item['location']
        return filter_list

    @staticmethod
    def list_media(storage, filter_list):
        """
        Return a list of media from default storage
        """
        results = []
        total = 0
        try:
            for media in storage.listdir('.')[1]:
                if not media.endswith('/') and media != "":
                    location = storage.url(media).split('?')[0]
                    total += 1
                    if not filter_list or location in filter_list:
                        results += [
                            {'location': location,
                            'tags': MediaTag.objects.filter(
                                location=location).values_list(
                                'tag', flat=True)
                            }]
        except OSError:
            LOGGER.warning("Unable to list objects in FileSystemStorage.")
        return {'count': total, 'results': results}

    @staticmethod
    def list_delete_media(storage, filter_list):

        results = []
        total = 0
        try:
            for media in storage.listdir('.')[1]:
                if not media.endswith('/') and media != "":
                    location = storage.url(media).split('?')[0]
                    total += 1
                    if filter_list and location in filter_list:
                            results += [
                                {'location': location,
                                'media': media}]
        except OSError:
            LOGGER.warning("Unable to list objects in FileSystemStorage.")
        return {'count': total, 'results': results}

    @staticmethod
    def get_bucket_name(account=None):
        if not account:
            return settings.AWS_STORAGE_BUCKET_NAME
        try:
            bucket_name = account.bucket_name
        except AttributeError:
            LOGGER.debug("``%s`` does not contain a ``bucket_name``"\
                " field, using ``slug`` instead.", account.__class__)
            bucket_name = None
        if not bucket_name:
            # We always need a non-empty bucket_name in order
            # to partition the namespace.
            bucket_name = account.slug
        return bucket_name

    @staticmethod
    def get_media_prefix(account=None):
        if not account:
            return settings.MEDIA_PREFIX
        try:
            return account.media_prefix
        except AttributeError:
            LOGGER.debug("``%s`` does not contain a ``media_prefix``"\
                " field.", account.__class__)
        return ""

    def get_default_storage(self, account=None):
        storage_class = get_storage_class()
        try:
            _ = storage_class.bucket_name
            return storage_class(
                bucket=self.get_bucket_name(account),
                location=self.get_media_prefix(account))
        except AttributeError:
            LOGGER.debug("``%s`` does not contain a ``bucket_name``"\
                " field, default to FileSystemStorage.", storage_class)
        return self.get_file_system_storage(account)

    def get_file_system_storage(self, account=None):
        location = settings.MEDIA_ROOT
        base_url = settings.MEDIA_URL
        bucket_name = self.get_bucket_name(account)
        if bucket_name:
            location = os.path.join(location, bucket_name)
            base_url = urljoin(base_url, bucket_name + '/')
        prefix = self.get_media_prefix(account)
        if prefix:
            location = os.path.join(location, prefix)
            base_url = urljoin(base_url, prefix)
        return FileSystemStorage(location=location, base_url=base_url)

@@ -1534,16 +1534,59 @@
  urljoin
+%0Afrom boto.exception import S3ResponseError
 %0A%0Afrom .
@@ -4095,62 +4095,225 @@
 GER.
-warning(%22Unable to list objects in FileSystemStorage.%22
+error(%0A                %22Unable to list objects in %25s.%22, storage.__class__.__name__)%0A        except S3ResponseError:%0A            LOGGER.error(%0A                %22Unable to list objects in %25s bucket.%22, storage.bucket_name
 )%0A  
@@ -4944,62 +4944,225 @@
 GER.
-warning(%22Unable to list objects in FileSystemStorage.%22
+error(%0A                %22Unable to list objects in %25s.%22, storage.__class__.__name__)%0A        except S3ResponseError:%0A            LOGGER.error(%0A                %22Unable to list objects in %25s bucket.%22, storage.bucket_name
 )%0A  

Improve list exceptions