/*
 * 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 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.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Link;
import org.onosproject.net.LinkKey;
import org.onosproject.net.OduSignalId;
import org.onosproject.net.OduSignalType;
import org.onosproject.net.OduSignalUtils;
import org.onosproject.net.OtuPort;
import org.onosproject.net.Path;
import org.onosproject.net.Port;
import org.onosproject.net.TributarySlot;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.flow.DefaultFlowRule;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.Criteria;
import org.onosproject.net.flow.instructions.Instructions;
import org.onosproject.net.intent.FlowRuleIntent;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentCompiler;
import org.onosproject.net.intent.IntentExtensionService;
import org.onosproject.net.intent.OpticalOduIntent;
import org.onosproject.net.intent.impl.IntentCompilationException;
import org.onosproject.net.optical.OduCltPort;
import org.onosproject.net.resource.Resource;
import org.onosproject.net.resource.ResourceService;
import org.onosproject.net.resource.ResourceAllocation;
import org.onosproject.net.resource.Resources;
import org.onosproject.net.topology.LinkWeight;
import org.onosproject.net.topology.Topology;
import org.onosproject.net.topology.TopologyService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.google.common.base.Preconditions.checkArgument;
import static org.onosproject.net.LinkKey.linkKey;
import static org.onosproject.net.optical.device.OpticalDeviceServiceView.opticalView;

/**
 * An intent compiler for {@link org.onosproject.net.intent.OpticalOduIntent}.
 */
@Component(immediate = true)
public class OpticalOduIntentCompiler implements IntentCompiler<OpticalOduIntent> {

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

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected IntentExtensionService intentManager;

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

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected TopologyService topologyService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected DeviceService deviceService;

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

    private ApplicationId appId;

    @Activate
    public void activate() {
        deviceService = opticalView(deviceService);
        appId = coreService.registerApplication("org.onosproject.net.intent");
        intentManager.registerCompiler(OpticalOduIntent.class, this);
    }

    @Deactivate
    public void deactivate() {
        intentManager.unregisterCompiler(OpticalOduIntent.class);
    }

    @Override
    public List<Intent> compile(OpticalOduIntent intent, List<Intent> installable) {
        // Check if ports are OduClt ports
        ConnectPoint src = intent.getSrc();
        ConnectPoint dst = intent.getDst();
        Port srcPort = deviceService.getPort(src.deviceId(), src.port());
        Port dstPort = deviceService.getPort(dst.deviceId(), dst.port());
        checkArgument(srcPort instanceof OduCltPort);
        checkArgument(dstPort instanceof OduCltPort);

        log.debug("Compiling optical ODU intent between {} and {}", src, dst);

        // Release of intent resources here is only a temporary solution for handling the
        // case of recompiling due to intent restoration (when intent state is FAILED).
        // TODO: try to release intent resources in IntentManager.
        resourceService.release(intent.id());

        // Check OduClt ports availability
        Resource srcPortResource = Resources.discrete(src.deviceId(), src.port()).resource();
        Resource dstPortResource = Resources.discrete(dst.deviceId(), dst.port()).resource();
        // If ports are not available, compilation fails
        if (!Stream.of(srcPortResource, dstPortResource).allMatch(resourceService::isAvailable)) {
            throw new IntentCompilationException("Ports for the intent are not available. Intent: " + intent);
        }
        List<Resource> intentResources = new ArrayList<>();
        intentResources.add(srcPortResource);
        intentResources.add(dstPortResource);

        // Calculate available light paths
        Set<Path> paths = getOpticalPaths(intent);

        if (paths.isEmpty()) {
            throw new IntentCompilationException("Unable to find suitable lightpath for intent " + intent);
        }

        // Use first path that can be successfully reserved
        for (Path path : paths) {

            // Find available Tributary Slots on both directions of path
            Map<LinkKey, Set<TributarySlot>> slotsMap = findAvailableTributarySlots(intent, path);
            if (slotsMap.isEmpty()) {
                continue;
            }
            List<Resource> tributarySlotResources = convertToResources(slotsMap);
            if (!tributarySlotResources.stream().allMatch(resourceService::isAvailable)) {
                continue;
            }

            intentResources.addAll(tributarySlotResources);

            allocateResources(intent, intentResources);

            List<FlowRule> rules = new LinkedList<>();

            // Create rules for forward and reverse path
            rules = createRules(intent, intent.getSrc(), intent.getDst(), path, slotsMap, false);
            if (intent.isBidirectional()) {
                rules.addAll(createRules(intent, intent.getDst(), intent.getSrc(), path, slotsMap, true));
            }

            return Collections.singletonList(new FlowRuleIntent(appId,
                    rules, ImmutableSet.copyOf(path.links())));
        }

        throw new IntentCompilationException("Unable to find suitable lightpath for intent " + intent);
    }

