"""Main module of kytos/pathfinder Kytos Network Application."""

from flask import jsonify, request
from kytos.core import KytosNApp, log, rest
from kytos.core.helpers import listen_to

# pylint: disable=import-error
from napps.kytos.pathfinder.graph import KytosGraph

# pylint: enable=import-error


class Main(KytosNApp):
    """Main class of kytos/pathfinder NApp.

    This class is the entry point for this napp.
    """

    def setup(self):
        """Create a graph to handle the nodes and edges."""
        self.graph = KytosGraph()
        self._topology = None

    def execute(self):
        """Do nothing."""

    def shutdown(self):
        """Shutdown the napp."""

    def _filter_paths(self, paths, desired, undesired):
        """Apply filters to the paths list.

        Make sure that each path in the list has all the desired links and none
        of the undesired ones.
        """
        filtered_paths = []

        if desired:
            for link_id in desired:
                try:
                    endpoint_a = self._topology.links[link_id].endpoint_a.id
                    endpoint_b = self._topology.links[link_id].endpoint_b.id
                except KeyError:
                    return []

                for path in paths:
                    head = path['hops'][:-1]
                    tail = path['hops'][1:]
                    if (((endpoint_a, endpoint_b) in zip(head, tail)) or
                            ((endpoint_b, endpoint_a) in zip(head, tail))):
                        filtered_paths.append(path)
        else:
            filtered_paths = paths

        if undesired:
            for link_id in undesired:
                try:
                    endpoint_a = self._topology.links[link_id].endpoint_a.id
                    endpoint_b = self._topology.links[link_id].endpoint_b.id
                except KeyError:
                    continue

                for path in paths:
                    head = path['hops'][:-1]
                    tail = path['hops'][1:]
                    if (((endpoint_a, endpoint_b) in zip(head, tail)) or
                            ((endpoint_b, endpoint_a) in zip(head, tail))):

                        filtered_paths.remove(path)

        return filtered_paths

    @rest('v2/', methods=['POST'])
    def shortest_path(self):
        """Calculate the best path between the source and destination."""
        data = request.get_json()

        desired = data.get('desired_links')
        undesired = data.get('undesired_links')
        parameter = data.get('parameter')

        paths = []
        for path in self.graph.shortest_paths(data['source'],
                                              data['destination'],
                                              parameter):

            paths.append({'hops': path})

        paths = self._filter_paths(paths, desired, undesired)
        return jsonify({'paths': paths})

    @rest('v3/', methods=['POST'])
    def shortest_constrained_path(self):
        """Get the set of shortest paths between the source and destination."""
        data = request.get_json()

        source = data.get('source')
        destination = data.get('destination')
        flexible = data.get('flexible', 0)
        metrics = data.get('metrics',{})

        paths = self.graph.constrained_flexible_paths(source, destination,
                                              flexible, **metrics)
                                            
        return jsonify(paths)

    @listen_to('kytos.topology.updated')
    def update_topology(self, event):
        """Update the graph when the network topology was updated.

        Clear the current graph and create a new with the most topoly updated.
        """
        if 'topology' not in event.content:
            return
        topology = event.content['topology']
        self._topology = topology
        self.graph.update_topology(topology)
        log.debug('Topology graph updated.')

"""Main module of kytos/pathfinder Kytos Network Application."""

from flask import jsonify, request
from kytos.core import KytosNApp, log, rest
from kytos.core.helpers import listen_to

# pylint: disable=import-error
from napps.kytos.pathfinder.graph import KytosGraph

# pylint: enable=import-error


class Main(KytosNApp):
    """Main class of kytos/pathfinder NApp.

    This class is the entry point for this napp.
    """

    def setup(self):
        """Create a graph to handle the nodes and edges."""
        self.graph = KytosGraph()
        self._topology = None

    def execute(self):
        """Do nothing."""

    def shutdown(self):
        """Shutdown the napp."""

    def _filter_paths(self, paths, desired, undesired):
        """Apply filters to the paths list.

        Make sure that each path in the list has all the desired links and none
        of the undesired ones.
        """
        filtered_paths = []

        if desired:
            for link_id in desired:
                try:
                    endpoint_a = self._topology.links[link_id].endpoint_a.id
                    endpoint_b = self._topology.links[link_id].endpoint_b.id
                except KeyError:
                    return []

                for path in paths:
                    head = path['hops'][:-1]
                    tail = path['hops'][1:]
                    if (((endpoint_a, endpoint_b) in zip(head, tail)) or
                            ((endpoint_b, endpoint_a) in zip(head, tail))):
                        filtered_paths.append(path)
        else:
            filtered_paths = paths

        if undesired:
            for link_id in undesired:
                try:
                    endpoint_a = self._topology.links[link_id].endpoint_a.id
                    endpoint_b = self._topology.links[link_id].endpoint_b.id
                except KeyError:
                    continue

                for path in paths:
                    head = path['hops'][:-1]
                    tail = path['hops'][1:]
                    if (((endpoint_a, endpoint_b) in zip(head, tail)) or
                            ((endpoint_b, endpoint_a) in zip(head, tail))):

                        filtered_paths.remove(path)

        return filtered_paths

    @rest('v2/', methods=['POST'])
    def shortest_path(self):
        """Calculate the best path between the source and destination."""
        data = request.get_json()

        desired = data.get('desired_links')
        undesired = data.get('undesired_links')
        parameter = data.get('parameter')

        paths = []
        for path in self.graph.shortest_paths(data['source'],
                                              data['destination'],
                                              parameter):

            paths.append({'hops': path})

        paths = self._filter_paths(paths, desired, undesired)
        return jsonify({'paths': paths})

    @rest('v3/', methods=['POST'])
    def shortest_constrained_path(self):
        """Get the set of shortest paths between the source and destination."""
        data = request.get_json()

        source = data.get('source')
        destination = data.get('destination')
        flexible = data.get('flexible', 0)
        metrics = data.get('metrics',{})

        paths = self.graph.constrained_flexible_paths(source, destination,
                                              flexible, **metrics)
                                            
        return jsonify(paths)

    @listen_to('kytos.topology.updated')
    def update_topology(self, event):
        """Update the graph when the network topology was updated.

        Clear the current graph and create a new with the most topoly updated.
        """
        if 'topology' not in event.content:
            return
        topology = event.content['topology']
        self._topology = topology
        self.graph.update_topology(topology)
        log.debug('Topology graph updated.')

Main module of kytos/pathfinder Kytos Network Application. # pylint: disable=import-error # pylint: enable=import-error Main class of kytos/pathfinder NApp.      This class is the entry point for this napp. Create a graph to handle the nodes and edges. Do nothing. Shutdown the napp. Apply filters to the paths list.          Make sure that each path in the list has all the desired links and none         of the undesired ones. Calculate the best path between the source and destination. Get the set of shortest paths between the source and destination. Update the graph when the network topology was updated.          Clear the current graph and create a new with the most topoly updated.