/*
 * Copyright 2015-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.reactive.routing;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.FilteredConnectPoint;
import org.onosproject.net.intf.Interface;
import org.onosproject.net.intf.InterfaceService;
import org.onosproject.intentsync.IntentSynchronizationService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Host;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.host.HostService;
import org.onosproject.net.intent.Constraint;
import org.onosproject.net.intent.Key;
import org.onosproject.net.intent.MultiPointToSinglePointIntent;
import org.onosproject.net.intent.constraint.PartialFailureConstraint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * FIB component for reactive routing intents.
 */
public class ReactiveRoutingFib implements IntentRequestListener {

    private static final int PRIORITY_OFFSET = 100;
    private static final int PRIORITY_MULTIPLIER = 5;
    protected static final ImmutableList<Constraint> CONSTRAINTS
            = ImmutableList.of(new PartialFailureConstraint());

    private final Logger log = LoggerFactory.getLogger(getClass());

    private final ApplicationId appId;
    private final HostService hostService;
    private final InterfaceService interfaceService;
    private final IntentSynchronizationService intentSynchronizer;

    private final Map<IpPrefix, MultiPointToSinglePointIntent> routeIntents;

    /**
     * Class constructor.
     *
     * @param appId application ID to use to generate intents
     * @param hostService host service
     * @param interfaceService interface service
     * @param intentSynchronizer intent synchronization service
     */
    public ReactiveRoutingFib(ApplicationId appId, HostService hostService,
                              InterfaceService interfaceService,
                              IntentSynchronizationService intentSynchronizer) {
        this.appId = appId;
        this.hostService = hostService;
        this.interfaceService = interfaceService;
        this.intentSynchronizer = intentSynchronizer;

        routeIntents = Maps.newConcurrentMap();
    }

    @Override
    public void setUpConnectivityInternetToHost(IpAddress hostIpAddress) {
        checkNotNull(hostIpAddress);

        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();

        if (hostIpAddress.isIp4()) {
            selector.matchEthType(Ethernet.TYPE_IPV4);
        } else {
            selector.matchEthType(Ethernet.TYPE_IPV6);
        }

        // Match the destination IP prefix at the first hop
        IpPrefix ipPrefix = hostIpAddress.toIpPrefix();
        selector.matchIPDst(ipPrefix);

        // Rewrite the destination MAC address
        MacAddress hostMac = null;
        FilteredConnectPoint egressPoint = null;
        for (Host host : hostService.getHostsByIp(hostIpAddress)) {
            if (host.mac() != null) {
                hostMac = host.mac();
                egressPoint = new FilteredConnectPoint(host.location());
                break;
            }
        }
        if (hostMac == null) {
            hostService.startMonitoringIp(hostIpAddress);
            return;
        }

        TrafficTreatment.Builder treatment =
                DefaultTrafficTreatment.builder().setEthDst(hostMac);
        Key key = Key.of(ipPrefix.toString(), appId);
        int priority = ipPrefix.prefixLength() * PRIORITY_MULTIPLIER
                + PRIORITY_OFFSET;

        Set<ConnectPoint> interfaceConnectPoints =
                interfaceService.getInterfaces().stream()
                .map(intf -> intf.connectPoint()).collect(Collectors.toSet());

        if (interfaceConnectPoints.isEmpty()) {
            log.error("The interface connect points are empty!");
            return;
        }

        Set<FilteredConnectPoint> ingressPoints = new HashSet<>();

        for (ConnectPoint connectPoint : interfaceConnectPoints) {
            if (!connectPoint.equals(egressPoint)) {
                ingressPoints.add(new FilteredConnectPoint(connectPoint));
            }
        }

        MultiPointToSinglePointIntent intent =
                MultiPointToSinglePointIntent.builder()
                        .appId(appId)
                        .key(key)
                        .selector(selector.build())
                        .treatment(treatment.build())
                        .filteredIngressPoints(ingressPoints)
                        .filteredEgressPoint(egressPoint)
                        .priority(priority)
                        .constraints(CONSTRAINTS)
                        .build();

        log.trace("Generates ConnectivityInternetToHost intent {}", intent);
        submitReactiveIntent(ipPrefix, intent);
    }

