/*
 * 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.simplefabric.impl;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
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.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.EncapsulationType;
import org.onosproject.net.FilteredConnectPoint;
import org.onosproject.net.Host;
import org.onosproject.net.ResourceGroup;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.host.HostService;
import org.onosproject.net.intent.Constraint;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentService;
import org.onosproject.net.intent.Key;
import org.onosproject.net.intent.MultiPointToSinglePointIntent;
import org.onosproject.net.intent.SinglePointToMultiPointIntent;
import org.onosproject.net.intent.constraint.EncapsulationConstraint;
import org.onosproject.net.intent.constraint.PartialFailureConstraint;
import org.onosproject.net.intf.Interface;
import org.onosproject.simplefabric.api.FabricNetwork;
import org.onosproject.simplefabric.api.SimpleFabricEvent;
import org.onosproject.simplefabric.api.SimpleFabricListener;
import org.onosproject.simplefabric.api.SimpleFabricService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static org.onosproject.simplefabric.api.Constants.FORWARDING_APP_ID;
import static org.onosproject.simplefabric.api.Constants.PRI_L2NETWORK_BROADCAST;
import static org.onosproject.simplefabric.api.Constants.PRI_L2NETWORK_UNICAST;


/**
 * An implementation of L2NetworkOperationService.
 * Handles the execution order of the L2 Network operations generated by the
 * application.
 */
@Component(immediate = true, enabled = false)
public class SimpleFabricForwarding {

    public static final String BROADCAST = "BCAST";
    public static final String UNICAST = "UNI";

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

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

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    protected IntentService intentService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    protected HostService hostService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    protected SimpleFabricService simpleFabric;

    public static final ImmutableList<Constraint> L2NETWORK_CONSTRAINTS =
            ImmutableList.of(new PartialFailureConstraint());

    private Map<Key, SinglePointToMultiPointIntent> bctIntentsMap = Maps.newConcurrentMap();
    private Map<Key, MultiPointToSinglePointIntent> uniIntentsMap = Maps.newConcurrentMap();
    private Set<Key> toBePurgedIntentKeys = new HashSet<>();

    private final InternalSimpleFabricListener simpleFabricListener = new InternalSimpleFabricListener();

    @Activate
    public void activate() {
        appId = coreService.registerApplication(FORWARDING_APP_ID);
        log.info("simple fabric forwarding starting with l2net app id {}", appId.toString());

        simpleFabric.addListener(simpleFabricListener);

        refresh();
        checkIntentsPurge();

        log.info("simple fabric forwarding started");
    }

    @Deactivate
    public void deactivate() {
        log.info("simple fabric forwarding stopping");

        simpleFabric.removeListener(simpleFabricListener);

        for (Intent intent : bctIntentsMap.values()) {
            intentService.withdraw(intent);
            toBePurgedIntentKeys.add(intent.key());
        }
        for (Intent intent : uniIntentsMap.values()) {
            intentService.withdraw(intent);
            toBePurgedIntentKeys.add(intent.key());
        }
        for (Key key : toBePurgedIntentKeys) {
            Intent intentToPurge = intentService.getIntent(key);
            if (intentToPurge != null) {
                intentService.purge(intentToPurge);
            }
        }

        // do not set clear for switch compatibility
        //bctIntentsMap.clear();
        //uniIntentsMap.clear();

        log.info("simple fabric forwarding stopped");
    }

