/*
 * Copyright 2015-present Open Networking Laboratory
 *
 * 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.mfwd.impl;

import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IPv4;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.net.ConnectPoint;
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.intent.Intent;
import org.onosproject.net.intent.IntentService;
import org.onosproject.net.intent.Key;
import org.onosproject.net.intent.SinglePointToMultiPointIntent;
import org.onosproject.net.mcast.McastRoute;
import org.onosproject.net.mcast.McastListener;
import org.onosproject.net.mcast.McastEvent;
import org.onosproject.net.mcast.MulticastRouteService;
import org.onosproject.net.packet.DefaultOutboundPacket;
import org.onosproject.net.packet.InboundPacket;
import org.onosproject.net.packet.OutboundPacket;
import org.onosproject.net.packet.PacketContext;
import org.onosproject.net.packet.PacketPriority;
import org.onosproject.net.packet.PacketProcessor;
import org.onosproject.net.packet.PacketService;
import org.slf4j.Logger;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import static com.google.common.base.Preconditions.checkNotNull;
import static org.slf4j.LoggerFactory.getLogger;

/**
 * The multicast forwarding component.  This component is responsible for
 * handling live multicast traffic by modifying multicast state and forwarding
 * packets that do not yet have state installed.
 */
@Component(immediate = true)
public class McastForwarding {

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

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected PacketService packetService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected CoreService coreService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    private IntentService intentService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected MulticastRouteService mcastRouteManager;

    protected McastIntentManager mcastIntentManager;

    private ReactivePacketProcessor processor = new ReactivePacketProcessor();
    private static ApplicationId appId;

    /**
     * Active MulticastForwardingIntent.
     */
    @Activate
    public void activate() {
        appId = coreService.registerApplication("org.onosproject.mfwd");

        mcastIntentManager = new McastIntentManager();
        mcastRouteManager.addListener(mcastIntentManager);

        packetService.addProcessor(processor, PacketProcessor.director(2));

        // Build a traffic selector for all multicast traffic
        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
        selector.matchEthType(Ethernet.TYPE_IPV4);
        selector.matchIPDst(IpPrefix.IPV4_MULTICAST_PREFIX);

        packetService.requestPackets(selector.build(), PacketPriority.REACTIVE, appId);

        log.info("Started");
    }

    /**
     * Deactivate Multicast Forwarding Intent.
     */
    @Deactivate
    public void deactivate() {
        packetService.removeProcessor(processor);
        mcastRouteManager.removeListener(mcastIntentManager);
        mcastIntentManager.withdrawAllIntents();
        processor = null;
        log.info("Stopped");
    }

    /**
     * Get the application ID, used by the McastIntentManager.
     *
     * @return the application ID
     */
    public static ApplicationId getAppId() {
        return appId;
    }

    /**
     * Forward the packet to it's multicast destinations.
     *
     * @param context The packet context
     * @param egressList The list of egress ports which the multicast packet is intended for.
     */
    private void forwardPacketToDst(PacketContext context, ArrayList<ConnectPoint> egressList) {

        // Send the pack out each of the respective egress ports
        for (ConnectPoint egress : egressList) {
            TrafficTreatment treatment = DefaultTrafficTreatment.builder()
                    .setOutput(egress.port()).build();

            OutboundPacket packet = new DefaultOutboundPacket(
                    egress.deviceId(),
                    treatment,
                    context.inPacket().unparsed());

            packetService.emit(packet);
        }
    }

    public static McastRoute createStaticRoute(String source, String group) {
        checkNotNull(source, "Must provide a source");
        checkNotNull(group, "Must provide a group");
        IpAddress ipSource = IpAddress.valueOf(source);
        IpAddress ipGroup = IpAddress.valueOf(group);
        return createStaticcreateRoute(ipSource, ipGroup);
    }

    public static McastRoute createStaticcreateRoute(IpAddress source, IpAddress group) {
        checkNotNull(source, "Must provide a source");
        checkNotNull(group, "Must provide a group");
        McastRoute.Type type = McastRoute.Type.STATIC;
        return new McastRoute(source, group, type);
    }

    /**
     * Packet processor responsible for forwarding packets along their paths.
     */