    @Override
    public void setUpConnectivityHostToInternet(IpAddress hostIp, IpPrefix prefix,
                                                IpAddress nextHopIpAddress) {
        // Find the attachment point (egress interface) of the next hop
        Interface egressInterface =
                interfaceService.getMatchingInterface(nextHopIpAddress);
        if (egressInterface == null) {
            log.warn("No outgoing interface found for {}",
                    nextHopIpAddress);
            return;
        }

        Set<Host> hosts = hostService.getHostsByIp(nextHopIpAddress);
        if (hosts.isEmpty()) {
            log.warn("No host found for next hop IP address");
            return;
        }
        MacAddress nextHopMacAddress = null;
        for (Host host : hosts) {
            nextHopMacAddress = host.mac();
            break;
        }

        hosts = hostService.getHostsByIp(hostIp);
        if (hosts.isEmpty()) {
            log.warn("No host found for host IP address");
            return;
        }
        Host host = hosts.stream().findFirst().get();
        ConnectPoint ingressPoint = host.location();

        // Generate the intent itself
        ConnectPoint egressPort = egressInterface.connectPoint();
        log.debug("Generating intent for prefix {}, next hop mac {}",
                prefix, nextHopMacAddress);

        // Match the destination IP prefix at the first hop
        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
        if (prefix.isIp4()) {
            selector.matchEthType(Ethernet.TYPE_IPV4);
            selector.matchIPDst(prefix);
        } else {
            selector.matchEthType(Ethernet.TYPE_IPV6);
            selector.matchIPv6Dst(prefix);
        }

        // Rewrite the destination MAC address
        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
                .setEthDst(nextHopMacAddress);
        if (!egressInterface.vlan().equals(VlanId.NONE)) {
            treatment.setVlanId(egressInterface.vlan());
            // If we set VLAN ID, we have to make sure a VLAN tag exists.
            // TODO support no VLAN -> VLAN routing
            selector.matchVlanId(VlanId.ANY);
        }

        int priority = prefix.prefixLength() * PRIORITY_MULTIPLIER + PRIORITY_OFFSET;
        Key key = Key.of(prefix.toString() + "-reactive", appId);
        MultiPointToSinglePointIntent intent = MultiPointToSinglePointIntent.builder()
                .appId(appId)
                .key(key)
                .selector(selector.build())
                .treatment(treatment.build())
                .filteredIngressPoints(Collections.singleton(new FilteredConnectPoint(ingressPoint)))
                .filteredEgressPoint(new FilteredConnectPoint(egressPort))
                .priority(priority)
                .constraints(CONSTRAINTS)
                .build();

        submitReactiveIntent(prefix, intent);
    }

    @Override
    public void setUpConnectivityHostToHost(IpAddress dstIpAddress,
                                            IpAddress srcIpAddress,
                                            MacAddress srcMacAddress,
                                            ConnectPoint srcConnectPoint) {
        checkNotNull(dstIpAddress);
        checkNotNull(srcIpAddress);
        checkNotNull(srcMacAddress);
        checkNotNull(srcConnectPoint);

        IpPrefix srcIpPrefix = srcIpAddress.toIpPrefix();
        IpPrefix dstIpPrefix = dstIpAddress.toIpPrefix();
        ConnectPoint dstConnectPoint = null;
        MacAddress dstMacAddress = null;

        for (Host host : hostService.getHostsByIp(dstIpAddress)) {
            if (host.mac() != null) {
                dstMacAddress = host.mac();
                dstConnectPoint = host.location();
                break;
            }
        }
        if (dstMacAddress == null) {
            hostService.startMonitoringIp(dstIpAddress);
            return;
        }

        //
        // Handle intent from source host to destination host
        //
        MultiPointToSinglePointIntent srcToDstIntent =
                hostToHostIntentGenerator(dstIpAddress, dstConnectPoint,
                        dstMacAddress, srcConnectPoint);
        submitReactiveIntent(dstIpPrefix, srcToDstIntent);

        //
        // Handle intent from destination host to source host
        //

        // Since we proactively handle the intent from destination host to
        // source host, we should check whether there is an exiting intent
        // first.
        if (mp2pIntentExists(srcIpPrefix)) {
            updateExistingMp2pIntent(srcIpPrefix, dstConnectPoint);
            return;
        } else {
            // There is no existing intent, create a new one.
            MultiPointToSinglePointIntent dstToSrcIntent =
                    hostToHostIntentGenerator(srcIpAddress, srcConnectPoint,
                            srcMacAddress, dstConnectPoint);
            submitReactiveIntent(srcIpPrefix, dstToSrcIntent);
        }
    }

