# vim: tabstop=4 shiftwidth=4 softtabstop=4

# Copyright 2012-2013 NEC Corporation.
# All rights reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.
#
# @author: Ryota MIBU
#

from oslo.config import cfg

from neutron.api import extensions
from neutron.api.v2 import attributes
from neutron.api.v2 import base
from neutron.common import exceptions
from neutron.manager import NeutronManager
from neutron import quota


quota_packet_filter_opts = [
    cfg.IntOpt('quota_packet_filter',
               default=100,
               help=_("Number of packet_filters allowed per tenant, "
                      "-1 for unlimited"))
]
cfg.CONF.register_opts(quota_packet_filter_opts, 'QUOTAS')


def convert_to_int(data):
    try:
        return int(data, 0)
    except (ValueError, TypeError):
        pass
    try:
        return int(data)
    except (ValueError, TypeError):
        msg = _("'%s' is not a integer") % data
        raise exceptions.InvalidInput(error_message=msg)


ALIAS = 'packet-filter'
RESOURCE = 'packet_filter'
COLLECTION = 'packet_filters'
PACKET_FILTER_ACTION_REGEX = '(?i)^(allow|accept|drop|deny)$'
PACKET_FILTER_PROTOCOL_REGEX = (
    '(?i)^(icmp|tcp|udp|arp|0x[0-9a-fA-F]+|[0-9]+|)$')
PACKET_FILTER_ATTR_PARAMS = {
    'id': {'allow_post': False, 'allow_put': False,
           'validate': {'type:uuid': None},
           'is_visible': True},
    'name': {'allow_post': True, 'allow_put': True, 'default': '',
             'validate': {'type:string': None},
             'is_visible': True},
    'tenant_id': {'allow_post': True, 'allow_put': False,
                  'validate': {'type:string': None},
                  'required_by_policy': True,
                  'is_visible': True},
    'network_id': {'allow_post': True, 'allow_put': False,
                   'validate': {'type:uuid': None},
                   'is_visible': True},
    'admin_state_up': {'allow_post': True, 'allow_put': True,
                       'default': True,
                       'convert_to': attributes.convert_to_boolean,
                       'is_visible': True},
    'status': {'allow_post': False, 'allow_put': False,
               'is_visible': True},
    'action': {'allow_post': True, 'allow_put': True,
               'validate': {'type:regex': PACKET_FILTER_ACTION_REGEX},
               'is_visible': True},
    'priority': {'allow_post': True, 'allow_put': True,
                 'convert_to': convert_to_int,
                 'is_visible': True},
    'in_port': {'allow_post': True, 'allow_put': False,
                'default': attributes.ATTR_NOT_SPECIFIED,
                'validate': {'type:uuid': None},
                'is_visible': True},
    'src_mac': {'allow_post': True, 'allow_put': True,
                'default': attributes.ATTR_NOT_SPECIFIED,
                'validate': {'type:mac_address': None},
                'is_visible': True},
    'dst_mac': {'allow_post': True, 'allow_put': True,
                'default': attributes.ATTR_NOT_SPECIFIED,
                'validate': {'type:mac_address': None},
                'is_visible': True},
    'eth_type': {'allow_post': True, 'allow_put': True,
                 'default': attributes.ATTR_NOT_SPECIFIED,
                 'convert_to': convert_to_int,
                 'is_visible': True},
    'src_cidr': {'allow_post': True, 'allow_put': True,
                 'default': attributes.ATTR_NOT_SPECIFIED,
                 'validate': {'type:subnet': None},
                 'is_visible': True},
    'dst_cidr': {'allow_post': True, 'allow_put': True,
                 'default': attributes.ATTR_NOT_SPECIFIED,
                 'validate': {'type:subnet': None},
                 'is_visible': True},
    'protocol': {'allow_post': True, 'allow_put': True,
                 'default': attributes.ATTR_NOT_SPECIFIED,
                 'validate': {'type:regex': PACKET_FILTER_PROTOCOL_REGEX},
                 'is_visible': True},
    'src_port': {'allow_post': True, 'allow_put': True,
                 'default': attributes.ATTR_NOT_SPECIFIED,
                 'convert_to': convert_to_int,
                 'is_visible': True},
    'dst_port': {'allow_post': True, 'allow_put': True,
                 'default': attributes.ATTR_NOT_SPECIFIED,
                 'convert_to': convert_to_int,
                 'is_visible': True},
}
PACKET_FILTER_ATTR_MAP = {COLLECTION: PACKET_FILTER_ATTR_PARAMS}


class Packetfilter(extensions.ExtensionDescriptor):

    @classmethod
    def get_name(cls):
        return ALIAS

    @classmethod
    def get_alias(cls):
        return ALIAS

    @classmethod
    def get_description(cls):
        return "PacketFilters on OFC"

    @classmethod
    def get_namespace(cls):
        return "http://www.nec.co.jp/api/ext/packet_filter/v2.0"

    @classmethod
    def get_updated(cls):
        return "2013-07-16T00:00:00+09:00"

    @classmethod
    def get_resources(cls):
        qresource = quota.CountableResource(RESOURCE,
                                            quota._count_resource,
                                            'quota_%s' % RESOURCE)
        quota.QUOTAS.register_resource(qresource)

        resource = base.create_resource(COLLECTION, RESOURCE,
                                        NeutronManager.get_plugin(),
                                        PACKET_FILTER_ATTR_PARAMS)
        pf_ext = extensions.ResourceExtension(
            COLLECTION, resource, attr_map=PACKET_FILTER_ATTR_PARAMS)
        return [pf_ext]

    def update_attributes_map(self, attributes):
        super(Packetfilter, self).update_attributes_map(
            attributes, extension_attrs_map=PACKET_FILTER_ATTR_MAP)

    def get_extended_resources(self, version):
        if version == "2.0":
            return PACKET_FILTER_ATTR_MAP
        else:
            return {}
