
# Copyright 2017-present Open Networking Foundation
#
# 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 requests
from synchronizers.new_base.syncstep import SyncStep, DeferredException
from synchronizers.new_base.modelaccessor import *
from xos.logger import Logger, logging

logger = Logger(level=logging.INFO)

DATAPLANE_IP = "dataPlaneIp"
PREFIX = "prefix"
NEXT_HOP = "nextHop"

class SyncAddressManagerServiceInstance(SyncStep):
    provides=[AddressManagerServiceInstance]
    observes = AddressManagerServiceInstance
    requested_interval=30
       
    def get_fabric_onos_service_internal(self):
        # There will be a ServiceInstanceLink from the FabricService to the Fabric ONOS App
        fs = FabricService.objects.first()
        for link in fs.subscribed_links.all():
            if link.provider_service_instance:
                # cast from ServiceInstance to ONOSApp
                service_instance = link.provider_service_instance.leaf_model
                # cast from Service to ONOSService
                return service_instance.owner.leaf_model

        return None

    def get_fabric_onos_service(self):
        fos = self.get_fabric_onos_service_internal()
        if not fos:
            raise Exception("Fabric ONOS service not found")
        return fos

    def get_node_tag(self, node, tagname):
        tags = Tag.objects.filter(content_type=model_accessor.get_content_type_id(node),
                                  object_id=node.id,
                                  name=tagname)
        if tags:
            return tags[0].value
        else:
            return None

    def fetch_pending(self, deleted):
        # If fetch_pending is being called for delete, then just execute the standard delete logic.
        if deleted:
            return super(SyncAddressManagerServiceInstance, self).fetch_pending(deleted)

        fs = FabricService.objects.first()
        if (not fs) or (not fs.autoconfig):
            logger.info("Not FabricServer or not autoconfig. Returning []");
            return []

        objs = super(SyncAddressManagerServiceInstance, self).fetch_pending(deleted)
        objs = list(objs)

        # Check that each is a valid VSG tenant or instance
        for address_si in objs:
            sub = self.get_subscriber(address_si)
            if sub:
                if not sub.instance:
                    logger.info("Skipping %s because it has no instance" % address_si)
                    objs.remove(address_si)
            else:
                # Maybe the Address is for an instance
                # TODO: tenant_for_instance_id needs to be a real database field
                instance_id = address_si.get_attribute("tenant_for_instance_id")
                if not instance_id:
                    logger.info("Skipping %s because it has no tenant_for_instance_id" % address_si)
                    objs.remove(address_si)
                else:
                    instance = Instance.objects.filter(id=instance_id)[0]
                    if not instance.instance_name:
                        logger.info("Skipping %s because it has no instance.instance_name" % address_si)
                        objs.remove(address_si)

        return objs

    def get_subscriber(self, address_si):
        links = address_si.provided_links.all()
        for link in links:
            if not link.subscriber_service_instance:
                continue
            # cast from ServiceInstance to VSGTEnant or similar
            sub = link.subscriber_service_instance.leaf_model
            # TODO: check here to make sure it's an appropriate type of ServiceInstance ?
            return sub
        return None

    def get_routes_url(self, fos):
        url = 'http://%s:%s/onos/routeservice/routes' % (fos.rest_hostname, fos.rest_port)

        logger.info("url: %s" % url)
        return url

    def sync_record(self, address_si):
        fos = self.get_fabric_onos_service()

        data = self.map_tenant_to_route(address_si)

        r = self.post_route(fos, data)

        logger.info("Posted %s: status: %s result '%s'" % (address_si, r.status_code, r.text))

    def delete_record(self, address_si):
        pass
        # Disabled for now due to lack of feedback state field
        # self.delete_route(self.get_fabric_onos_service(),  self.map_tenant_to_route(address_si))


    def map_tenant_to_route(self, address_si):
        instance = None
        # Address setup is kind of hacky right now, we'll
        # need to revisit.  The idea is:
        # * Look up the instance corresponding to the address
        # * Look up the node running the instance
        # * Get the "dataPlaneIp" tag, push to the fabric

        sub = self.get_subscriber(address_si)
        if sub:
            instance = sub.instance
        else:
            instance_id = address_si.get_attribute("tenant_for_instance_id")
            instance = Instance.objects.filter(id=instance_id)[0]

        node = instance.node
        dataPlaneIp = node.dataPlaneIp

        if not dataPlaneIp:
            raise DeferredException("No IP found for node %s tenant %s -- skipping" % (str(node), str(address_si)))

        data = {
            PREFIX : "%s/32" % address_si.public_ip,
            NEXT_HOP : dataPlaneIp.split('/')[0]
        }

        return data

    def delete_route(self, fos, route):
        url = self.get_routes_url(fos)

        r = requests.delete(url, json=route, auth=(fos.rest_username, fos.rest_password))

        logger.info("status: %s" % r.status_code)
        logger.info('result: %s' % r.text)

        return r

    def post_route(self, fos, route):
        url = self.get_routes_url(fos)
        return requests.post(url, json=route, auth=(fos.rest_username, fos.rest_password))

