/*
 * 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.size() == 0) {
                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);
        }
    }
}
