/*
 * Copyright 2017-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.vpls.intent;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.core.ApplicationId;
import org.onosproject.incubator.net.intf.Interface;
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.intent.ConnectivityIntent;
import org.onosproject.net.intent.Constraint;
import org.onosproject.net.intent.Intent;
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.vpls.api.VplsData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static java.util.Objects.*;
import static org.onosproject.net.EncapsulationType.*;

/**
 * Intent utilities for VPLS.
 */
public final class VplsIntentUtility {
    private static final String SP2MP =
            "Building sp2mp intent from {}";
    private static final String MP2SP =
            "Building mp2sp intent to {}";

    private static final Logger log = LoggerFactory.getLogger(
            VplsIntentUtility.class);

    private static final int PRIORITY_OFFSET = 1000;
    private static final int PRIORITY_UNI = 200;
    private static final int PRIORITY_BRC = 100;

    public static final String PREFIX_BROADCAST = "brc";
    public static final String PREFIX_UNICAST = "uni";
    private static final String SEPARATOR = "-";

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

    private VplsIntentUtility() {
        // Utility classes should not have a public or default constructor.
    }

    /**
     * Builds broadcast Intents for a VPLS.
     *
     * @param vplsData the VPLS
     * @param appId the application id for Intents
     * @return broadcast Intents for the VPLS
     */
    public static Set<Intent> buildBrcIntents(VplsData vplsData, ApplicationId appId) {
        Set<Interface> interfaces = vplsData.interfaces();

        // At least two or more network interfaces to build broadcast Intents
        if (interfaces.size() < 2) {
            return ImmutableSet.of();
        }
        Set<Intent> brcIntents = Sets.newHashSet();
        ResourceGroup resourceGroup = ResourceGroup.of(vplsData.name());

        // Generates broadcast Intents from any network interface to other
        // network interface from the VPLS.
        interfaces.forEach(src -> {
            FilteredConnectPoint srcFcp = VplsIntentUtility.buildFilteredConnectedPoint(src);
            Set<FilteredConnectPoint> dstFcps =
                    interfaces.stream()
                            .filter(iface -> !iface.equals(src))
                            .map(VplsIntentUtility::buildFilteredConnectedPoint)
                            .collect(Collectors.toSet());
            Key key = VplsIntentUtility.buildKey(PREFIX_BROADCAST,
                                                 srcFcp.connectPoint(),
                                                 vplsData.name(),
                                                 MacAddress.BROADCAST,
                                                 appId);
            Intent brcIntent = buildBrcIntent(key,
                                              appId,
                                              srcFcp,
                                              dstFcps,
                                              vplsData.encapsulationType(),
                                              resourceGroup);

            brcIntents.add(brcIntent);
        });
        return brcIntents;
    }

    /**
     * Builds a broadcast intent.
     *
     * @param key key to identify the intent
     * @param appId application ID for this Intent
     * @param src the source connect point
     * @param dsts the destination connect points
     * @param encap the encapsulation type
     * @param resourceGroup resource group for this Intent
     * @return the generated single-point to multi-point intent
     */
    protected static SinglePointToMultiPointIntent buildBrcIntent(Key key,
                                                                  ApplicationId appId,
                                                                  FilteredConnectPoint src,
                                                                  Set<FilteredConnectPoint> dsts,
                                                                  EncapsulationType encap,
                                                                  ResourceGroup resourceGroup) {
        log.debug("Building broadcast intent {} for source {}", SP2MP, src);

        SinglePointToMultiPointIntent.Builder intentBuilder;

        TrafficSelector selector = DefaultTrafficSelector.builder()
                .matchEthDst(MacAddress.BROADCAST)
                .build();

        intentBuilder = SinglePointToMultiPointIntent.builder()
                .appId(appId)
                .key(key)
                .selector(selector)
                .filteredIngressPoint(src)
                .filteredEgressPoints(dsts)
                .constraints(PARTIAL_FAILURE_CONSTRAINT)
                .priority(PRIORITY_OFFSET + PRIORITY_BRC)
                .resourceGroup(resourceGroup);

        setEncap(intentBuilder, PARTIAL_FAILURE_CONSTRAINT, encap);

        return intentBuilder.build();
    }