    /**
     * Find available TributarySlots across path.
     *
     * @param intent
     * @param path path in OTU topology
     * @return Map of Linkey and Set of available TributarySlots on its ports
     */
    private Map<LinkKey, Set<TributarySlot>> findAvailableTributarySlots(OpticalOduIntent intent, Path path) {
        Set<LinkKey> linkRequest = Sets.newHashSetWithExpectedSize(path.links().size());
        for (int i = 0; i < path.links().size(); i++) {
            LinkKey link = linkKey(path.links().get(i));
            linkRequest.add(link);
        }

        return findTributarySlots(intent, linkRequest);
    }

    private List<Resource> convertToResources(Map<LinkKey, Set<TributarySlot>> slotsMap) {
       // Same TributarySlots are used for both directions
        Set<Resource> resources = slotsMap.entrySet().stream()
                .flatMap(x -> x.getValue()
                        .stream()
                        .flatMap(ts-> Stream.of(
                                Resources.discrete(x.getKey().src().deviceId(), x.getKey().src().port())
                                        .resource().child(ts),
                                Resources.discrete(x.getKey().dst().deviceId(), x.getKey().dst().port())
                                        .resource().child(ts))))
                .collect(Collectors.toSet());
        return (ImmutableList.copyOf(resources));
    }

    private void allocateResources(Intent intent, List<Resource> resources) {
        // reserve all of required resources
        List<ResourceAllocation> allocations = resourceService.allocate(intent.id(), resources);
        if (allocations.isEmpty()) {
            log.info("Resource allocation for {} failed (resource request: {})", intent, resources);
            throw new IntentCompilationException("Unable to allocate resources: " + resources);
        }
    }

    private Map<LinkKey, Set<TributarySlot>> findTributarySlots(OpticalOduIntent intent, Set<LinkKey> links) {
        OduSignalType oduSignalType = OduSignalUtils.mappingCltSignalTypeToOduSignalType(intent.getSignalType());
        int requestedTsNum = oduSignalType.tributarySlots();

        Map<LinkKey, Set<TributarySlot>> slotsMap = new HashMap<>();
        for (LinkKey link : links) {
            Set<TributarySlot> common = findCommonTributarySlotsOnCps(link.src(), link.dst());
            if (common.isEmpty() || (common.size() < requestedTsNum)) {
                log.debug("Failed to find TributarySlots on link {} requestedTsNum={}", link, requestedTsNum);
                return Collections.emptyMap(); // failed to find enough available TributarySlots on a link
            }
            slotsMap.put(link, common.stream()
                                .limit(requestedTsNum)
                                .collect(Collectors.toSet()));
        }
        return slotsMap;
    }

    /**
     * Calculates optical paths in OTU topology.
     *
     * @param intent optical ODU intent
     * @return set of paths in OTU topology
     */
    private Set<Path> getOpticalPaths(OpticalOduIntent intent) {
        // Route in OTU topology
        Topology topology = topologyService.currentTopology();

        LinkWeight weight = edge -> {
            // Disregard inactive or non-optical links
            if (edge.link().state() == Link.State.INACTIVE) {
                return -1;
            }
            if (edge.link().type() != Link.Type.OPTICAL) {
                return -1;
            }
            // Find path with available TributarySlots resources
            if (!isAvailableTributarySlots(intent, edge.link())) {
                return -1;
            }
            return 1;
        };

        ConnectPoint start = intent.getSrc();
        ConnectPoint end = intent.getDst();

        return topologyService.getPaths(topology, start.deviceId(), end.deviceId(), weight);
    }

