# Copyright (c) 2012-2013, Mark Peek <mark@peek.org>
# Copyright (c) 2014, Andy Botting <andy.botting@theguardian.com>
# All rights reserved.
#
# See LICENSE file for full license.


from troposphere import AWSObject, AWSProperty
from troposphere.validators import boolean, integer, network_port


class BlockDeviceMapping(AWSProperty):
    props = {
        'delete_on_termination': (boolean, False),
        'device_name': (str, True),
        'snapshot_id': (str, False),
        'volume_id': (str, False),
        'volume_size': (integer, False),
    }


class BlockDeviceMappingV2(AWSProperty):
    props = {
        'boot_index': (integer, False),
        'delete_on_termination': (boolean, False),
        'device_name': (str, False),
        'device_type': (str, False),
        'disk_bus': (str, False),
        'ephemeral_format': (str, False),
        'ephemeral_size': (integer, False),
        'image_id': (str, False),
        'snapshot_id': (str, False),
        'swap_size': (integer, False),
        'volume_id': (str, False),
        'volume_size': (integer, False),
    }

    def validate(self):
        if 'device_type' in self.resource:
            device_type = self.resource['device_type']
            if device_type not in ['cdrom', 'disk']:
                raise ValueError(
                    "The device_type attribute "
                    "must be either cdrom or disk")

        if 'disk_bus' in self.resource:
            disk_bus = self.resource['disk_bus']
            if disk_bus not in ['ide', 'lame_bus', 'scsi', 'usb', 'virtio']:
                raise ValueError(
                    "The device_bus attribute "
                    "must be one of ide, lame_bus, scsi, usb or virtio")

        if 'ephemeral_format' in self.resource:
            ephemeral_format = self.resource['ephemeral_format']
            if ephemeral_format not in ['ext2', 'ext3', 'ext4', 'xfs', 'ntfs']:
                raise ValueError(
                    "The device_type attribute "
                    "must be one of ext2, ext3, ext4, xfs, ntfs")


class Network(AWSProperty):
    props = {
        'fixed_ip': (str, False),
        'network': (str, False),
        'port': (network_port, False),
    }


class FloatingIP(AWSObject):
    resource_type = "OS::Nova::FloatingIP"

    props = {
        'pool': (str, False),
    }


class FloatingIPAssociation(AWSObject):
    resource_type = "OS::Nova::FloatingIPAssociation"

    props = {
        'floating_ip': (str, True),
        'server_ip': (str, True),
    }


class KeyPair(AWSObject):
    resource_type = "OS::Nova::KeyPair"

    props = {
        'name': (str, True),
        'public_key': (str, False),
        'save_private_key': (boolean, False),
    }


class Server(AWSObject):
    resource_type = "OS::Nova::Server"

    props = {
        'admin_pass': (str, False),
        'admin_user': (str, False),
        'availability_zone': (str, False),
        'block_device_mapping': (list, False),
        'block_device_mapping_v2': (list, False),
        'config_drive': (str, False),
        'diskConfig': (str, False),
        'flavor': (str, False),
        'flavor_update_policy': (str, False),
        'image': (str, True),
        'image_update_policy': (str, False),
        'key_name': (str, False),
        'metadata': (dict, False),
        'name': (str, False),
        'personality': (dict, False),
        'networks': (list, True),
        'reservation_id': (str, False),
        'scheduler_hints': (dict, False),
        'security_groups': (list, False),
        'software_config_transport': (str, False),
        'user_data': (str, False),
        'user_data_format': (str, False),
    }

    def validate(self):
        if 'diskConfig' in self.resource:
            diskConfig = self.resource['diskConfig']
            if diskConfig not in ['AUTO', 'MANUAL']:
                raise ValueError(
                    "The diskConfig attribute "
                    "must be either AUTO or MANUAL")

        if 'flavor_update_policy' in self.resource:
            flavor_update_policy = self.resource['flavor_update_policy']
            if flavor_update_policy not in ['RESIZE', 'REPLACE']:
                raise ValueError(
                    "The flavor_update_policy attribute "
                    "must be either RESIZE or REPLACE")

        if 'image_update_policy' in self.resource:
            image_update_policy = self.resource['flavor_update_policy']
            if image_update_policy not in ['REBUILD', 'REPLACE',
                                           'REBUILD_PRESERVE_EPHEMERAL']:
                raise ValueError(
                    "The image_update_policy attribute "
                    "must be either REBUILD, REPLACE or "
                    "REBUILD_PRESERVE_EPHEMERAL")

        if 'software_config_transport' in self.resource:
            sct = self.resource['software_config_transport']
            if sct not in ['POLL_SERVER_CFN', 'POLL_SERVER_HEAT']:
                raise ValueError(
                    "The software_config_transport attribute "
                    "must be either POLL_SERVER_CFN or POLL_SERVER_HEAT")

        if 'user_data_format' in self.resource:
            user_data_format = self.resource['user_data_format']
            if user_data_format not in ['HEAT_CFNTOOLS', 'RAW']:
                raise ValueError(
                    "The user_data_format attribute "
                    "must be either HEAT_CFNTOOLS or RAW")

        return True
