/*
 * 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.pipelines.fabric.impl.behaviour.pipeliner;

import com.google.common.collect.Lists;
import org.onlab.packet.MplsLabel;
import org.onlab.packet.VlanId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
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.flow.criteria.Criterion;
import org.onosproject.net.flow.criteria.PiCriterion;
import org.onosproject.net.flow.criteria.VlanIdCriterion;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction;
import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
import org.onosproject.net.flowobjective.DefaultNextTreatment;
import org.onosproject.net.flowobjective.NextObjective;
import org.onosproject.net.flowobjective.NextTreatment;
import org.onosproject.net.flowobjective.Objective;
import org.onosproject.net.flowobjective.ObjectiveError;
import org.onosproject.net.group.DefaultGroupBucket;
import org.onosproject.net.group.DefaultGroupDescription;
import org.onosproject.net.group.DefaultGroupKey;
import org.onosproject.net.group.GroupBucket;
import org.onosproject.net.group.GroupBuckets;
import org.onosproject.net.group.GroupDescription;
import org.onosproject.net.group.GroupKey;
import org.onosproject.net.pi.model.PiTableId;
import org.onosproject.net.pi.runtime.PiAction;
import org.onosproject.net.pi.runtime.PiActionParam;
import org.onosproject.net.pi.runtime.PiActionProfileGroupId;
import org.onosproject.net.pi.runtime.PiGroupKey;
import org.onosproject.pipelines.fabric.impl.behaviour.FabricCapabilities;
import org.onosproject.pipelines.fabric.FabricConstants;
import org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils;

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

import static java.lang.String.format;
import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.MPLS_LABEL;
import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_ID;
import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_POP;
import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.criterion;
import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.l2Instruction;
import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.l2Instructions;
import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.outputPort;

/**
 * ObjectiveTranslator implementation for NextObjective.
 */
