/*
 * Copyright 2016-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.
 */

package org.onosproject.segmentrouting;

import com.google.common.collect.Sets;

import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.HostLocation;
import org.onosproject.net.PortNumber;
import org.onosproject.net.host.HostEvent;
import org.onosproject.routeservice.ResolvedRoute;
import org.onosproject.routeservice.RouteEvent;
import org.onosproject.net.DeviceId;
import org.onosproject.routeservice.RouteInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Handles RouteEvent and manages routing entries.
 */
public class RouteHandler {
    private static final Logger log = LoggerFactory.getLogger(RouteHandler.class);
    private final SegmentRoutingManager srManager;

    RouteHandler(SegmentRoutingManager srManager) {
        this.srManager = srManager;
    }

    protected void init(DeviceId deviceId) {
        Optional<DeviceId> pairDeviceId = srManager.getPairDeviceId(deviceId);

        srManager.routeService.getRouteTables().stream()
                .map(srManager.routeService::getRoutes)
                .flatMap(Collection::stream)
                .map(RouteInfo::allRoutes)
                .filter(allRoutes -> allRoutes.stream().allMatch(resolvedRoute ->
                        srManager.nextHopLocations(resolvedRoute).stream().allMatch(cp ->
                            deviceId.equals(cp.deviceId()) ||
                                    (pairDeviceId.isPresent() && pairDeviceId.get().equals(cp.deviceId()))
                        )))
                .forEach(this::processRouteAddedInternal);
    }

    void processRouteAdded(RouteEvent event) {
        processRouteAddedInternal(event.alternatives());
    }

    private void processRouteAddedInternal(Collection<ResolvedRoute> routes) {
        if (!isReady()) {
            log.info("System is not ready. Skip adding route for {}", routes);
            return;
        }

        log.info("processRouteAddedInternal. routes={}", routes);

        if (routes.size() > 2) {
            log.info("Route {} has more than two next hops. Do not process route change", routes);
            return;
        }

        Set<ConnectPoint> allLocations = Sets.newHashSet();
        Set<IpPrefix> allPrefixes = Sets.newHashSet();
        routes.forEach(route -> {
            allLocations.addAll(srManager.nextHopLocations(route));
            allPrefixes.add(route.prefix());
        });
        log.debug("RouteAdded. populateSubnet {}, {}", allLocations, allPrefixes);
        srManager.defaultRoutingHandler.populateSubnet(allLocations, allPrefixes);

        routes.forEach(route -> {
            IpPrefix prefix = route.prefix();
            MacAddress nextHopMac = route.nextHopMac();
            VlanId nextHopVlan = route.nextHopVlan();
            Set<ConnectPoint> locations = srManager.nextHopLocations(route);

            locations.forEach(location -> {
                log.debug("RouteAdded. addSubnet {}, {}", location, prefix);
                srManager.deviceConfiguration.addSubnet(location, prefix);
                log.debug("RouteAdded populateRoute {}, {}, {}, {}", location, prefix, nextHopMac, nextHopVlan);
                srManager.defaultRoutingHandler.populateRoute(location.deviceId(), prefix,
                        nextHopMac, nextHopVlan, location.port(), false);
            });
        });
    }

    void processRouteUpdated(RouteEvent event) {
        processRouteUpdatedInternal(Sets.newHashSet(event.alternatives()),
                Sets.newHashSet(event.prevAlternatives()));
    }

    void processAlternativeRoutesChanged(RouteEvent event) {
        processRouteUpdatedInternal(Sets.newHashSet(event.alternatives()),
                Sets.newHashSet(event.prevAlternatives()));
    }