    private void refresh() {
        log.debug("simple fabric forwarding refresh");

        Map<Key, SinglePointToMultiPointIntent> newBctIntentsMap = Maps.newConcurrentMap();
        Map<Key, MultiPointToSinglePointIntent> newUniIntentsMap = Maps.newConcurrentMap();

        for (FabricNetwork fabricNetwork : simpleFabric.fabricNetworks()) {
            // scans all l2network regardless of isDirty flag
            // if fabricNetwork.isForward == false or number of interfaces() < 2, no Intents generated
            for (SinglePointToMultiPointIntent intent : buildBrcIntents(fabricNetwork)) {
                newBctIntentsMap.put(intent.key(), intent);
            }
            for (MultiPointToSinglePointIntent intent :
                    buildUniIntents(fabricNetwork, hostsFromL2Network(fabricNetwork))) {
                newUniIntentsMap.put(intent.key(), intent);
            }
            if (fabricNetwork.isDirty()) {
                fabricNetwork.setDirty(false);
            }
        }

        boolean bctUpdated = false;
        for (SinglePointToMultiPointIntent intent : bctIntentsMap.values()) {
            SinglePointToMultiPointIntent newIntent = newBctIntentsMap.get(intent.key());
            if (newIntent == null) {
                log.info("simple fabric forwarding withdraw broadcast intent: {}",
                        intent.key().toString());
                toBePurgedIntentKeys.add(intent.key());
                intentService.withdraw(intent);
                bctUpdated = true;
            }
        }
        for (SinglePointToMultiPointIntent intent : newBctIntentsMap.values()) {
            SinglePointToMultiPointIntent oldIntent = bctIntentsMap.get(intent.key());
            if (oldIntent == null ||
                    !oldIntent.filteredEgressPoints().equals(intent.filteredEgressPoints()) ||
                    !oldIntent.filteredIngressPoint().equals(intent.filteredIngressPoint()) ||
                    !oldIntent.selector().equals(intent.selector()) ||
                    !oldIntent.treatment().equals(intent.treatment()) ||
                    !oldIntent.constraints().equals(intent.constraints())) {
                log.info("simple fabric forwarding submit broadcast intent: {}",
                        intent.key().toString());
                toBePurgedIntentKeys.remove(intent.key());
                intentService.submit(intent);
                bctUpdated = true;
            }
        }

        boolean uniUpdated = false;
        for (MultiPointToSinglePointIntent intent : uniIntentsMap.values()) {
            MultiPointToSinglePointIntent newIntent = newUniIntentsMap.get(intent.key());
            if (newIntent == null) {
                log.info("simple fabric forwarding withdraw unicast intent: {}",
                        intent.key().toString());
                toBePurgedIntentKeys.add(intent.key());
                intentService.withdraw(intent);
                uniUpdated = true;
            }
        }
        for (MultiPointToSinglePointIntent intent : newUniIntentsMap.values()) {
            MultiPointToSinglePointIntent oldIntent = uniIntentsMap.get(intent.key());
            if (oldIntent == null ||
                    !oldIntent.filteredEgressPoint().equals(intent.filteredEgressPoint()) ||
                    !oldIntent.filteredIngressPoints().equals(intent.filteredIngressPoints()) ||
                    !oldIntent.selector().equals(intent.selector()) ||
                    !oldIntent.treatment().equals(intent.treatment()) ||
                    !oldIntent.constraints().equals(intent.constraints())) {
                log.info("simple fabric forwarding submit unicast intent: {}",
                        intent.key().toString());
                toBePurgedIntentKeys.remove(intent.key());
                intentService.submit(intent);
                uniUpdated = true;
            }
        }

        if (bctUpdated) {
            bctIntentsMap = newBctIntentsMap;
        }
        if (uniUpdated) {
            uniIntentsMap = newUniIntentsMap;
        }
    }

    private void checkIntentsPurge() {
        // check intents to be purge
        if (!toBePurgedIntentKeys.isEmpty()) {
            Set<Key> purgedKeys = new HashSet<>();
            for (Key key : toBePurgedIntentKeys) {
                Intent intentToPurge = intentService.getIntent(key);
                if (intentToPurge == null) {
                    log.info("simple fabric forwarding purged intent: key={}", key.toString());
                    purgedKeys.add(key);
                } else {
                    switch (intentService.getIntentState(key)) {
                    case FAILED:
                    case WITHDRAWN:
                        log.info("simple fabric forwarding try to purge intent: key={}",
                                key.toString());
                        intentService.purge(intentToPurge);
                        break;
                    case INSTALL_REQ:
                    case INSTALLED:
                    case INSTALLING:
                    case RECOMPILING:
                    case COMPILING:
                        log.warn("simple fabric forwarding withdraw intent to purge: key={}", key);
                        intentService.withdraw(intentToPurge);
                        break;
                    case WITHDRAW_REQ:
                    case WITHDRAWING:
                    case PURGE_REQ:
                    case CORRUPT:
                    default:
                        // no action
                        break;
                    }
                }
            }
            toBePurgedIntentKeys.removeAll(purgedKeys);
        }
    }