    /**
     * Generates MultiPointToSinglePointIntent for both source host and
     * destination host located in local SDN network.
     *
     * @param dstIpAddress the destination IP address
     * @param dstConnectPoint the destination host connect point
     * @param dstMacAddress the MAC address of destination host
     * @param srcConnectPoint the connect point where packet-in from
     * @return the generated MultiPointToSinglePointIntent
     */
    private MultiPointToSinglePointIntent hostToHostIntentGenerator(
            IpAddress dstIpAddress,
            ConnectPoint dstConnectPoint,
            MacAddress dstMacAddress,
            ConnectPoint srcConnectPoint) {
        checkNotNull(dstIpAddress);
        checkNotNull(dstConnectPoint);
        checkNotNull(dstMacAddress);
        checkNotNull(srcConnectPoint);

        Set<FilteredConnectPoint> ingressPoints = new HashSet<>();
        ingressPoints.add(new FilteredConnectPoint(srcConnectPoint));
        IpPrefix dstIpPrefix = dstIpAddress.toIpPrefix();

        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
        if (dstIpAddress.isIp4()) {
            selector.matchEthType(Ethernet.TYPE_IPV4);
            selector.matchIPDst(dstIpPrefix);
        } else {
            selector.matchEthType(Ethernet.TYPE_IPV6);
            selector.matchIPv6Dst(dstIpPrefix);
        }

        // Rewrite the destination MAC address
        TrafficTreatment.Builder treatment =
                DefaultTrafficTreatment.builder().setEthDst(dstMacAddress);

        Key key = Key.of(dstIpPrefix.toString(), appId);
        int priority = dstIpPrefix.prefixLength() * PRIORITY_MULTIPLIER
                + PRIORITY_OFFSET;
        MultiPointToSinglePointIntent intent =
                MultiPointToSinglePointIntent.builder()
                        .appId(appId)
                        .key(key)
                        .selector(selector.build())
                        .treatment(treatment.build())
                        .filteredIngressPoints(ingressPoints)
                        .filteredEgressPoint(new FilteredConnectPoint(dstConnectPoint))
                        .priority(priority)
                        .constraints(CONSTRAINTS)
                        .build();

        log.trace("Generates ConnectivityHostToHost = {} ", intent);
        return intent;
    }

    @Override
    public void updateExistingMp2pIntent(IpPrefix ipPrefix,
                                         ConnectPoint ingressConnectPoint) {
        checkNotNull(ipPrefix);
        checkNotNull(ingressConnectPoint);

        MultiPointToSinglePointIntent existingIntent =
                getExistingMp2pIntent(ipPrefix);
        if (existingIntent != null) {
            Set<FilteredConnectPoint> ingressPoints = existingIntent.filteredIngressPoints();
            // Add host connect point into ingressPoints of the existing intent
            if (ingressPoints.add(new FilteredConnectPoint(ingressConnectPoint))) {
                MultiPointToSinglePointIntent updatedMp2pIntent =
                        MultiPointToSinglePointIntent.builder()
                                .appId(appId)
                                .key(existingIntent.key())
                                .selector(existingIntent.selector())
                                .treatment(existingIntent.treatment())
                                .filteredIngressPoints(ingressPoints)
                                .filteredEgressPoint(existingIntent.filteredEgressPoint())
                                .priority(existingIntent.priority())
                                .constraints(CONSTRAINTS)
                                .build();

                log.trace("Update an existing MultiPointToSinglePointIntent "
                        + "to new intent = {} ", updatedMp2pIntent);
                submitReactiveIntent(ipPrefix, updatedMp2pIntent);
            }
            // If adding ingressConnectPoint to ingressPoints failed, it
            // because between the time interval from checking existing intent
            // to generating new intent, onos updated this intent due to other
            // packet-in and the new intent also includes the
            // ingressConnectPoint. This will not affect reactive routing.
        }
    }

    /**
     * Submits a reactive intent to the intent synchronizer.
     *
     * @param ipPrefix IP prefix of the intent
     * @param intent intent to submit
     */
    void submitReactiveIntent(IpPrefix ipPrefix, MultiPointToSinglePointIntent intent) {
        routeIntents.put(ipPrefix, intent);

        intentSynchronizer.submit(intent);
    }

    /**
     * Gets the existing MultiPointToSinglePointIntent from memory for a given
     * IP prefix.
     *
     * @param ipPrefix the IP prefix used to find MultiPointToSinglePointIntent
     * @return the MultiPointToSinglePointIntent if found, otherwise null
     */
    private MultiPointToSinglePointIntent getExistingMp2pIntent(IpPrefix ipPrefix) {
        checkNotNull(ipPrefix);
        return routeIntents.get(ipPrefix);
    }

    @Override
    public boolean mp2pIntentExists(IpPrefix ipPrefix) {
        checkNotNull(ipPrefix);
        return routeIntents.get(ipPrefix) != null;
    }
}
