# Copyright (c) 2014 OpenStack Foundation.  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.

import sqlalchemy as sa
from sqlalchemy import orm

from neutron.db import db_base_plugin_v2
from neutron.db import model_base
from neutron.extensions import l3


class RouterExtraAttributes(model_base.BASEV2):
    """Additional attributes for a Virtual Router."""

    # NOTE(armando-migliaccio): this model can be a good place to
    # add extension attributes to a Router model. Each case needs
    # to be individually examined, however 'distributed' and other
    # simple ones fit the pattern well.
    __tablename__ = "router_extra_attributes"
    router_id = sa.Column(sa.String(36),
                          sa.ForeignKey('routers.id', ondelete="CASCADE"),
                          primary_key=True)
    # Whether the router is a legacy (centralized) or a distributed one
    distributed = sa.Column(sa.Boolean, default=False,
                            server_default=sa.sql.false(),
                            nullable=False)
    # Whether the router is to be considered a 'service' router
    service_router = sa.Column(sa.Boolean, default=False,
                               server_default=sa.sql.false(),
                               nullable=False)
    ha = sa.Column(sa.Boolean, default=False,
                   server_default=sa.sql.false(),
                   nullable=False)
    ha_vr_id = sa.Column(sa.Integer())
    # Availability Zone support
    availability_zone_hints = sa.Column(sa.String(255))

    router = orm.relationship(
        'Router',
        backref=orm.backref("extra_attributes", lazy='joined',
                            uselist=False, cascade='delete'))


class ExtraAttributesMixin(object):
    """Mixin class to enable router's extra attributes."""

    extra_attributes = []

    def _extend_extra_router_dict(self, router_res, router_db):
        extra_attrs = router_db['extra_attributes'] or {}
        for attr in self.extra_attributes:
            name = attr['name']
            default = attr['default']
            router_res[name] = (
                extra_attrs[name] if name in extra_attrs else default)

    def _get_extra_attributes(self, router, extra_attributes):
        return (dict((attr['name'],
                      router.get(attr['name'], attr['default']))
                for attr in extra_attributes))

    def _process_extra_attr_router_create(
        self, context, router_db, router_req):
        kwargs = self._get_extra_attributes(router_req, self.extra_attributes)
        # extra_attributes reference is populated via backref
        if not router_db['extra_attributes']:
            attributes_db = RouterExtraAttributes(
                router_id=router_db['id'], **kwargs)
            context.session.add(attributes_db)
            router_db['extra_attributes'] = attributes_db
        else:
            # The record will exist if RouterExtraAttributes model's
            # attributes are added with db migrations over time
            router_db['extra_attributes'].update(kwargs)

    db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(
        l3.ROUTERS, ['_extend_extra_router_dict'])
