/*
 * Copyright 2016 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.drivers.lumentum;

import com.google.common.collect.Lists;
import org.apache.commons.lang3.tuple.Pair;
import org.onosproject.net.ChannelSpacing;
import org.onosproject.net.GridType;
import org.onosproject.net.OchSignal;
import org.onosproject.net.OchSignalType;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.driver.AbstractHandlerBehaviour;
import org.onosproject.net.flow.DefaultFlowEntry;
import org.onosproject.net.flow.DefaultFlowRule;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowId;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.FlowRuleProgrammable;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.Criteria;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.snmp4j.PDU;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.smi.Integer32;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.UnsignedInteger32;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.util.TreeEvent;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.google.common.base.Preconditions.checkArgument;

// TODO: need to convert between OChSignal and XC channel number
public class LumentumFlowRuleDriver extends AbstractHandlerBehaviour implements FlowRuleProgrammable {

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

    // Default values
    private static final int DEFAULT_TARGET_GAIN_PREAMP = 150;
    private static final int DEFAULT_TARGET_GAIN_BOOSTER = 200;
    private static final int DISABLE_CHANNEL_TARGET_POWER = -650;
    private static final int DEFAULT_CHANNEL_TARGET_POWER = -30;
    private static final int DISABLE_CHANNEL_ABSOLUTE_ATTENUATION = 160;
    private static final int DEFAULT_CHANNEL_ABSOLUTE_ATTENUATION = 50;
    private static final int DISABLE_CHANNEL_ADD_DROP_PORT_INDEX = 1;
    private static final int OUT_OF_SERVICE = 1;
    private static final int IN_SERVICE = 2;
    private static final int OPEN_LOOP = 1;
    private static final int CLOSED_LOOP = 2;
    // First 20 ports are add/mux ports, next 20 are drop/demux
    private static final int DROP_PORT_OFFSET = 20;

    // OIDs
    private static final String CTRL_AMP_MODULE_SERVICE_STATE_PREAMP = ".1.3.6.1.4.1.46184.1.4.4.1.2.1";
    private static final String CTRL_AMP_MODULE_SERVICE_STATE_BOOSTER = ".1.3.6.1.4.1.46184.1.4.4.1.2.2";
    private static final String CTRL_AMP_MODULE_TARGET_GAIN_PREAMP = ".1.3.6.1.4.1.46184.1.4.4.1.8.1";
    private static final String CTRL_AMP_MODULE_TARGET_GAIN_BOOSTER = ".1.3.6.1.4.1.46184.1.4.4.1.8.2";
    private static final String CTRL_CHANNEL_STATE = ".1.3.6.1.4.1.46184.1.4.2.1.3.";
    private static final String CTRL_CHANNEL_MODE = ".1.3.6.1.4.1.46184.1.4.2.1.4.";
    private static final String CTRL_CHANNEL_TARGET_POWER = ".1.3.6.1.4.1.46184.1.4.2.1.6.";
    private static final String CTRL_CHANNEL_ADD_DROP_PORT_INDEX = ".1.3.6.1.4.1.46184.1.4.2.1.13.";
    private static final String CTRL_CHANNEL_ABSOLUTE_ATTENUATION = ".1.3.6.1.4.1.46184.1.4.2.1.5.";

    private LumentumSnmpDevice snmp;

    @Override
    public Collection<FlowEntry> getFlowEntries() {
        try {
            snmp = new LumentumSnmpDevice(handler().data().deviceId());
        } catch (IOException e) {
            log.error("Failed to connect to device: ", e);
            return Collections.emptyList();
        }

        // Line in is last but one port, line out is last
        DeviceService deviceService = this.handler().get(DeviceService.class);
        List<Port> ports = deviceService.getPorts(data().deviceId());
        if (ports.size() < 2) {
            return Collections.emptyList();
        }
        PortNumber lineIn = ports.get(ports.size() - 2).number();
        PortNumber lineOut = ports.get(ports.size() - 1).number();

        Collection<FlowEntry> entries = Lists.newLinkedList();

        // Add rules
        OID addOid = new OID(CTRL_CHANNEL_STATE + "1");
        entries.addAll(
                fetchRules(addOid, true, lineOut).stream()
                        .map(fr -> new DefaultFlowEntry(fr, FlowEntry.FlowEntryState.ADDED, 0, 0, 0))
                        .collect(Collectors.toList())
        );

        // Drop rules
        OID dropOid = new OID(CTRL_CHANNEL_STATE + "2");
        entries.addAll(
                fetchRules(dropOid, false, lineIn).stream()
                        .map(fr -> new DefaultFlowEntry(fr, FlowEntry.FlowEntryState.ADDED, 0, 0, 0))
                        .collect(Collectors.toList())
        );

        return entries;
    }

    @Override
    public Collection<FlowRule> applyFlowRules(Collection<FlowRule> rules) {
        try {
            snmp = new LumentumSnmpDevice(data().deviceId());
        } catch (IOException e) {
            log.error("Failed to connect to device: ", e);
        }

        // Line ports
        DeviceService deviceService = this.handler().get(DeviceService.class);
        List<Port> ports = deviceService.getPorts(data().deviceId());
        List<PortNumber> linePorts = ports.subList(ports.size() - 2, ports.size()).stream()
                .map(p -> p.number())
                .collect(Collectors.toList());

        // Apply the valid rules on the device
        Collection<FlowRule> added = rules.stream()
                .map(r -> new CrossConnectFlowRule(r, linePorts))
                .filter(xc -> installCrossConnect(xc))
                .collect(Collectors.toList());

        // Cache the cookie/priority
        CrossConnectCache cache = this.handler().get(CrossConnectCache.class);
        added.stream()
                .forEach(xc -> cache.set(
                        Objects.hash(data().deviceId(), xc.selector(), xc.treatment()),
                        xc.id(),
                        xc.priority()));

        return added;
    }

    @Override
    public Collection<FlowRule> removeFlowRules(Collection<FlowRule> rules) {
        try {
            snmp = new LumentumSnmpDevice(data().deviceId());
        } catch (IOException e) {
            log.error("Failed to connect to device: ", e);
        }

        // Line ports
        DeviceService deviceService = this.handler().get(DeviceService.class);
        List<Port> ports = deviceService.getPorts(data().deviceId());
        List<PortNumber> linePorts = ports.subList(ports.size() - 2, ports.size()).stream()
                .map(p -> p.number())
                .collect(Collectors.toList());

        // Apply the valid rules on the device
        Collection<FlowRule> removed = rules.stream()
                .map(r -> new CrossConnectFlowRule(r, linePorts))
                .filter(xc -> removeCrossConnect(xc))
                .collect(Collectors.toList());

        // Remove flow rule from cache
        CrossConnectCache cache = this.handler().get(CrossConnectCache.class);
        removed.stream()
                .forEach(xc -> cache.remove(
                        Objects.hash(data().deviceId(), xc.selector(), xc.treatment())));

        return removed;
    }

    // Installs cross connect on device
    private boolean installCrossConnect(CrossConnectFlowRule xc) {

        int channel = toChannel(xc.ochSignal());
        long addDrop = xc.addDrop().toLong();
        if (!xc.isAddRule()) {
            addDrop -= DROP_PORT_OFFSET;
        }

        // Create the PDU object
        PDU pdu = new PDU();
        pdu.setType(PDU.SET);

        // Enable preamp & booster
        List<OID> oids = Arrays.asList(new OID(CTRL_AMP_MODULE_SERVICE_STATE_PREAMP),
                new OID(CTRL_AMP_MODULE_SERVICE_STATE_BOOSTER));
        oids.forEach(
                oid -> pdu.add(new VariableBinding(oid, new Integer32(IN_SERVICE)))
        );

        // Set target gain on preamp & booster
        OID ctrlAmpModuleTargetGainPreamp = new OID(CTRL_AMP_MODULE_TARGET_GAIN_PREAMP);
        pdu.add(new VariableBinding(ctrlAmpModuleTargetGainPreamp, new Integer32(DEFAULT_TARGET_GAIN_PREAMP)));
        OID ctrlAmpModuleTargetGainBooster = new OID(CTRL_AMP_MODULE_TARGET_GAIN_BOOSTER);
        pdu.add(new VariableBinding(ctrlAmpModuleTargetGainBooster, new Integer32(DEFAULT_TARGET_GAIN_BOOSTER)));

        // Make cross connect
        OID ctrlChannelAddDropPortIndex = new OID(CTRL_CHANNEL_ADD_DROP_PORT_INDEX +
                (xc.isAddRule() ? "1." : "2.") + channel);
        pdu.add(new VariableBinding(ctrlChannelAddDropPortIndex, new UnsignedInteger32(addDrop)));

        // Add rules use closed loop, drop rules open loop
        // Add rules are set to target power, drop rules are attenuated
        if (xc.isAddRule()) {
            OID ctrlChannelMode = new OID(CTRL_CHANNEL_MODE + "1." + channel);
            pdu.add(new VariableBinding(ctrlChannelMode, new Integer32(CLOSED_LOOP)));

            OID ctrlChannelTargetPower = new OID(CTRL_CHANNEL_TARGET_POWER + "1." + channel);
            pdu.add(new VariableBinding(ctrlChannelTargetPower, new Integer32(DEFAULT_CHANNEL_TARGET_POWER)));
        } else {
            OID ctrlChannelMode = new OID(CTRL_CHANNEL_MODE + "2." + channel);
            pdu.add(new VariableBinding(ctrlChannelMode, new Integer32(OPEN_LOOP)));

            OID ctrlChannelAbsoluteAttenuation = new OID(CTRL_CHANNEL_ABSOLUTE_ATTENUATION + "2." + channel);
            pdu.add(new VariableBinding(
                    ctrlChannelAbsoluteAttenuation, new UnsignedInteger32(DEFAULT_CHANNEL_ABSOLUTE_ATTENUATION)));
        }

        // Final step is to enable the channel
        OID ctrlChannelState = new OID(CTRL_CHANNEL_STATE + (xc.isAddRule() ? "1." : "2.") + channel);
        pdu.add(new VariableBinding(ctrlChannelState, new Integer32(IN_SERVICE)));

        try {
            ResponseEvent response = snmp.set(pdu);

             // TODO: parse response
        } catch (IOException e) {
            log.error("Failed to create cross connect, unable to connect to device: ", e);
        }

        return true;
    }

    // Removes cross connect on device
    private boolean removeCrossConnect(CrossConnectFlowRule xc) {

        int channel = toChannel(xc.ochSignal());

        // Create the PDU object
        PDU pdu = new PDU();
        pdu.setType(PDU.SET);

        // Disable the channel
        OID ctrlChannelState = new OID(CTRL_CHANNEL_STATE + (xc.isAddRule() ? "1." : "2.") + channel);
        pdu.add(new VariableBinding(ctrlChannelState, new Integer32(OUT_OF_SERVICE)));

        // Put cross connect back into default port 1
        OID ctrlChannelAddDropPortIndex = new OID(CTRL_CHANNEL_ADD_DROP_PORT_INDEX +
                (xc.isAddRule() ? "1." : "2.") + channel);
        pdu.add(new VariableBinding(ctrlChannelAddDropPortIndex,
                new UnsignedInteger32(DISABLE_CHANNEL_ADD_DROP_PORT_INDEX)));

        // Put port/channel back to open loop
        OID ctrlChannelMode = new OID(CTRL_CHANNEL_MODE + (xc.isAddRule() ? "1." : "2.") + channel);
        pdu.add(new VariableBinding(ctrlChannelMode, new Integer32(OPEN_LOOP)));

        // Add rules are set to target power, drop rules are attenuated
        if (xc.isAddRule()) {
            OID ctrlChannelTargetPower = new OID(CTRL_CHANNEL_TARGET_POWER + "1." + channel);
            pdu.add(new VariableBinding(ctrlChannelTargetPower, new Integer32(DISABLE_CHANNEL_TARGET_POWER)));
        } else {
            OID ctrlChannelAbsoluteAttenuation = new OID(CTRL_CHANNEL_ABSOLUTE_ATTENUATION + "2." + channel);
            pdu.add(new VariableBinding(
                    ctrlChannelAbsoluteAttenuation, new UnsignedInteger32(DISABLE_CHANNEL_ABSOLUTE_ATTENUATION)));
        }

        try {
            ResponseEvent response = snmp.set(pdu);

            // TODO: parse response
        } catch (IOException e) {
            log.error("Failed to remove cross connect, unable to connect to device: ", e);
            return false;
        }

        return true;
    }

    /**
     * Convert OCh signal to Lumentum channel ID.
     *
     * @param ochSignal OCh signal
     * @return Lumentum channel ID
     */
    public static int toChannel(OchSignal ochSignal) {
        // FIXME: move to cross connect validation
        checkArgument(ochSignal.channelSpacing() == ChannelSpacing.CHL_50GHZ);
        checkArgument(LumentumSnmpDevice.START_CENTER_FREQ.compareTo(ochSignal.centralFrequency()) <= 0);
        checkArgument(LumentumSnmpDevice.END_CENTER_FREQ.compareTo(ochSignal.centralFrequency()) >= 0);

        return ochSignal.spacingMultiplier() + LumentumSnmpDevice.MULTIPLIER_SHIFT;
    }

    /**
     * Convert Lumentum channel ID to OCh signal.
     *
     * @param channel Lumentum channel ID
     * @return OCh signal
     */
    public static OchSignal toOchSignal(int channel) {
        checkArgument(1 <= channel);
        checkArgument(channel <= 96);

        return new OchSignal(GridType.DWDM, ChannelSpacing.CHL_50GHZ,
                channel - LumentumSnmpDevice.MULTIPLIER_SHIFT, 4);
    }

    // Returns the currently configured add/drop port for the given channel.
    private PortNumber getAddDropPort(int channel, boolean isAddPort) {
        OID oid = new OID(CTRL_CHANNEL_ADD_DROP_PORT_INDEX + (isAddPort ? "1" : "2"));

        for (TreeEvent event : snmp.get(oid)) {
            if (event == null) {
                return null;
            }

            VariableBinding[] varBindings = event.getVariableBindings();

            for (VariableBinding varBinding : varBindings) {
                if (varBinding.getOid().last() == channel) {
                    int port = varBinding.getVariable().toInt();
                    if (!isAddPort) {
                        port += DROP_PORT_OFFSET;
                    }
                    return PortNumber.portNumber(port);

                }
            }

        }

        return null;
    }

    // Returns the currently installed flow entries on the device.
    private List<FlowRule> fetchRules(OID oid, boolean isAdd, PortNumber linePort) {
        List<FlowRule> rules = new LinkedList<>();

        for (TreeEvent event : snmp.get(oid)) {
            if (event == null) {
                continue;
            }

            VariableBinding[] varBindings = event.getVariableBindings();
            for (VariableBinding varBinding : varBindings) {
                CrossConnectCache cache = this.handler().get(CrossConnectCache.class);

                if (varBinding.getVariable().toInt() == IN_SERVICE) {
                    int channel = varBinding.getOid().removeLast();

                    PortNumber addDropPort = getAddDropPort(channel, isAdd);
                    if (addDropPort == null) {
                        continue;
                    }

                    TrafficSelector selector = DefaultTrafficSelector.builder()
                            .matchInPort(isAdd ? addDropPort : linePort)
                            .add(Criteria.matchOchSignalType(OchSignalType.FIXED_GRID))
                            .add(Criteria.matchLambda(toOchSignal(channel)))
                            .build();
                    TrafficTreatment treatment = DefaultTrafficTreatment.builder()
                            .setOutput(isAdd ? linePort : addDropPort)
                            .build();

                    // Lookup flow ID and priority
                    int hash = Objects.hash(data().deviceId(), selector, treatment);
                    Pair<FlowId, Integer> lookup = cache.get(hash);
                    if (lookup == null) {
                        continue;
                    }

                    FlowRule fr = DefaultFlowRule.builder()
                            .forDevice(data().deviceId())
                            .makePermanent()
                            .withSelector(selector)
                            .withTreatment(treatment)
                            .withPriority(lookup.getRight())
                            .withCookie(lookup.getLeft().value())
                            .build();
                    rules.add(fr);
                }
            }
        }

        return rules;
    }
}