    private class ReactivePacketProcessor implements PacketProcessor {
        /**
         * Process incoming packets.
         *
         * @param context packet processing context
         */
        @Override
        public void process(PacketContext context) {
            // Stop processing if the packet has been handled, since we
            // can't do any more to it.
            if (context.isHandled()) {
                return;
            }

            InboundPacket pkt = context.inPacket();
            Ethernet ethPkt = pkt.parsed();

            if (ethPkt == null) {
                return;
            }

            if (ethPkt.getEtherType() != Ethernet.TYPE_IPV4 &&
                    ethPkt.getEtherType() != Ethernet.TYPE_IPV6) {
                return;
            }

            if (ethPkt.getEtherType() == Ethernet.TYPE_IPV6) {
                // Ignore ipv6 at the moment.
                return;
            }

            IPv4 ip = (IPv4) ethPkt.getPayload();
            IpAddress saddr = Ip4Address.valueOf(ip.getSourceAddress());
            IpAddress gaddr = IpAddress.valueOf(ip.getDestinationAddress());

            log.debug("Packet ({}, {}) has been punted\n" +
                            "\tingress port: {}\n",
                    saddr.toString(),
                    gaddr.toString(),
                    context.inPacket().receivedFrom().toString());

            // Don't allow PIM/IGMP packets to be handled here.
            byte proto = ip.getProtocol();
            if (proto == IPv4.PROTOCOL_PIM || proto == IPv4.PROTOCOL_IGMP) {
                return;
            }

            IpPrefix spfx = IpPrefix.valueOf(saddr, 32);
            IpPrefix gpfx = IpPrefix.valueOf(gaddr, 32);

            // TODO do we want to add a type for Mcast?
            McastRoute mRoute = new McastRoute(saddr, gaddr, McastRoute.Type.STATIC);

            ConnectPoint ingress = mcastRouteManager.fetchSource(mRoute);

            // An ingress port already exists. Log error.
            if (ingress != null) {
                log.error(McastForwarding.class.getSimpleName() + " received packet which already has a route.");
                return;
            } else {
                //add ingress port
                mcastRouteManager.addSource(mRoute, pkt.receivedFrom());
            }

            ArrayList<ConnectPoint> egressList = (ArrayList<ConnectPoint>) mcastRouteManager.fetchSinks(mRoute);
            //If there are no egress ports set return, otherwise forward the packets to their expected port.
            if (egressList.isEmpty()) {
                return;
            }

            // Send the pack out each of the egress devices & port
            forwardPacketToDst(context, egressList);
        }

    }

    private class McastIntentManager implements McastListener {

        private Map<McastRoute, Key> intentHashMap;

        public McastIntentManager() {
            intentHashMap = new HashMap<>();
        }

        @Override
        public void event(McastEvent event) {
            McastRoute route = event.subject().route();
            if (intentHashMap.containsKey(route)) {
                withdrawIntent(intentHashMap.get(route));
            }
            Key routeKey = setIntent(route);
            intentHashMap.put(route, routeKey);
        }

        private Key setIntent(McastRoute route) {

            ConnectPoint ingressPoint = mcastRouteManager.fetchSource(route);
            Set<ConnectPoint> egressPoints = new HashSet<>(mcastRouteManager.fetchSinks(route));

            TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
            TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();

            if (ingressPoint == null) {
                log.warn("Can't set intent without an ingress or egress connect points");
                return null;
            }

            selector.matchEthType(Ethernet.TYPE_IPV4)
                    .matchIPDst(route.group().toIpPrefix())
                    .matchIPSrc(route.source().toIpPrefix());

            SinglePointToMultiPointIntent.Builder builder = SinglePointToMultiPointIntent.builder()
                    .appId(appId)
                    .selector(selector.build())
                    .treatment(treatment)
                    .ingressPoint(ingressPoint);

            // allowing intent to be pushed without egress points means we can drop packets.
            if (!egressPoints.isEmpty()) {
                builder.egressPoints(egressPoints);
            }

            SinglePointToMultiPointIntent intent = builder.build();
            intentService.submit(intent);

            return intent.key();
        }

        public void withdrawAllIntents() {
            for (Map.Entry<McastRoute, Key> entry : intentHashMap.entrySet()) {
                withdrawIntent(entry.getValue());
            }
            intentHashMap.clear();
        }

        public void withdrawIntent(Key key) {
            if (key == null) {
                // nothing to withdraw
                return;
            }
            Intent intent = intentService.getIntent(key);
            intentService.withdraw(intent);
        }
    }
}