    // Generates Unicast Intents and broadcast Intents for the L2 Network.

    private Set<Intent> generateL2NetworkIntents(FabricNetwork fabricNetwork) {
        return new ImmutableSet.Builder<Intent>()
                .addAll(buildBrcIntents(fabricNetwork))
                .addAll(buildUniIntents(fabricNetwork, hostsFromL2Network(fabricNetwork)))
                .build();
    }

    // Build Boadcast Intents for a L2 Network.
    private Set<SinglePointToMultiPointIntent> buildBrcIntents(FabricNetwork fabricNetwork) {
        Set<Interface> interfaces = fabricNetwork.interfaces();
        if (interfaces.size() < 2 || !fabricNetwork.isForward() || !fabricNetwork.isBroadcast()) {
            return ImmutableSet.of();
        }
        Set<SinglePointToMultiPointIntent> brcIntents = Sets.newHashSet();
        ResourceGroup resourceGroup = ResourceGroup.of(fabricNetwork.name());

        // Generates broadcast Intents from any network interface to other
        // network interface from the L2 Network.
        interfaces
            .forEach(src -> {
            FilteredConnectPoint srcFcp = buildFilteredConnectedPoint(src);
            Set<FilteredConnectPoint> dstFcps = interfaces.stream()
                    .filter(iface -> !iface.equals(src))
                    .map(this::buildFilteredConnectedPoint)
                    .collect(Collectors.toSet());
            Key key = buildKey(fabricNetwork.name(), "BCAST",
                    srcFcp.connectPoint(), MacAddress.BROADCAST);
            TrafficSelector selector = DefaultTrafficSelector.builder()
                    .matchEthDst(MacAddress.BROADCAST)
                    .build();
            SinglePointToMultiPointIntent.Builder
                    intentBuilder = SinglePointToMultiPointIntent.builder()
                    .appId(appId)
                    .key(key)
                    .selector(selector)
                    .filteredIngressPoint(srcFcp)
                    .filteredEgressPoints(dstFcps)
                    .constraints(buildConstraints(L2NETWORK_CONSTRAINTS,
                            fabricNetwork.encapsulation()))
                    .priority(PRI_L2NETWORK_BROADCAST)
                    .resourceGroup(resourceGroup);
            brcIntents.add(intentBuilder.build());
        });
        return brcIntents;
    }

    // Builds unicast Intents for a L2 Network.
    private Set<MultiPointToSinglePointIntent> buildUniIntents(FabricNetwork fabricNetwork,
                                                               Set<Host> hosts) {
        Set<Interface> interfaces = fabricNetwork.interfaces();
        if (!fabricNetwork.isForward() || interfaces.size() < 2) {
            return ImmutableSet.of();
        }
        Set<MultiPointToSinglePointIntent> uniIntents = Sets.newHashSet();
        ResourceGroup resourceGroup = ResourceGroup.of(fabricNetwork.name());
        hosts.forEach(host -> {
            FilteredConnectPoint hostFcp = buildFilteredConnectedPoint(host);
            Set<FilteredConnectPoint> srcFcps = interfaces.stream()
                    .map(this::buildFilteredConnectedPoint)
                    .filter(fcp -> !fcp.equals(hostFcp))
                    .collect(Collectors.toSet());
            Key key = buildKey(fabricNetwork.name(), "UNI", hostFcp.connectPoint(), host.mac());
            TrafficSelector selector = DefaultTrafficSelector.builder()
                    .matchEthDst(host.mac()).build();
            MultiPointToSinglePointIntent.Builder
                    intentBuilder = MultiPointToSinglePointIntent.builder()
                    .appId(appId)
                    .key(key)
                    .selector(selector)
                    .filteredIngressPoints(srcFcps)
                    .filteredEgressPoint(hostFcp)
                    .constraints(buildConstraints(L2NETWORK_CONSTRAINTS,
                            fabricNetwork.encapsulation()))
                    .priority(PRI_L2NETWORK_UNICAST)
                    .resourceGroup(resourceGroup);
            uniIntents.add(intentBuilder.build());
        });

        return uniIntents;
    }

