/*
 * Copyright 2016-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.net.intent.impl.compiler;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Sets;
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.util.Identifier;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.domain.DomainService;
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.EthCriterion;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flowobjective.DefaultFilteringObjective;
import org.onosproject.net.flowobjective.DefaultForwardingObjective;
import org.onosproject.net.flowobjective.DefaultNextObjective;
import org.onosproject.net.flowobjective.FilteringObjective;
import org.onosproject.net.flowobjective.FlowObjectiveService;
import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.net.flowobjective.NextObjective;
import org.onosproject.net.flowobjective.Objective;
import org.onosproject.net.intent.FlowObjectiveIntent;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentCompiler;
import org.onosproject.net.intent.LinkCollectionIntent;
import org.onosproject.net.intent.constraint.EncapsulationConstraint;
import org.onosproject.net.resource.ResourceService;
import org.onosproject.net.resource.impl.LabelAllocator;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import static org.onosproject.net.domain.DomainId.LOCAL;
import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT;

/**
 * Compiler to produce flow objectives from link collections.
 */
@Component(immediate = true)
public class LinkCollectionIntentObjectiveCompiler
        extends LinkCollectionCompiler<Objective>
        implements IntentCompiler<LinkCollectionIntent> {

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected IntentConfigurableRegistrator registrator;

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

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected FlowObjectiveService flowObjectiveService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected ResourceService resourceService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected DomainService domainService;

    private ApplicationId appId;

    @Activate
    public void activate() {
        appId = coreService.registerApplication("org.onosproject.net.intent");
        registrator.registerCompiler(LinkCollectionIntent.class, this, true);
        if (labelAllocator == null) {
            labelAllocator = new LabelAllocator(resourceService);
        }
    }


    @Deactivate
    public void deactivate() {
        registrator.unregisterCompiler(LinkCollectionIntent.class, true);
    }

    @Override
    public List<Intent> compile(LinkCollectionIntent intent, List<Intent> installable) {

        SetMultimap<DeviceId, PortNumber> inputPorts = HashMultimap.create();
        SetMultimap<DeviceId, PortNumber> outputPorts = HashMultimap.create();
        Map<ConnectPoint, Identifier<?>> labels = ImmutableMap.of();

        Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);

        computePorts(intent, inputPorts, outputPorts);

        if (encapConstraint.isPresent()) {
            labels = labelAllocator.assignLabelToPorts(intent.links(),
                                                       intent.id(),
                                                       encapConstraint.get().encapType());
        }

        ImmutableList.Builder<Intent> intentList = ImmutableList.builder();
        if (this.isDomainProcessingEnabled(intent)) {
            intentList.addAll(this.getDomainIntents(intent, domainService));
        }

        List<Objective> objectives = new ArrayList<>();
        List<DeviceId> devices = new ArrayList<>();
        for (DeviceId deviceId : outputPorts.keySet()) {
            // add only objectives that are not inside of a domain
            if (LOCAL.equals(domainService.getDomain(deviceId))) {
                List<Objective> deviceObjectives =
                        createRules(intent,
                                    deviceId,
                                    inputPorts.get(deviceId),
                                    outputPorts.get(deviceId),
                                    labels);
                deviceObjectives.forEach(objective -> {
                    objectives.add(objective);
                    devices.add(deviceId);
                });
            }
        }
        // if any objectives have been created
        if (!objectives.isEmpty()) {
            intentList.add(new FlowObjectiveIntent(appId, intent.key(), devices,
                                                   objectives,
                                                   intent.resources(),
                                                   intent.resourceGroup()));
        }
        return intentList.build();
    }

    @Override
    boolean optimizeTreatments() {
        return false;
    }

    @Override
    protected List<Objective> createRules(LinkCollectionIntent intent,
                                          DeviceId deviceId,
                                          Set<PortNumber> inPorts,
                                          Set<PortNumber> outPorts,
                                          Map<ConnectPoint, Identifier<?>> labels) {

        List<Objective> objectives = new ArrayList<>(inPorts.size() * 2);

        /*
         * Looking for the encapsulation constraint
         */
        Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);

        inPorts.forEach(inport -> {

            ForwardingInstructions instructions = this.createForwardingInstruction(
                    encapConstraint,
                    intent,
                    inport,
                    outPorts,
                    deviceId,
                    labels
            );

            Set<TrafficTreatment> treatmentsWithDifferentPort =
                    Sets.newHashSet();

            TrafficTreatment.Builder treatmentBuilder =
                    DefaultTrafficTreatment.builder();

            for (Instruction inst : instructions.treatment().allInstructions()) {
                if (inst.type() == OUTPUT) {
                    treatmentBuilder.add(inst);
                    treatmentsWithDifferentPort.add(treatmentBuilder.build());
                    treatmentBuilder = DefaultTrafficTreatment.builder();
                } else {
                    treatmentBuilder.add(inst);
                }
            }

            EthCriterion ethDst = (EthCriterion) instructions.selector()
                    .getCriterion(Criterion.Type.ETH_DST);
            boolean broadcastObjective = ethDst != null &&
                    (ethDst.mac().isBroadcast() || ethDst.mac().isMulticast());

            if (treatmentsWithDifferentPort.size() < 2 && !broadcastObjective) {
                objectives.addAll(createSimpleNextObjective(instructions, intent));
            } else {
                objectives.addAll(createBroadcastObjective(instructions,
                                                           treatmentsWithDifferentPort,
                                                           intent));
            }
        });

        return objectives;
    }

    private List<Objective> createBroadcastObjective(ForwardingInstructions instructions,
                                                     Set<TrafficTreatment> treatmentsWithDifferentPort,
                                                     LinkCollectionIntent intent) {
        List<Objective> objectives = Lists.newArrayList();
        FilteringObjective filteringObjective;
        ForwardingObjective forwardingObjective;
        NextObjective nextObjective;

        Integer nextId = flowObjectiveService.allocateNextId();

        forwardingObjective = buildForwardingObjective(instructions.selector(),
                                                       nextId, intent.priority());

        DefaultNextObjective.Builder nxBuilder = DefaultNextObjective.builder();
        nxBuilder.withId(nextId)
                .withMeta(instructions.selector())
                .withType(NextObjective.Type.BROADCAST)
                .fromApp(appId)
                .withPriority(intent.priority())
                .makePermanent();

        treatmentsWithDifferentPort.forEach(nxBuilder::addTreatment);
        nextObjective = nxBuilder.add();

        filteringObjective = buildFilteringObjective(instructions.selector(), intent.priority());

        objectives.add(filteringObjective);
        objectives.add(forwardingObjective);
        objectives.add(nextObjective);

        return objectives;
    }

    private List<Objective> createSimpleNextObjective(ForwardingInstructions instructions,
                                                      LinkCollectionIntent intent) {
        List<Objective> objectives = Lists.newArrayList();
        FilteringObjective filteringObjective;
        ForwardingObjective forwardingObjective;
        NextObjective nextObjective;

        Integer nextId = flowObjectiveService.allocateNextId();

        forwardingObjective = buildForwardingObjective(instructions.selector(),
                                                       nextId, intent.priority());

        DefaultNextObjective.Builder nxBuilder = DefaultNextObjective.builder();
        nextObjective = nxBuilder.withId(nextId)
                .withMeta(instructions.selector())
                .addTreatment(instructions.treatment())
                .withType(NextObjective.Type.SIMPLE)
                .fromApp(appId)
                .makePermanent()
                .withPriority(intent.priority())
                .add();

        filteringObjective = buildFilteringObjective(instructions.selector(), intent.priority());

        objectives.add(filteringObjective);
        objectives.add(forwardingObjective);
        objectives.add(nextObjective);

        return objectives;
    }

    private ForwardingObjective buildForwardingObjective(TrafficSelector selector, Integer nextId, int priority) {
        return DefaultForwardingObjective.builder()
                .withMeta(selector)
                .withSelector(selector)
                .nextStep(nextId)
                .fromApp(appId)
                .withPriority(priority)
                .withFlag(ForwardingObjective.Flag.SPECIFIC)
                .makePermanent()
                .add();
    }

    private FilteringObjective buildFilteringObjective(TrafficSelector selector, int priority) {
        FilteringObjective.Builder builder = DefaultFilteringObjective.builder();
        builder.fromApp(appId)
                .permit()
                .makePermanent()
                .withPriority(priority);

        Criterion inPortCriterion =
                selector.getCriterion(Criterion.Type.IN_PORT);

        if (inPortCriterion != null) {
            builder.withKey(inPortCriterion);
        }

        selector.criteria().forEach(builder::addCondition);
        return builder.add();
    }

}