    private void processRouteUpdatedInternal(Set<ResolvedRoute> routes, Set<ResolvedRoute> oldRoutes) {
        if (!isReady()) {
            log.info("System is not ready. Skip updating route for {} -> {}", oldRoutes, routes);
            return;
        }

        log.info("processRouteUpdatedInternal. routes={}, oldRoutes={}", routes, oldRoutes);

        if (routes.size() > 2) {
            log.info("Route {} has more than two next hops. Do not process route change", routes);
            return;
        }

        Set<ConnectPoint> allLocations = Sets.newHashSet();
        Set<IpPrefix> allPrefixes = Sets.newHashSet();
        routes.forEach(route -> {
            allLocations.addAll(srManager.nextHopLocations(route));
            allPrefixes.add(route.prefix());
        });

        // Just come back from an invalid next hop count
        // Revoke subnet from all locations and reset oldRoutes such that system will be reprogrammed from scratch
        if (oldRoutes.size() > 2) {
            log.info("Revoke subnet {} and reset oldRoutes");
            srManager.defaultRoutingHandler.revokeSubnet(allPrefixes);
            oldRoutes = Sets.newHashSet();
        }

        log.debug("RouteUpdated. populateSubnet {}, {}", allLocations, allPrefixes);
        srManager.defaultRoutingHandler.populateSubnet(allLocations, allPrefixes);

        Set<ResolvedRoute> toBeRemoved = Sets.difference(oldRoutes, routes).immutableCopy();
        Set<ResolvedRoute> toBeAdded = Sets.difference(routes, oldRoutes).immutableCopy();

        toBeRemoved.forEach(route -> {
            srManager.nextHopLocations(route).forEach(oldLocation -> {
                if (toBeAdded.stream().map(srManager::nextHopLocations)
                        .flatMap(Set::stream).map(ConnectPoint::deviceId)
                        .noneMatch(deviceId -> deviceId.equals(oldLocation.deviceId()))) {
                    IpPrefix prefix = route.prefix();
                    log.debug("RouteUpdated. removeSubnet {}, {}", oldLocation, prefix);
                    srManager.deviceConfiguration.removeSubnet(oldLocation, prefix);
                    // We don't remove the flow on the old location in occasion of two next hops becoming one
                    // since the populateSubnet will point the old location to the new location via spine.
                }
            });
        });

        toBeAdded.forEach(route -> {
            IpPrefix prefix = route.prefix();
            MacAddress nextHopMac = route.nextHopMac();
            VlanId nextHopVlan = route.nextHopVlan();
            Set<ConnectPoint> locations = srManager.nextHopLocations(route);

            locations.forEach(location -> {
                log.debug("RouteUpdated. addSubnet {}, {}", location, prefix);
                srManager.deviceConfiguration.addSubnet(location, prefix);
                log.debug("RouteUpdated. populateRoute {}, {}, {}, {}", location, prefix, nextHopMac, nextHopVlan);
                srManager.defaultRoutingHandler.populateRoute(location.deviceId(), prefix,
                        nextHopMac, nextHopVlan, location.port(), false);
            });
        });
    }

    void processRouteRemoved(RouteEvent event) {
        processRouteRemovedInternal(event.alternatives());
    }

    private void processRouteRemovedInternal(Collection<ResolvedRoute> routes) {
        if (!isReady()) {
            log.info("System is not ready. Skip removing route for {}", routes);
            return;
        }

        log.info("processRouteRemovedInternal. routes={}", routes);

        Set<IpPrefix> allPrefixes = Sets.newHashSet();
        routes.forEach(route -> {
            allPrefixes.add(route.prefix());
        });
        log.debug("RouteRemoved. revokeSubnet {}", allPrefixes);
        srManager.defaultRoutingHandler.revokeSubnet(allPrefixes);

        routes.forEach(route -> {
            IpPrefix prefix = route.prefix();
            MacAddress nextHopMac = route.nextHopMac();
            VlanId nextHopVlan = route.nextHopVlan();
            Set<ConnectPoint> locations = srManager.nextHopLocations(route);

            locations.forEach(location -> {
                log.debug("RouteRemoved. removeSubnet {}, {}", location, prefix);
                srManager.deviceConfiguration.removeSubnet(location, prefix);
                // We don't need to call revokeRoute again since revokeSubnet will remove the prefix
                // from all devices, including the ones that next hop attaches to.

                // Also remove redirection flows on the pair device if exists.
                Optional<DeviceId> pairDeviceId = srManager.getPairDeviceId(location.deviceId());
                Optional<PortNumber> pairLocalPort = srManager.getPairLocalPort(location.deviceId());
                if (pairDeviceId.isPresent() && pairLocalPort.isPresent()) {
                    // NOTE: Since the pairLocalPort is trunk port, use assigned vlan of original port
                    //       when the host is untagged
                    VlanId vlanId = Optional.ofNullable(srManager.getInternalVlanId(location)).orElse(nextHopVlan);

                    log.debug("RouteRemoved. revokeRoute {}, {}, {}, {}", location, prefix, nextHopMac, nextHopVlan);
                    srManager.defaultRoutingHandler.revokeRoute(pairDeviceId.get(), prefix,
                            nextHopMac, vlanId, pairLocalPort.get(), false);
                }
            });
        });
    }