    // Intent generate utilities

    private Set<Host> hostsFromL2Network(FabricNetwork fabricNetwork) {
        Set<Interface> interfaces = fabricNetwork.interfaces();
        return interfaces.stream()
                .map(this::hostsFromInterface)
                .flatMap(Collection::stream)
                .collect(Collectors.toSet());
    }

    private Set<Host> hostsFromInterface(Interface iface) {
        return hostService.getConnectedHosts(iface.connectPoint())
                .stream()
                .filter(host -> host.vlan().equals(iface.vlan()))
                .collect(Collectors.toSet());
    }

    private Key buildKey(String l2NetworkName, String type,
                         ConnectPoint cPoint, MacAddress dstMac) {
        return Key.of(l2NetworkName + "-" + type + "-" +
                cPoint.toString() + "-" + dstMac, appId);
    }

    private List<Constraint> buildConstraints(List<Constraint> constraints,
                                              EncapsulationType encapsulation) {
        if (!encapsulation.equals(EncapsulationType.NONE)) {
            List<Constraint> newConstraints = new ArrayList<>(constraints);
            constraints.stream()
                .filter(c -> c instanceof EncapsulationConstraint)
                .forEach(newConstraints::remove);
            newConstraints.add(new EncapsulationConstraint(encapsulation));
            return ImmutableList.copyOf(newConstraints);
        }
        return constraints;
    }

    private FilteredConnectPoint buildFilteredConnectedPoint(Interface iface) {
        Objects.requireNonNull(iface);
        TrafficSelector.Builder trafficSelector = DefaultTrafficSelector.builder();

        if (iface.vlan() != null && !iface.vlan().equals(VlanId.NONE)) {
            trafficSelector.matchVlanId(iface.vlan());
        }
        return new FilteredConnectPoint(iface.connectPoint(), trafficSelector.build());
    }

    protected FilteredConnectPoint buildFilteredConnectedPoint(Host host) {
        Objects.requireNonNull(host);
        TrafficSelector.Builder trafficSelector = DefaultTrafficSelector.builder();

        if (host.vlan() != null && !host.vlan().equals(VlanId.NONE)) {
            trafficSelector.matchVlanId(host.vlan());
        }
        return new FilteredConnectPoint(host.location(), trafficSelector.build());
    }

    // Dump command handler
    private void dump(String subject, PrintStream out) {
        if ("intents".equals(subject)) {
            out.println("Forwarding Broadcast Intents:\n");
            for (SinglePointToMultiPointIntent intent: bctIntentsMap.values()) {
                out.println("    " + intent.key().toString()
                          + ": " + intent.selector().criteria()
                          + ", [" + intent.filteredIngressPoint().connectPoint()
                          + "] -> " + intent.filteredEgressPoints().stream()
                                      .map(FilteredConnectPoint::connectPoint)
                                        .collect(Collectors.toSet()));
            }
            out.println("");
            out.println("Forwarding Unicast Intents:\n");
            for (MultiPointToSinglePointIntent intent: uniIntentsMap.values()) {
                out.println("    " + intent.key().toString()
                          + ": " + intent.selector().criteria()
                          + ", [" + intent.filteredIngressPoints().stream()
                                    .map(FilteredConnectPoint::connectPoint)
                                    .collect(Collectors.toSet())
                          + "] -> " + intent.filteredEgressPoint().connectPoint());
            }
            out.println("");
            out.println("Forwarding Intents to Be Purged:\n");
            for (Key key: toBePurgedIntentKeys) {
                out.println("    " + key.toString());
            }
            out.println("");
        }
    }

    // Listener
    private class InternalSimpleFabricListener implements SimpleFabricListener {
        @Override
        public void event(SimpleFabricEvent event) {
            switch (event.type()) {
            case SIMPLE_FABRIC_UPDATED:
                refresh();
                checkIntentsPurge();
                break;
            case SIMPLE_FABRIC_IDLE:
                refresh();
                checkIntentsPurge();
                break;
            case SIMPLE_FABRIC_DUMP:
                dump(event.subject(), event.out());
                break;
            default:
                // NOTE: nothing to do on SIMPLE_FABRIC_FLUSH
                break;
            }
        }
    }

}
