# 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.

from synchronizers.new_base.modelaccessor import *
from synchronizers.new_base.model_policies.model_policy_tenantwithcontainer import TenantWithContainerPolicy, LeastLoadedNodeScheduler
from synchronizers.new_base.exceptions import *

class HSSDBServiceInstancePolicy(TenantWithContainerPolicy):
    model_name = "HSSDBServiceInstance"
    constrain_by_service_instance = True

    def handle_create(self, service_instance):
        return self.handle_update(service_instance)

    def handle_update(self, service_instance):
        if (service_instance.link_deleted_count>0) and (not service_instance.provided_links.exists()):
            self.logger.info("The last provided link has been deleted -- self-destructing.")
            self.handle_delete(service_instance)
            if HSSDBServiceInstance.objects.filter(id=service_instance.id).exists():
                service_instance.delete()
            else:
                self.logger.info("Tenant %s is already deleted" % service_instance)
            return

        self.manage_container(service_instance)

    def handle_delete(self, service_instance):
        if service_instance.instance and (not service_instance.instance.deleted):
            all_service_instances_this_instance = HSSDBServiceInstance.objects.filter(instance_id=service_instance.instance.id)
            other_service_instances_this_instance = [x for x in all_service_instances_this_instance if x.id != service_instance.id]
            if (not other_service_instances_this_instance):
                self.logger.info("HSSDBServiceInstance %s is now unused -- deleting" % service_instance.instance)
                self.delete_instance(service_instance, service_instance.instance)
            else:
                self.logger.info("HSSDBServiceInstance %s has %d other service instances attached" % (service_instance.instance, len(other_service_instances_this_instance)))

    def get_service(self, service_instance):
        service_name = service_instance.owner.leaf_model_name
        service_class = globals()[service_name]
        return service_class.objects.get(id=service_instance.owner.id)

    def find_instance_for_instance_tag(self, instance_tag):
        tags = Tag.objects.filter(name="instance_tag", value=instance_tag)
        if tags:
            return tags[0].content_object
        return None

    def find_or_make_instance_for_instance_tag(self, service_instance):
        instance_tag = self.get_instance_tag(service_instance)
        instance = self.find_instance_for_instance_tag(instance_tag)
        if instance:
            if instance.no_sync:
                # if no_sync is still set, then perhaps we failed while saving it and need to retry.
                self.save_instance(service_instance, instance)
            return instance

        desired_image = self.get_image(service_instance)
        desired_flavor = self.get_flavor(service_instance)
        node_label = service_instance.node_label
        constrain_by_service_instance = self.constrain_by_service_instance

        slice = service_instance.owner.slices.first()

        scheduler = LeastLoadedNodeScheduler(slice, label=node_label, constrain_by_service_instance=constrain_by_service_instance)
        (node, parent) = scheduler.pick()

        assert (slice is not None)
        assert (node is not None)
        assert (desired_image is not None)
        assert (service_instance.creator is not None)
        assert (node.site_deployment.deployment is not None)
        assert (desired_image is not None)

        instance = Instance(slice=slice,
                            node=node,
                            image=desired_image,
                            creator=service_instance.creator,
                            deployment=node.site_deployment.deployment,
                            flavor=desired_flavor,
                            isolation=slice.default_isolation,
                            parent=parent)

        self.save_instance(service_instance, instance)

        return instance

    def manage_container(self, service_instance):
        if service_instance.deleted:
            return

        if service_instance.instance:
            # We're good.
            return

        instance = self.find_or_make_instance_for_instance_tag(service_instance)
        service_instance.instance = instance
        # TODO: possible for partial failure here?
        service_instance.save()

    def delete_instance(self, service_instance, instance):
        # delete the `instance_tag` tags
        tags = Tag.objects.filter(service_id=service_instance.owner.id, content_type=instance.self_content_type_id,
                                  object_id=instance.id, name="instance_tag")
        for tag in tags:
            tag.delete()

        tags = Tag.objects.filter(content_type=instance.self_content_type_id, object_id=instance.id,
                                  name="vm_vrouter_tenant")
        for tag in tags:
            address_manager_instances = list(ServiceInstance.objects.filter(id=tag.value))
            tag.delete()

            # TODO: Potential partial failure

            for address_manager_instance in address_manager_instances:
                self.logger.info("Deleting address_manager_instance %s" % address_manager_instance)
                address_manager_instance.delete()

        instance.delete()

    def save_instance(self, service_instance, instance):
        instance.no_sync = True   # prevent instance from being synced until we're done with it
        super(HSSDBServiceInstancePolicy, self).save_instance(instance)

        try:
            if instance.isolation in ["container", "container_vm"]:
                raise Exception("Not supported")

            instance_tag = self.get_instance_tag(service_instance)
            if instance_tag:
                tags = Tag.objects.filter(name="instance_tag", value=instance_tag)
                if not tags:
                    tag = Tag(service=service_instance.owner, content_type=instance.self_content_type_id, object_id=instance.id, name="instance_tag", value=str(instance_tag))
                    tag.save()

            instance.no_sync = False   # allow the synchronizer to run now
            super(HSSDBServiceInstancePolicy, self).save_instance(instance)
        except:
            # need to clean up any failures here
            raise

    def get_instance_tag(self, service_instance):
        return '%d'%service_instance.id

    def get_image(self, service_instance):
        return service_instance.hssdb_vendor.image

    def get_flavor(self, service_vendor):
        return service_vendor.hssdb_vendor.flavor