
# 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 os, sys
from itertools import chain

from synchronizers.new_base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible #if needed
from synchronizers.new_base.ansible_helper import run_template_ssh #if needed
from synchronizers.new_base.modelaccessor import *
from xos.logger import Logger, logging
from synchronizers.metronetwork.providers.providerfactory import ProviderFactory
from synchronizers.metronetwork.invokers.invokerfactory import InvokerFactory

# metronetwork will be in steps/..
parentdir = os.path.join(os.path.dirname(__file__), "..")
sys.path.insert(0, parentdir)

logger = Logger(level=logging.INFO)


class SyncMetroNetworkSystem(SyncStep):
    provides = [MetroNetworkSystem]
    observes = MetroNetworkSystem
    requested_interval = 0
    initialized = False

    def __init__(self, **args):
        SyncStep.__init__(self, **args)

    def fetch_pending(self, deletion=False):

        # The general idea:
        # We do one of two things in here:
        #    1. Full Synchronization of the DBS (XOS <-> MetroONOS)
        #    2. Look for updates between the two stores
        # The first thing is potentially a much bigger
        # operation and should not happen as often
        #
        # The Sync operation must take into account the 'deletion' flag

        objs = []

        # Get the NetworkSystem object - if it exists it will test us
        # whether we should do a full sync or not - it all has our config
        # information about the REST interface

        metronetworksystem = self.get_metronetwork_system()
        if not metronetworksystem:
            logger.debug("No Service configured")
            return objs

        # Check to make sure the Metro Network System is enabled
        metronetworksystem = self.get_metronetwork_system()
        if metronetworksystem.administrativeState == 'disabled':
            # Nothing to do
            logger.debug("MetroService configured - state is Disabled")
            return objs

        # The Main Loop - retrieve all the NetworkDevice objects - for each of these
        # Apply synchronization aspects
        networkdevices = NetworkDevice.objects.all()

        for dev in networkdevices:

            # Set up the provider
            provider = ProviderFactory.getprovider(dev)

            # First check is for the AdminState of Disabled - do nothing
            if dev.administrativeState == 'disabled':
                # Nothing to do with this device
                logger.debug("NetworkDevice %s: administrativeState set to Disabled - continuing" % dev.id)

            # Now to the main options - are we syncing - deletion portion
            elif dev.administrativeState == 'syncrequested' and deletion is True:

                logger.info("NetworkDevice %s: administrativeState set to SyncRequested" % dev.id)

                # Kill Links
                networklinks = provider.get_network_links_for_deletion()
                for link in networklinks:
                    objs.append(link)

                # Kill Ports
                allports = provider.get_network_ports_for_deletion()
                for port in allports:
                    objs.append(port)

                logger.info("NetworkDevice %s: Deletion part of Sync completed" % dev.id)
                dev.administrativeState = 'syncinprogress'
                dev.save(update_fields=['administrativeState'])

            # Now to the main options - are we syncing - creation portion
            elif dev.administrativeState == 'syncinprogress' and deletion is False:

                logger.info("NetworkDevice %s: administrativeState set to SyncRequested" % dev.id)
                # Reload objects in the reverse order of deletion

                # Add Ports
                networkports = provider.get_network_ports()
                for port in networkports:
                    objs.append(port)

                # Add Links
                networklinks = provider.get_network_links()
                for link in networklinks:
                    objs.append(link)

                logger.info("NetworkDevice %s: Creation part of Sync completed" % dev.id)
                dev.administrativeState = 'enabled'
                dev.save(update_fields=['administrativeState'])

            # If we are enabled - then check for events - in either direction and sync
            elif dev.administrativeState == 'enabled' and deletion is False:
                logger.debug("NetworkDevice: administrativeState set to Enabled - non deletion phase")

                # This should be the 'normal running state' when we are not deleting - a few things to do in here

                # Get the changed objects from the provider - deletions are handled separately
                eventobjs = provider.get_updated_or_created_objects()
                for eventobj in eventobjs:
                    # Simply put in the queue for update - this will handle both new and changed objects
                    objs.append(eventobj)

                # Handle changes XOS -> ONOS
                # Check for ConnectivityObjects that are in acticationequested state - creates to the backend
                p2pactivatereqs = NetworkEdgeToEdgePointConnection.objects.filter(adminstate='activationrequested')
                mp2mpactivatereqs = NetworkMultipointToMultipointConnection.objects.filter(adminstate='activationrequested')
                r2mpactivatereqs = NetworkEdgeToMultipointConnection.objects.filter(adminstate='activationrequested')
                activatereqs = list(chain(p2pactivatereqs, mp2mpactivatereqs, r2mpactivatereqs))
                for activatereq in activatereqs:

                    # Call the XOS Interface to create the service
                    logger.debug("Attempting to create EdgePointToEdgePointConnectivity: %s" % activatereq.id)
                    if (provider.create_network_connectivity(activatereq)):
                        # Everyting is OK, lets let the system handle the persist
                        objs.append(activatereq)
                    else:
                        # In the case of an error we persist the state of the object directly to preserve
                        # the error code - and because that is how the base synchronizer is designed
                        activatereq.save()

                # Check for ConnectivityObjects that are in deacticationequested state - deletes to the backend
                p2pdeactivatereqs = NetworkEdgeToEdgePointConnection.objects.filter(adminstate='deactivationrequested')
                mp2mpdeactivatereqs = NetworkMultipointToMultipointConnection.objects.filter(adminstate='deactivationrequested')
                r2mpdeactivatereqs = NetworkEdgeToMultipointConnection.objects.filter(adminstate='deactivationrequested')
                deactivatereqs = list(chain(p2pdeactivatereqs, mp2mpdeactivatereqs, r2mpdeactivatereqs))
                for deactivatereq in deactivatereqs:

                    # Call the XOS Interface to delete the service
                    logger.debug("Attempting to delete EdgePointToEdgePointConnectivity: %s" % deactivatereq.id)
                    if provider.delete_network_connectivity(deactivatereq):
                        # Everyting is OK, lets let the system handle the persist
                        objs.append(deactivatereq)
                    else:
                        # In the case of an error we persist the state of the object directly to preserve
                        # the error code - and because that is how the base synchronizer is designed
                        deactivatereq.save()

            # If we are enabled - and in our deletion pass then look for objects waiting for deletion
            elif dev.administrativeState == 'enabled' and deletion is True:
                logger.debug("NetworkDevice: administrativeState set to Enabled - deletion phase")

                # Any object that is simply deleted in the model gets removed automatically - the synchronizer
                # doesn't get involved - we just need to check for deleted objects in the domain and reflect that
                # in the model
                #
                # Get the deleted objects from the provider
                eventobjs = provider.get_deleted_objects()
                for eventobj in eventobjs:
                    # Simply put in the queue for update - this will handle both new and changed objects
                    objs.append(eventobj)

                # Handle the case where we have deleted Eline Services from our side - if the Service is in
                # enabled state then we call the provider, otherwise just queue it for deletion
                elinedeletedobjs = NetworkEdgeToEdgePointConnection.deleted_objects.all()
                for elinedeletedobj in elinedeletedobjs:
                    if elinedeletedobj.adminstate == 'enabled':
                        provider.delete_network_connectivity(elinedeletedobj)
                    # Either way queue it for deletion
                    objs.append(elinedeletedobj)

                # Handle the case where we have deleted Etree Services from our side - if the Service is in
                # enabled state then we call the provider, otherwise just queue it for deletion
                etreedeletedobjs = NetworkEdgeToMultipointConnection.deleted_objects.all()
                for etreedeletedobj in etreedeletedobjs:
                    # TODO: Handle the case where its connected, we need to disconnect first
                    if etreedeletedobj.adminstate == 'enabled':
                        provider.delete_network_connectivity(etreedeletedobj)
                    # Either way queue it for deletion
                    objs.append(etreedeletedobj)

                # Handle the case where we have deleted Elan Services from our side - if the Service is in
                # enabled state then we call the provider, otherwise just queue it for deletion
                elandeletedobjs = NetworkMultipointToMultipointConnection.deleted_objects.all()
                for elandeletedobj in elandeletedobjs:
                    # TODO: Handle the case where its connected, we need to disconnect first
                    if elandeletedobj.adminstate == 'enabled':
                        provider.delete_network_connectivity(elandeletedobj)
                    # Either way queue it for deletion
                    objs.append(elandeletedobj)

                # Handle the case where we have deleted VnodGlobal Services from our side - if there is
                # an attached Eline/Etree/Elan we set that to deleted
                vnodbloaldeletedobjs = VnodGlobalService.deleted_objects.all()
                for vnodbloaldeletedobj in vnodbloaldeletedobjs:
                    # Check for dependent eline service
                    if vnodbloaldeletedobj.metronetworkpointtopoint is not None:
                        elineobj = vnodbloaldeletedobj.metronetworkpointtopoint
                        elineobj.deleted = True
                        objs.append(elineobj)
                    # Check for dependent elan service
                    if vnodbloaldeletedobj.metronetworkmultipoint is not None:
                        elanobj = vnodbloaldeletedobj.metronetworkmultipoint
                        elanobj.deleted = True
                        objs.append(elanobj)
                    # Check for dependent etree service
                    if vnodbloaldeletedobj.metronetworkroottomultipoint is not None:
                        etreeobj = vnodbloaldeletedobj.metronetworkroottomultipoint
                        etreeobj.deleted = True
                        objs.append(etreeobj)

                    objs.append(vnodbloaldeletedobj)

        # In add cases return the objects we are interested in
        return objs

    def sync_record(self, o):

        # First we call and see if there is an invoker for this object - the idea of the invoker
        # is to wrap the save with a pre/post paradigm to handle special cases
        # It will only exist for a subset of ojbects
        invoker = InvokerFactory.getinvoker(o)

        # Call Pre-save on the inovker (if it exists)
        if invoker is not None:
            invoker.presave(o)

        # Simply save the record to the DB - both updates and adds are handled the same way
        o.save()

        # Call Post-save on the inovker (if it exists)
        if invoker is not None:
            invoker.postsave(o)

    def delete_record(self, o):
        # Overriden to customize our behaviour - the core sync step for will remove the record directly
        # We just log and return
        logger.debug("deleting Object %s" % str(o), extra=o.tologdict())

    def get_metronetwork_system(self):
        # We only expect to have one of these objects in the system in the curent design
        # So get the first element from the query
        metronetworksystem = MetroNetworkSystem.objects.all()
        if not metronetworksystem:
            return None

        return metronetworksystem[0]