class NextObjectiveTranslator
        extends AbstractObjectiveTranslator<NextObjective> {

    private static final String XCONNECT = "xconnect";

    NextObjectiveTranslator(DeviceId deviceId, FabricCapabilities capabilities) {
        super(deviceId, capabilities);
    }

    @Override
    public ObjectiveTranslation doTranslate(NextObjective obj)
            throws FabricPipelinerException {

        final ObjectiveTranslation.Builder resultBuilder =
                ObjectiveTranslation.builder();

        switch (obj.type()) {
            case SIMPLE:
                simpleNext(obj, resultBuilder, false);
                break;
            case HASHED:
                hashedNext(obj, resultBuilder);
                break;
            case BROADCAST:
                if (isXconnect(obj)) {
                    xconnectNext(obj, resultBuilder);
                } else {
                    multicastNext(obj, resultBuilder);
                }
                break;
            default:
                log.warn("Unsupported NextObjective type '{}'", obj);
                return ObjectiveTranslation.ofError(ObjectiveError.UNSUPPORTED);
        }

        if (!isGroupModifyOp(obj)) {
            // Generate next MPLS and VLAN rules.
            nextMpls(obj, resultBuilder);
            nextVlan(obj, resultBuilder);
        }

        return resultBuilder.build();
    }

    private void nextMpls(NextObjective obj,
                          ObjectiveTranslation.Builder resultBuilder)
            throws FabricPipelinerException {
        // Next objective can contain only one mpls push and one mpls label
        // instruction. Pipeliner does not support other configurations.

        final List<List<ModMplsLabelInstruction>> mplsInstructions = defaultNextTreatments(
                obj.nextTreatments(), false).stream()
                .map(defaultNextTreatment -> l2Instructions(defaultNextTreatment.treatment(), MPLS_LABEL)
                        .stream().map(v -> (ModMplsLabelInstruction) v)
                        .collect(Collectors.toList()))
                .filter(l -> !l.isEmpty())
                .collect(Collectors.toList());

        if (mplsInstructions.isEmpty()) {
            // No need to apply next mpls table
            return;
        }

        // We expect one mpls label for each treatment and the label has to be the same
        final Set<MplsLabel> mplsLabels = mplsInstructions.stream()
                .flatMap(Collection::stream)
                .map(ModMplsLabelInstruction::label)
                .collect(Collectors.toSet());
        if (obj.nextTreatments().size() != mplsInstructions.size() ||
                mplsLabels.size() != 1) {
            throw new FabricPipelinerException(
                    "Inconsistent MPLS_LABEL instructions, cannot process " +
                            "next_mpls rule. It is required that all " +
                            "treatments have the same MPLS_LABEL instructions.");
        }
        final TrafficSelector selector = nextIdSelector(obj.id());
        final TrafficTreatment treatment = DefaultTrafficTreatment.builder()
                .setMpls(mplsLabels.iterator().next())
                .build();

        resultBuilder.addFlowRule(flowRule(
                obj, FabricConstants.FABRIC_INGRESS_PRE_NEXT_NEXT_MPLS,
                selector, treatment));
    }

    private void nextVlan(NextObjective obj,
                          ObjectiveTranslation.Builder resultBuilder)
            throws FabricPipelinerException {
        // We expect NextObjective treatments to contain one or two VLAN instructions.
        // If two, this treatment should be mapped to an action for double-vlan push.
        // In fabric.p4, mapping next IDs to VLAN IDs is done by a direct table (next_vlan),
        // for this reason, we also make sure that all treatments in the NextObjective
        // have exactly the same VLAN instructions, as they will be mapped to a single action

        // Try to extract VLAN instructions in the treatment,
        //  later we check if we support multiple VLAN termination.
        final List<List<ModVlanIdInstruction>> vlanInstructions = defaultNextTreatments(
                obj.nextTreatments(), false).stream()
                .map(defaultNextTreatment ->
                             l2Instructions(defaultNextTreatment.treatment(), VLAN_ID)
                                     .stream().map(v -> (ModVlanIdInstruction) v)
                                     .collect(Collectors.toList()))
                .filter(l -> !l.isEmpty())
                .collect(Collectors.toList());

        final VlanIdCriterion vlanIdCriterion = obj.meta() == null ? null
                : (VlanIdCriterion) criterion(obj.meta().criteria(), Criterion.Type.VLAN_VID);

        final List<VlanId> vlanIdList;
        if (vlanInstructions.isEmpty() && vlanIdCriterion == null) {
            // No VLAN_ID to apply.
            return;
        }
        if (!vlanInstructions.isEmpty()) {
            // Give priority to what found in the instructions.
            // Expect the same VLAN ID (or two VLAN IDs in the same order) for all instructions.
            final Set<List<VlanId>> vlanIds = vlanInstructions.stream()
                    .map(l -> l.stream().map(ModVlanIdInstruction::vlanId).collect(Collectors.toList()))
                    .collect(Collectors.toSet());
            if (obj.nextTreatments().size() != vlanInstructions.size() ||
                    vlanIds.size() != 1) {
                throw new FabricPipelinerException(
                        "Inconsistent VLAN_ID instructions, cannot process " +
                                "next_vlan rule. It is required that all " +
                                "treatments have the same VLAN_ID instructions.");
            }
            vlanIdList = vlanIds.iterator().next();
        } else {
            // Use the value in meta.
            // FIXME: there should be no need to generate a next_vlan rule for
            //  the value found in meta. Meta describes the fields that were
            //  expected to be matched in previous pipeline stages, i.e.
            //  existing packet fields. But, for some reason, if we remove this
            //  rule, traffic is not forwarded at spines. We might need to look
            //  at the way default VLANs are handled in fabric.p4.
            vlanIdList = List.of(vlanIdCriterion.vlanId());
        }

        final TrafficSelector selector = nextIdSelector(obj.id());
        final TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
        vlanIdList.stream().forEach(vlanId -> treatmentBuilder.setVlanId(vlanId));
        final TrafficTreatment treatment = treatmentBuilder.build();

        resultBuilder.addFlowRule(flowRule(
                obj, FabricConstants.FABRIC_INGRESS_PRE_NEXT_NEXT_VLAN,
                selector, treatment));
    }

    private void simpleNext(NextObjective obj,
                            ObjectiveTranslation.Builder resultBuilder,
                            boolean forceSimple)
            throws FabricPipelinerException {

        if (capabilities.hasHashedTable()) {
            // Use hashed table when possible.
            hashedNext(obj, resultBuilder);
            return;
        }

        if (obj.nextTreatments().isEmpty()) {
            // Do nothing.
            return;
        } else if (!forceSimple && obj.nextTreatments().size() != 1) {
            throw new FabricPipelinerException(format(
                    "SIMPLE NextObjective should contain only 1 treatment, found %d",
                    obj.nextTreatments().size()), ObjectiveError.BADPARAMS);
        }

        final TrafficSelector selector = nextIdSelector(obj.id());

        final List<DefaultNextTreatment> treatments = defaultNextTreatments(
                obj.nextTreatments(), true);

        if (forceSimple && treatments.size() > 1) {
            log.warn("Forcing SIMPLE behavior for NextObjective with {} treatments {}",
                     treatments.size(), obj);
        }

        // If not forcing, we are essentially extracting the only available treatment.
        final TrafficTreatment treatment = defaultNextTreatments(
                obj.nextTreatments(), true).get(0).treatment();

        resultBuilder.addFlowRule(flowRule(
                obj, FabricConstants.FABRIC_INGRESS_NEXT_SIMPLE,
                selector, treatment));

        handleEgress(obj, treatment, resultBuilder, false);
    }

    private void hashedNext(NextObjective obj,
                            ObjectiveTranslation.Builder resultBuilder)
            throws FabricPipelinerException {

        if (!capabilities.hasHashedTable()) {
            simpleNext(obj, resultBuilder, true);
            return;
        }

        // Updated result builder with hashed group.
        final int groupId = selectGroup(obj, resultBuilder);

        if (isGroupModifyOp(obj) || obj.op() == Objective.Operation.VERIFY) {
            // No changes to flow rules.
            return;
        }

        final TrafficSelector selector = nextIdSelector(obj.id());
        final TrafficTreatment treatment = DefaultTrafficTreatment.builder()
                .piTableAction(PiActionProfileGroupId.of(groupId))
                .build();

        resultBuilder.addFlowRule(flowRule(
                obj, FabricConstants.FABRIC_INGRESS_NEXT_HASHED,
                selector, treatment));
    }

    private void handleEgress(NextObjective obj, TrafficTreatment treatment,
                              ObjectiveTranslation.Builder resultBuilder,
                              boolean strict)
            throws FabricPipelinerException {
        final PortNumber outPort = outputPort(treatment);
        final Instruction popVlanInst = l2Instruction(treatment, VLAN_POP);
        if (outPort != null) {
            if (strict && treatment.allInstructions().size() > 2) {
                throw new FabricPipelinerException(
                        "Treatment contains instructions other " +
                                "than OUTPUT and VLAN_POP, cannot generate " +
                                "egress rules");
            }
            // We cannot program if there are no proper metadata in the objective
            if (obj.meta() != null && obj.meta().getCriterion(Criterion.Type.VLAN_VID) != null) {
                egressVlan(outPort, obj, popVlanInst, resultBuilder);
            } else {
                log.debug("NextObjective {} is trying to program {} without {} information",
                        obj, FabricConstants.FABRIC_EGRESS_EGRESS_NEXT_EGRESS_VLAN,
                        obj.meta() == null ? "metadata" : "vlanId");
            }
        }
    }

    private void egressVlan(PortNumber outPort, NextObjective obj, Instruction popVlanInst,
                            ObjectiveTranslation.Builder resultBuilder)
            throws FabricPipelinerException {

        final VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) criterion(
                obj.meta(), Criterion.Type.VLAN_VID);

        final PiCriterion egressVlanTableMatch = PiCriterion.builder()
                .matchExact(FabricConstants.HDR_EG_PORT, outPort.toLong())
                .build();
        final TrafficSelector selector = DefaultTrafficSelector.builder()
                .matchPi(egressVlanTableMatch)
                .matchVlanId(vlanIdCriterion.vlanId())
                .build();
        final TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
        if (popVlanInst == null) {
            treatmentBuilder.pushVlan();
        } else {
            treatmentBuilder.popVlan();
        }

        resultBuilder.addFlowRule(flowRule(
                obj, FabricConstants.FABRIC_EGRESS_EGRESS_NEXT_EGRESS_VLAN,
                selector, treatmentBuilder.build()));
    }

    private TrafficSelector nextIdSelector(int nextId) {
        return nextIdSelectorBuilder(nextId).build();
    }

    private TrafficSelector.Builder nextIdSelectorBuilder(int nextId) {
        final PiCriterion nextIdCriterion = PiCriterion.builder()
                .matchExact(FabricConstants.HDR_NEXT_ID, nextId)
                .build();
        return DefaultTrafficSelector.builder()
                .matchPi(nextIdCriterion);
    }

    private void xconnectNext(NextObjective obj, ObjectiveTranslation.Builder resultBuilder)
            throws FabricPipelinerException {

        final Collection<DefaultNextTreatment> defaultNextTreatments =
                defaultNextTreatments(obj.nextTreatments(), true);

        final List<PortNumber> outPorts = defaultNextTreatments.stream()
                .map(DefaultNextTreatment::treatment)
                .map(FabricUtils::outputPort)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

        if (outPorts.size() != 2) {
            throw new FabricPipelinerException(format(
                    "Handling XCONNECT with %d treatments (ports), but expected is 2",
                    defaultNextTreatments.size()), ObjectiveError.UNSUPPORTED);
        }

        final PortNumber port1 = outPorts.get(0);
        final PortNumber port2 = outPorts.get(1);
        final TrafficSelector selector1 = nextIdSelectorBuilder(obj.id())
                .matchInPort(port1)
                .build();
        final TrafficTreatment treatment1 = DefaultTrafficTreatment.builder()
                .setOutput(port2)
                .build();
        final TrafficSelector selector2 = nextIdSelectorBuilder(obj.id())
                .matchInPort(port2)
                .build();
        final TrafficTreatment treatment2 = DefaultTrafficTreatment.builder()
                .setOutput(port1)
                .build();

        resultBuilder.addFlowRule(flowRule(
                obj, FabricConstants.FABRIC_INGRESS_NEXT_XCONNECT,
                selector1, treatment1));
        resultBuilder.addFlowRule(flowRule(
                obj, FabricConstants.FABRIC_INGRESS_NEXT_XCONNECT,
                selector2, treatment2));

    }

    private void multicastNext(NextObjective obj,
                               ObjectiveTranslation.Builder resultBuilder)
            throws FabricPipelinerException {

        // Create ALL group that will be translated to a PRE multicast entry.
        final int groupId = allGroup(obj, resultBuilder);

        if (isGroupModifyOp(obj)) {
            // No changes to flow rules.
            return;
        }

        final TrafficSelector selector = nextIdSelector(obj.id());
        final PiActionParam groupIdParam = new PiActionParam(
                FabricConstants.GROUP_ID, groupId);
        final PiAction setMcGroupAction = PiAction.builder()
                .withId(FabricConstants.FABRIC_INGRESS_NEXT_SET_MCAST_GROUP_ID)
                .withParameter(groupIdParam)
                .build();
        final TrafficTreatment treatment = DefaultTrafficTreatment.builder()
                .piTableAction(setMcGroupAction)
                .build();

        resultBuilder.addFlowRule(flowRule(
                obj, FabricConstants.FABRIC_INGRESS_NEXT_MULTICAST,
                selector, treatment));
    }

    private int selectGroup(NextObjective obj,
                            ObjectiveTranslation.Builder resultBuilder)
            throws FabricPipelinerException {

        final PiTableId hashedTableId = FabricConstants.FABRIC_INGRESS_NEXT_HASHED;
        final List<DefaultNextTreatment> defaultNextTreatments =
                defaultNextTreatments(obj.nextTreatments(), true);
        final List<TrafficTreatment> piTreatments = Lists.newArrayList();

        for (DefaultNextTreatment t : defaultNextTreatments) {
            // Map treatment to PI...
            piTreatments.add(mapTreatmentToPiIfNeeded(t.treatment(), hashedTableId));
            // ...and handle egress if necessary.
            handleEgress(obj, t.treatment(), resultBuilder, false);
        }

        final List<GroupBucket> bucketList = piTreatments.stream()
                .map(DefaultGroupBucket::createSelectGroupBucket)
                .collect(Collectors.toList());

        final int groupId = obj.id();
        final PiGroupKey groupKey = (PiGroupKey) getGroupKey(obj);

        resultBuilder.addGroup(new DefaultGroupDescription(
                deviceId,
                GroupDescription.Type.SELECT,
                new GroupBuckets(bucketList),
                groupKey,
                groupId,
                obj.appId()));

        return groupId;
    }

    private int allGroup(NextObjective obj,
                         ObjectiveTranslation.Builder resultBuilder)
            throws FabricPipelinerException {

        final Collection<DefaultNextTreatment> defaultNextTreatments =
                defaultNextTreatments(obj.nextTreatments(), true);
        // No need to map treatments to PI as translation of ALL groups to PRE
        // multicast entries is based solely on the output port.
        for (DefaultNextTreatment t : defaultNextTreatments) {
            handleEgress(obj, t.treatment(), resultBuilder, true);
        }

        // FIXME: this implementation supports only the case in which each
        // switch interface is associated with only one VLAN, otherwise we would
        // need to support replicating multiple times the same packet for the
        // same port while setting different VLAN IDs. Hence, collect in a set.
        final Set<PortNumber> outPorts = defaultNextTreatments.stream()
                .map(DefaultNextTreatment::treatment)
                .map(FabricUtils::outputPort)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());

        if (outPorts.size() != defaultNextTreatments.size()) {
            throw new FabricPipelinerException(format(
                    "Found BROADCAST NextObjective with %d treatments but " +
                            "found only %d distinct OUTPUT port numbers, cannot " +
                            "translate to ALL groups",
                    defaultNextTreatments.size(), outPorts.size()),
                                               ObjectiveError.UNSUPPORTED);
        }

        final List<GroupBucket> bucketList = outPorts.stream()
                .map(p -> DefaultTrafficTreatment.builder().setOutput(p).build())
                .map(DefaultGroupBucket::createAllGroupBucket)
                .collect(Collectors.toList());

        final int groupId = obj.id();
        // Use DefaultGroupKey instead of PiGroupKey as we don't have any
        // action profile to apply to the groups of ALL type.
        final GroupKey groupKey = getGroupKey(obj);

        resultBuilder.addGroup(
                new DefaultGroupDescription(
                        deviceId,
                        GroupDescription.Type.ALL,
                        new GroupBuckets(bucketList),
                        groupKey,
                        groupId,
                        obj.appId()));

        return groupId;
    }

    private List<DefaultNextTreatment> defaultNextTreatments(
            Collection<NextTreatment> nextTreatments, boolean strict)
            throws FabricPipelinerException {
        final List<DefaultNextTreatment> defaultNextTreatments = Lists.newArrayList();
        final List<NextTreatment> unsupportedNextTreatments = Lists.newArrayList();
        for (NextTreatment n : nextTreatments) {
            if (n.type() == NextTreatment.Type.TREATMENT) {
                defaultNextTreatments.add((DefaultNextTreatment) n);
            } else {
                unsupportedNextTreatments.add(n);
            }
        }
        if (strict && !unsupportedNextTreatments.isEmpty()) {
            throw new FabricPipelinerException(format(
                    "Unsupported NextTreatments: %s",
                    unsupportedNextTreatments));
        }
        return defaultNextTreatments;
    }

    private TrafficTreatment getFirstDefaultNextTreatmentIfAny(
            Collection<NextTreatment> nextTreatments)
            throws FabricPipelinerException {
        final Collection<DefaultNextTreatment> nexts = defaultNextTreatments(nextTreatments, false);
        return nexts.isEmpty() ? null : nexts.iterator().next().treatment();
    }

    private boolean isGroupModifyOp(NextObjective obj) {
        // If operation is ADD_TO_EXIST, REMOVE_FROM_EXIST it means we modify
        // group buckets only, no changes for flow rules.
        return obj.op() == Objective.Operation.ADD_TO_EXISTING ||
                obj.op() == Objective.Operation.REMOVE_FROM_EXISTING;
    }

    private boolean isXconnect(NextObjective obj) {
        return obj.appId().name().contains(XCONNECT);
    }

    // Builds up the group key based on the next objective type
    public GroupKey getGroupKey(NextObjective objective) {
        if (objective.type() == NextObjective.Type.HASHED || objective.type() == NextObjective.Type.SIMPLE) {
            return new PiGroupKey(FabricConstants.FABRIC_INGRESS_NEXT_HASHED,
                    FabricConstants.FABRIC_INGRESS_NEXT_HASHED_SELECTOR,
                    objective.id());
        } else if (objective.type() == NextObjective.Type.BROADCAST) {
            return new DefaultGroupKey(
                    FabricPipeliner.KRYO.serialize(objective.id()));
        }
        return null;
    }
}
