/*
 * Copyright 2018-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.provider.hostprobing.impl;

import org.onlab.packet.ARP;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IPv6;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip6Address;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onlab.packet.ndp.NeighborSolicitation;
import org.onosproject.mastership.MastershipService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Host;
import org.onosproject.net.HostLocation;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.host.HostProbe;
import org.onosproject.net.host.HostProbingEvent;
import org.onosproject.net.host.HostProbingProvider;
import org.onosproject.net.host.HostProbingProviderRegistry;
import org.onosproject.net.host.HostProbingProviderService;
import org.onosproject.net.host.HostProvider;
import org.onosproject.net.host.HostProviderRegistry;
import org.onosproject.net.host.HostProviderService;
import org.onosproject.net.host.ProbeMode;
import org.onosproject.net.packet.DefaultOutboundPacket;
import org.onosproject.net.packet.OutboundPacket;
import org.onosproject.net.packet.PacketProcessor;
import org.onosproject.net.packet.PacketService;
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.provider.ProviderId;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.slf4j.Logger;

import java.nio.ByteBuffer;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import static java.util.concurrent.Executors.newScheduledThreadPool;
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
import static org.onlab.util.Tools.groupedThreads;
import static org.slf4j.LoggerFactory.getLogger;

/**
 * Provider which sends host location probes to discover or verify a host at specific location.
 */
@Component(immediate = true, service = { HostProvider.class, HostProbingProvider.class })
public class DefaultHostProbingProvider extends AbstractProvider implements HostProvider, HostProbingProvider {
    private final Logger log = getLogger(getClass());

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    private HostProviderRegistry providerRegistry;

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    private HostProbingProviderRegistry hostProbingProviderRegistry;

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    private PacketService packetService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    private MastershipService mastershipService;

    private HostProviderService providerService;
    private HostProbingProviderService hostProbingProviderService;
    private ExecutorService packetHandler;
    private ExecutorService probeEventHandler;
    private ScheduledExecutorService hostProber;

    private final PacketProcessor packetProcessor = context ->
        packetHandler.execute(() -> {
            Ethernet eth = context.inPacket().parsed();
            if (eth == null) {
                return;
            }
            MacAddress srcMac = eth.getSourceMAC();
            MacAddress destMac = eth.getDestinationMAC();
            VlanId vlan = VlanId.vlanId(eth.getVlanID());
            ConnectPoint heardOn = context.inPacket().receivedFrom();

            // Receives a location probe. Invalid entry from the cache
            if (destMac.isOnos() && !MacAddress.NONE.equals(destMac)) {
                log.debug("Receives probe for {}/{} on {}", srcMac, vlan, heardOn);
                hostProbingProviderService.removeProbingHost(destMac);
            }
        });

    // TODO Make this configurable
    private static final int PROBE_INIT_DELAY_MS = 1000;
    private static final int DEFAULT_RETRY = 5;

    /**
     * Creates an OpenFlow host provider.
     */
    public DefaultHostProbingProvider() {
        super(new ProviderId("hostprobing", "org.onosproject.provider.hostprobing"));
    }

    @Activate
    public void activate(ComponentContext context) {
        providerService = providerRegistry.register(this);
        hostProbingProviderService = hostProbingProviderRegistry.register(this);

        packetHandler = newSingleThreadScheduledExecutor(groupedThreads("onos/host-loc-provider",
                "packet-handler", log));
        probeEventHandler = newSingleThreadScheduledExecutor(groupedThreads("onos/host-loc-provider",
                "probe-handler", log));
        hostProber = newScheduledThreadPool(32, groupedThreads("onos/host-loc-probe", "%d", log));

        packetService.addProcessor(packetProcessor, PacketProcessor.advisor(1));
    }

    @Deactivate
    public void deactivate() {
        providerRegistry.unregister(this);
        hostProbingProviderRegistry.unregister(this);
        providerService = null;

        packetService.removeProcessor(packetProcessor);

        packetHandler.shutdown();
        probeEventHandler.shutdown();
        hostProber.shutdown();
    }

    @Override
    public void triggerProbe(Host host) {
        // Not doing anything at this moment...
    }