    /**
     * Builds unicast Intents for a VPLS.
     *
     * @param vplsData the VPLS
     * @param hosts the hosts of the VPLS
     * @param appId application ID for Intents
     * @return unicast Intents for the VPLS
     */
    public static Set<Intent> buildUniIntents(VplsData vplsData, Set<Host> hosts, ApplicationId appId) {
        Set<Interface> interfaces = vplsData.interfaces();
        if (interfaces.size() < 2) {
            return ImmutableSet.of();
        }
        Set<Intent> uniIntents = Sets.newHashSet();
        ResourceGroup resourceGroup = ResourceGroup.of(vplsData.name());
        hosts.forEach(host -> {
            FilteredConnectPoint hostFcp = buildFilteredConnectedPoint(host);
            Set<FilteredConnectPoint> srcFcps =
                    interfaces.stream()
                            .map(VplsIntentUtility::buildFilteredConnectedPoint)
                            .filter(fcp -> !fcp.equals(hostFcp))
                            .collect(Collectors.toSet());
            Key key = buildKey(PREFIX_UNICAST,
                               hostFcp.connectPoint(),
                               vplsData.name(),
                               host.mac(),
                               appId);
            Intent uniIntent = buildUniIntent(key,
                                              appId,
                                              srcFcps,
                                              hostFcp,
                                              host,
                                              vplsData.encapsulationType(),
                                              resourceGroup);
            uniIntents.add(uniIntent);
        });

        return uniIntents;
    }

    /**
     * Builds a unicast intent.
     *
     * @param key key to identify the intent
     * @param appId application ID for this Intent
     * @param srcs the source Connect Points
     * @param dst the destination Connect Point
     * @param host destination Host
     * @param encap the encapsulation type
     * @param resourceGroup resource group for this Intent
     * @return the generated multi-point to single-point intent
     */
    protected static MultiPointToSinglePointIntent buildUniIntent(Key key,
                                                                  ApplicationId appId,
                                                                  Set<FilteredConnectPoint> srcs,
                                                                  FilteredConnectPoint dst,
                                                                  Host host,
                                                                  EncapsulationType encap,
                                                                  ResourceGroup resourceGroup) {
        log.debug("Building unicast intent {} for destination {}", MP2SP, dst);

        MultiPointToSinglePointIntent.Builder intentBuilder;

        TrafficSelector selector = DefaultTrafficSelector.builder()
                .matchEthDst(host.mac())
                .build();

        intentBuilder = MultiPointToSinglePointIntent.builder()
                .appId(appId)
                .key(key)
                .selector(selector)
                .filteredIngressPoints(srcs)
                .filteredEgressPoint(dst)
                .constraints(PARTIAL_FAILURE_CONSTRAINT)
                .priority(PRIORITY_OFFSET + PRIORITY_UNI)
                .resourceGroup(resourceGroup);

        setEncap(intentBuilder, PARTIAL_FAILURE_CONSTRAINT, encap);

        return intentBuilder.build();
    }

    /**
     * Builds an intent key either for single-point to multi-point or
     * multi-point to single-point intents, based on a prefix that defines
     * the type of intent, the single connect point representing the single
     * source or destination for that intent, the name of the VPLS the intent
     * belongs to, and the destination host MAC address the intent reaches.
     *
     * @param prefix the key prefix
     * @param cPoint the connect point identifying the source/destination
     * @param vplsName the name of the VPLS
     * @param hostMac the source/destination MAC address
     * @param appId application ID for the key
     * @return the key to identify the intent
     */
    protected static Key buildKey(String prefix,
                                  ConnectPoint cPoint,
                                  String vplsName,
                                  MacAddress hostMac,
                                  ApplicationId appId) {
        String keyString = vplsName +
                SEPARATOR +
                prefix +
                SEPARATOR +
                cPoint.deviceId() +
                SEPARATOR +
                cPoint.port() +
                SEPARATOR +
                hostMac;

        return Key.of(keyString, appId);
    }


    /**
     * Sets one or more encapsulation constraints on the intent builder given.
     *
     * @param builder the intent builder
     * @param constraints the existing intent constraints
     * @param encap the encapsulation type to be set
     */
    public static void setEncap(ConnectivityIntent.Builder builder,
                                List<Constraint> constraints,
                                EncapsulationType encap) {
        // Constraints might be an immutable list, so a new modifiable list
        // is created
        List<Constraint> newConstraints = new ArrayList<>(constraints);

        // Remove any encapsulation constraint if already in the list
        constraints.stream()
                .filter(c -> c instanceof EncapsulationConstraint)
                .forEach(newConstraints::remove);

        // if the new encapsulation is different from NONE, a new encapsulation
        // constraint should be added to the list
        if (!encap.equals(NONE)) {
            newConstraints.add(new EncapsulationConstraint(encap));
        }

        // Submit new constraint list as immutable list
        builder.constraints(ImmutableList.copyOf(newConstraints));
    }

    /**
     * Builds filtered connected point by a given network interface.
     *
     * @param iface the network interface
     * @return the filtered connected point of a given network interface
     */
    protected static 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());
    }

    /**
     * Builds filtered connected point by a given host.
     *
     * @param host the host
     * @return the filtered connected point of the given host
     */
    protected static FilteredConnectPoint buildFilteredConnectedPoint(Host host) {
        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());
    }
}
