"""
smartaws.ec2.internet_gateway
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This module manages Amazon internet gateway objects and related resources.

:copyright: (c) 2016 by Yann Lambret.
:license: MIT, see LICENSE for more details.
"""
from boto3 import Session
from botocore.exceptions import ClientError

from smartaws import log
from smartaws.ec2 import base


logger = log.get_logger(__name__)


class InternetGatewayWrapper(base.BaseWrapper):
    """
    Wrapper class for :class:`boto3.resources.factory.ec2.InternetGateway`
    objects.
    """
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)


def _add_wrapper(base_classes, **kwargs):
    """
    Register the :class:`InternetGatewayWrapper` class.

    See `Boto 3 Extensibility Guide
    <http://boto3.readthedocs.org/en/latest/guide/events.html>`_
    """
    base_classes.insert(0, InternetGatewayWrapper)


class InternetGatewayHandler(base.BaseHandler):
    """Manage a :class:`InternetGatewayWrapper` object's lifecycle."""

    def __init__(self, ctx, credentials):
        """Create boto3 session and clients."""
        super().__init__()

        # Create a boto session and add extra features
        # to the base class EC2.InternetGateway
        event = 'creating-resource-class.ec2.InternetGateway'
        self._session = Session(**credentials)
        self._session.events.register(event, _add_wrapper)

        # boto3 clients
        self._ec2 = self._session.resource('ec2')
        self._client = self._session.client('ec2')

        # Context for the resource we want
        # to create, update or delete
        self._ctx = ctx
        self._name = ctx.get('name')

    def create_resource(self):
        """Create an internet gateway, or update it if it already exists."""
        try:
            self._resource = self._load(self._name, manager_name='internet_gateways')
        except ValueError as err:
            logger.critical(err)
            return

        if self._resource:
            logger.info('Internet gateway %s already exists.', self._name)
        else:
            self._create_internet_gateway()

        # Store the object in the cache for future use
        with self._lock:
            self._cache[self._name] = self._resource

    def update_resource(self):
        """Update an internet gateway."""
        try:
            self._resource = self._load(self._name, manager_name='internet_gateways')
        except ValueError as err:
            logger.critical(err)
            return

        if self._resource:
            self._update_internet_gateway()

            # Store the object in the cache for future use
            with self._lock:
                self._cache[self._name] = self._resource
        else:
            logger.error('Internet gateway %s does not exist.', self._name)

    def delete_resource(self):
        """Delete a :class:`InternetGatewayWrapper` object."""
        try:
            self._resource = self._load(self._name, manager_name='internet_gateways')
        except ValueError as err:
            logger.critical(err)
            return

        if self._resource:
            logger.info('Removing internet gateway %s.', self._name)
            if self._resource.attachments:
                # If the internet gateway is attached to a VPC,
                # we don't take the responsibility to detach it
                vpc_id = self._resource.attachments[0]['VpcId']
                logger.warning(
                    'The internet gateway %s is currently attached to VPC %s.'
                    ' Operation not performed.', self._name, vpc_id
                )
            else:
                try:
                    self._client.delete_internet_gateway(InternetGatewayId=self._resource.id)
                except ClientError as exc:
                    logger.error(exc)
        else:
            logger.error('Internet gateway %s does not exist.', self._name)

    def _create_internet_gateway(self):
        """Create a :class:`InternetGatewayWrapper` object."""
        logger.info('Creating internet gateway %s.', self._name)
        try:
            self._resource = self._ec2.create_internet_gateway()
        except ClientError as exc:
            logger.error(exc)
            return

        # Set the value of the 'Name' tag
        self._resource.name = self._name

        # Update other object attributes
        self._update_internet_gateway()

    def _update_internet_gateway(self):
        """Update a :class:`InternetGatewayWrapper` object."""
        self._update_tags()


def create_handler(ctx, credentials):
    """
    Helper funcion to create a :class:`InternetGatewayHandler` object.

    :param ctx:
        A dictionary that contains specific values for a
        :class:`boto3.resources.factory.ec2.InternetGateway` object

    :param credentials:
        A dictionary that contains AWS credentials and the target AWS region.

    :return:
        :class:`InternetGatewayHandler <InternetGatewayHandler>` object.

    :rtype:
        smartaws.ec2.internet_gateway.InternetGatewayHandler
    """
    return InternetGatewayHandler(ctx, credentials)