    void processHostMovedEvent(HostEvent event) {
        log.info("processHostMovedEvent {}", event);
        MacAddress hostMac = event.subject().mac();
        VlanId hostVlanId = event.subject().vlan();
        // map of nextId for prev port in each device
        Map<DeviceId, Integer> nextIdMap = new HashMap<>();
        Set<HostLocation> prevLocations = event.prevSubject().locations();
        Set<HostLocation> newLocations = event.subject().locations();
        Set<ConnectPoint> connectPoints = newLocations.stream().map(l -> (ConnectPoint) l).collect(Collectors.toSet());
        List<Set<IpPrefix>> batchedSubnets =
                srManager.deviceConfiguration.getBatchedSubnets(event.subject().id());

        batchedSubnets.forEach(subnets -> {
            log.debug("HostMoved. populateSubnet {}, {}", newLocations, subnets);
            srManager.defaultRoutingHandler.populateSubnet(connectPoints, subnets);

            subnets.forEach(prefix -> {
                Set<DeviceId> newDeviceIds = newLocations.stream().map(HostLocation::deviceId)
                        .collect(Collectors.toSet());

                // Set of deviceIDs of the previous locations where the host was connected
                // Used to determine if host moved to different connect points
                // on same device or moved to a different device altogether
                Set<DeviceId> oldDeviceIds = prevLocations.stream().map(HostLocation::deviceId)
                        .collect(Collectors.toSet());

                // For each old location
                Sets.difference(prevLocations, newLocations).forEach(prevLocation -> {
                    //find next Id for each old port, add to map
                    int nextId = srManager.getNextIdForHostPort(prevLocation.deviceId(), hostMac,
                                                                 hostVlanId, prevLocation.port());
                    log.debug("HostMoved. NextId For Host {}, {}, {}, {} {}", prevLocation, prefix,
                                                                 hostMac, hostVlanId, nextId);

                    nextIdMap.put(prevLocation.deviceId(), nextId);

                    // Remove flows for unchanged IPs only when the host moves from a switch to another.
                    // Otherwise, do not remove and let the adding part update the old flow
                    if (newDeviceIds.contains(prevLocation.deviceId())) {
                        return;
                    }

                    log.debug("HostMoved. removeSubnet {}, {}", prevLocation, prefix);
                    srManager.deviceConfiguration.removeSubnet(prevLocation, prefix);

                    // Do not remove flow from a device if the route is still reachable via its pair device.
                    // populateSubnet will update the flow to point to its pair device via spine.
                    DeviceId pairDeviceId = srManager.getPairDeviceId(prevLocation.deviceId()).orElse(null);
                    if (newLocations.stream().anyMatch(n -> n.deviceId().equals(pairDeviceId))) {
                        return;
                    }

                    log.debug("HostMoved. revokeRoute {}, {}, {}, {}", prevLocation, prefix, hostMac, hostVlanId);
                    srManager.defaultRoutingHandler.revokeRoute(prevLocation.deviceId(), prefix,
                            hostMac, hostVlanId, prevLocation.port(), false);
                });

                // For each new location, add all new IPs.
                Sets.difference(newLocations, prevLocations).forEach(newLocation -> {
                    log.debug("HostMoved. addSubnet {}, {}", newLocation, prefix);
                    srManager.deviceConfiguration.addSubnet(newLocation, prefix);

                    //its a new connect point, not a move from an existing device, populateRoute
                    if (!oldDeviceIds.contains(newLocation.deviceId())) {
                       log.debug("HostMoved. populateRoute {}, {}, {}, {}", newLocation, prefix, hostMac, hostVlanId);
                       srManager.defaultRoutingHandler.populateRoute(newLocation.deviceId(), prefix,
                              hostMac, hostVlanId, newLocation.port(), false);
                    } else {
                      // update same flow to point to new nextObj
                      VlanId vlanId = Optional.ofNullable(srManager.getInternalVlanId(newLocation)).orElse(hostVlanId);
                      //use nextIdMap to send new port details to update the nextId group bucket
                      log.debug("HostMoved. update L3 Ucast Group Bucket {}, {}, {} --> {}",
                                             newLocation, hostMac, vlanId, nextIdMap.get(newLocation.deviceId()));
                      srManager.updateMacVlanTreatment(newLocation.deviceId(), hostMac, vlanId,
                              newLocation.port(), nextIdMap.get(newLocation.deviceId()));
                    }
                });
            });
        });
    }

    private boolean isReady() {
        return Objects.nonNull(srManager.deviceConfiguration) &&
                Objects.nonNull(srManager.defaultRoutingHandler);
    }
}