    @Override
    public void processEvent(HostProbingEvent event) {
        probeEventHandler.execute(() -> {
            log.debug("Receiving HostProbingEvent {}", event);
            HostProbe hostProbe = event.subject();

            switch (event.type()) {
                case PROBE_REQUESTED:
                    // Do nothing
                    break;
                case PROBE_TIMEOUT:
                    // Retry probe until PROBE_FAIL
                    // TODO Only retry DISCOVER probes
                    probeHostInternal(hostProbe, hostProbe.connectPoint(),
                            hostProbe.mode(), hostProbe.probeMac(), hostProbe.retry());
                    break;
                case PROBE_FAIL:
                    // Remove this location if this is a verify probe.
                    if (hostProbe.mode() == ProbeMode.VERIFY) {
                        providerService.removeLocationFromHost(hostProbe.id(),
                                (HostLocation) hostProbe.connectPoint());
                    }
                    break;
                case PROBE_COMPLETED:
                    // Add this location if this is a discover probe.
                    if (hostProbe.mode() == ProbeMode.DISCOVER) {
                        HostLocation newLocation = new HostLocation(hostProbe.connectPoint(),
                                System.currentTimeMillis());
                        providerService.addLocationToHost(hostProbe.id(), newLocation);
                    }
                    break;
                default:
                    log.warn("Unknown HostProbingEvent type: {}", event.type());
            }
        });
    }

    @Override
    public void probeHost(Host host, ConnectPoint connectPoint, ProbeMode probeMode) {
        probeHostInternal(host, connectPoint, probeMode, null, DEFAULT_RETRY);
    }

    // probeMac can be null if this is the very first probe and the mac is to-be-generated.
    private void probeHostInternal(Host host, ConnectPoint connectPoint, ProbeMode probeMode,
                                   MacAddress probeMac, int retry) {
        if (!mastershipService.isLocalMaster(connectPoint.deviceId())) {
            log.debug("Current node is not master of {}, abort probing {}", connectPoint.deviceId(), host);
            return;
        }

        log.debug("probeHostInternal host={}, cp={}, mode={}, probeMac={}, retry={}", host, connectPoint,
                probeMode, probeMac, retry);
        Optional<IpAddress> ipOptional = host.ipAddresses().stream().findFirst();

        if (ipOptional.isPresent()) {
            probeMac = hostProbingProviderService.addProbingHost(host, connectPoint, probeMode, probeMac, retry);

            IpAddress ip = ipOptional.get();
            log.debug("Constructing {} probe for host {} with {}", probeMode, host.id(), ip);
            Ethernet probe;
            if (ip.isIp4()) {
                probe = ARP.buildArpRequest(probeMac.toBytes(), Ip4Address.ZERO.toOctets(),
                        host.id().mac().toBytes(), ip.toOctets(),
                        host.id().mac().toBytes(), host.id().vlanId().toShort());
            } else {
                probe = NeighborSolicitation.buildNdpSolicit(
                        ip.getIp6Address(),
                        Ip6Address.valueOf(IPv6.getLinkLocalAddress(probeMac.toBytes())),
                        ip.getIp6Address(),
                        probeMac,
                        host.id().mac(),
                        host.id().vlanId());
            }

            // NOTE: delay the probe a little bit to wait for the store synchronization is done
            hostProber.schedule(() ->
                    sendLocationProbe(probe, connectPoint), PROBE_INIT_DELAY_MS, TimeUnit.MILLISECONDS);
        } else {
            log.debug("Host {} has no IP address yet. Skip probing.", host);
        }
    }

    /**
     * Send the probe packet on given port.
     *
     * @param probe the probe packet
     * @param connectPoint the port we want to probe
     */
    private void sendLocationProbe(Ethernet probe, ConnectPoint connectPoint) {
        log.debug("Sending probe for host {} on location {} with probeMac {}",
                probe.getDestinationMAC(), connectPoint, probe.getSourceMAC());
        TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();
        OutboundPacket outboundPacket = new DefaultOutboundPacket(connectPoint.deviceId(),
                treatment, ByteBuffer.wrap(probe.serialize()));
        packetService.emit(outboundPacket);
    }
}