    private boolean isAvailableTributarySlots(OpticalOduIntent intent, Link link) {
        OduSignalType oduSignalType = OduSignalUtils.mappingCltSignalTypeToOduSignalType(intent.getSignalType());
        int requestedTsNum = oduSignalType.tributarySlots();

        Set<TributarySlot> common = findCommonTributarySlotsOnCps(link.src(), link.dst());
        if (common.isEmpty() || (common.size() < requestedTsNum)) {
            log.debug("Not enough available TributarySlots on link {} requestedTsNum={}", link, requestedTsNum);
            return false;
        }
        return true;
    }

    /**
     * Create rules for the forward (or the reverse) path of the intent.
     *
     * @param intent OpticalOduIntent intent
     * @param path path found for intent
     * @param slotsMap Map of LinkKey and TributarySlots resources
     * @return list of flow rules
     */
    private List<FlowRule> createRules(OpticalOduIntent intent, ConnectPoint src, ConnectPoint dst,
            Path path, Map<LinkKey, Set<TributarySlot>> slotsMap, boolean reverse) {
        // Build the ingress OTN rule
        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
        selector.matchInPort(src.port());
        OduSignalType oduCltPortOduSignalType =
                OduSignalUtils.mappingCltSignalTypeToOduSignalType(intent.getSignalType());
        selector.add(Criteria.matchOduSignalType(oduCltPortOduSignalType));

        List<FlowRule> rules = new LinkedList<>();
        ConnectPoint current = src;

        List<Link> links = ((!reverse) ? path.links() : Lists.reverse(path.links()));

        for (Link link : links) {
            Set<TributarySlot> slots = slotsMap.get(linkKey(link));
            OtuPort otuPort = (OtuPort) (deviceService.getPort(link.src().deviceId(), link.src().port()));
            OduSignalType otuPortOduSignalType =
                    OduSignalUtils.mappingOtuSignalTypeToOduSignalType(otuPort.signalType());

            TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder();
            OduSignalId oduSignalId = null;
            // use Instruction of OduSignalId only in case of ODU Multiplexing
            if (oduCltPortOduSignalType != otuPortOduSignalType) {
                oduSignalId = OduSignalUtils.buildOduSignalId(otuPortOduSignalType, slots);
                treat.add(Instructions.modL1OduSignalId(oduSignalId));
            }
            ConnectPoint next = ((!reverse) ? link.src() : link.dst());
            treat.setOutput(next.port());

            FlowRule rule = createFlowRule(intent, current.deviceId(), selector.build(), treat.build());
            rules.add(rule);

            current = ((!reverse) ? link.dst() : link.src());
            selector = DefaultTrafficSelector.builder();
            selector.matchInPort(current.port());
            selector.add(Criteria.matchOduSignalType(oduCltPortOduSignalType));
            // use Criteria of OduSignalId only in case of ODU Multiplexing
            if (oduCltPortOduSignalType != otuPortOduSignalType) {
                selector.add(Criteria.matchOduSignalId(oduSignalId));
            }
        }

        // Build the egress OTN rule
        TrafficTreatment.Builder treatLast = DefaultTrafficTreatment.builder();
        treatLast.setOutput(dst.port());

        FlowRule rule = createFlowRule(intent, dst.deviceId(), selector.build(), treatLast.build());
        rules.add(rule);

        return rules;
    }

    private FlowRule createFlowRule(OpticalOduIntent intent, DeviceId deviceId,
            TrafficSelector selector, TrafficTreatment treat) {
        return DefaultFlowRule.builder()
                .forDevice(deviceId)
                .withSelector(selector)
                .withTreatment(treat)
                .withPriority(intent.priority())
                .fromApp(appId)
                .makePermanent()
                .build();
    }

    /**
     * Finds the common TributarySlots available on the two connect points.
     *
     * @param src source connect point
     * @param dst dest connect point
     * @return set of common TributarySlots on both connect points
     */
    Set<TributarySlot> findCommonTributarySlotsOnCps(ConnectPoint src, ConnectPoint dst) {
        Set<TributarySlot> forward = findTributarySlotsOnCp(src);
        Set<TributarySlot> backward = findTributarySlotsOnCp(dst);
        return Sets.intersection(forward, backward);
    }

    /**
     * Finds the TributarySlots available on the connect point.
     *
     * @param cp connect point
     * @return set of TributarySlots available on the connect point
     */
    Set<TributarySlot> findTributarySlotsOnCp(ConnectPoint cp) {
        return resourceService.getAvailableResourceValues(
                Resources.discrete(cp.deviceId(), cp.port()).id(),
                TributarySlot.class);
    }
}