/*
 * Copyright 2014-2015 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.rest.resources;

import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import org.onlab.packet.ChassisId;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onlab.util.Frequency;
import org.onosproject.net.AnnotationKeys;
import org.onosproject.net.ChannelSpacing;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.GridType;
import org.onosproject.net.Host;
import org.onosproject.net.HostId;
import org.onosproject.net.HostLocation;
import org.onosproject.net.Link;
import org.onosproject.net.MastershipRole;
import org.onosproject.net.OchPort;
import org.onosproject.net.OchSignal;
import org.onosproject.net.OduCltPort;
import org.onosproject.net.OduSignalType;
import org.onosproject.net.OmsPort;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.SparseAnnotations;
import org.onosproject.net.device.DefaultDeviceDescription;
import org.onosproject.net.device.DefaultPortDescription;
import org.onosproject.net.device.DeviceDescription;
import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceProvider;
import org.onosproject.net.device.DeviceProviderRegistry;
import org.onosproject.net.device.DeviceProviderService;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.device.OchPortDescription;
import org.onosproject.net.device.OduCltPortDescription;
import org.onosproject.net.device.OmsPortDescription;
import org.onosproject.net.device.PortDescription;
import org.onosproject.net.host.DefaultHostDescription;
import org.onosproject.net.host.HostProvider;
import org.onosproject.net.host.HostProviderRegistry;
import org.onosproject.net.host.HostProviderService;
import org.onosproject.net.link.DefaultLinkDescription;
import org.onosproject.net.link.LinkProvider;
import org.onosproject.net.link.LinkProviderRegistry;
import org.onosproject.net.link.LinkProviderService;
import org.onosproject.net.provider.ProviderId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URI;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.google.common.base.Preconditions.checkNotNull;
import static org.onosproject.net.DeviceId.deviceId;
import static org.onosproject.net.PortNumber.portNumber;
import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED;

/**
 * Provider of devices and links parsed from a JSON configuration structure.
 */
class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider {

    private final Logger log = LoggerFactory.getLogger(getClass());

    private static final ProviderId PID =
            new ProviderId("cfg", "org.onosproject.rest", true);

    private static final String UNKNOWN = "unknown";

    private static final Frequency CENTER = Frequency.ofTHz(193.1);
    // C-band has 4.4 THz (4,400 GHz) total bandwidth
    private static final Frequency TOTAL = Frequency.ofTHz(4.4);

    private CountDownLatch deviceLatch;

    private final JsonNode cfg;
    private final DeviceService deviceService;

    private final DeviceProviderRegistry deviceProviderRegistry;
    private final LinkProviderRegistry linkProviderRegistry;
    private final HostProviderRegistry hostProviderRegistry;

    private DeviceProviderService deviceProviderService;
    private LinkProviderService linkProviderService;
    private HostProviderService hostProviderService;

    private DeviceListener deviceEventCounter = new DeviceEventCounter();
    private List<ConnectPoint> connectPoints = Lists.newArrayList();
    private Map<ConnectPoint, PortDescription> descriptions = Maps.newHashMap();

    /**
     * Creates a new configuration provider.
     *
     * @param cfg                    JSON configuration
     * @param deviceService          device service
     * @param deviceProviderRegistry device provider registry
     * @param linkProviderRegistry   link provider registry
     * @param hostProviderRegistry   host provider registry
     */
    ConfigProvider(JsonNode cfg,
                   DeviceService deviceService,
                   DeviceProviderRegistry deviceProviderRegistry,
                   LinkProviderRegistry linkProviderRegistry,
                   HostProviderRegistry hostProviderRegistry) {
        this.cfg = checkNotNull(cfg, "Configuration cannot be null");
        this.deviceService = checkNotNull(deviceService, "Device service cannot be null");
        this.deviceProviderRegistry = checkNotNull(deviceProviderRegistry, "Device provider registry cannot be null");
        this.linkProviderRegistry = checkNotNull(linkProviderRegistry, "Link provider registry cannot be null");
        this.hostProviderRegistry = checkNotNull(hostProviderRegistry, "Host provider registry cannot be null");
    }

    /**
     * Parses the given JSON and provides links as configured.
     */
    void parse() {
        try {
            register();
            parseDevices();
            parseLinks();
            parseHosts();
            addMissingPorts();
        } finally {
            unregister();
        }
    }

    private void register() {
        deviceProviderService = deviceProviderRegistry.register(this);
        linkProviderService = linkProviderRegistry.register(this);
        hostProviderService = hostProviderRegistry.register(this);
    }

    private void unregister() {
        deviceProviderRegistry.unregister(this);
        linkProviderRegistry.unregister(this);
        hostProviderRegistry.unregister(this);
    }

    // Parses the given JSON and provides devices.
    private void parseDevices() {
        try {
            JsonNode nodes = cfg.get("devices");
            if (nodes != null) {
                prepareForDeviceEvents(nodes.size());
                for (JsonNode node : nodes) {
                    parseDevice(node);

                    // FIXME: hack to make sure device attributes take
                    // This will be fixed when GossipDeviceStore uses ECM
                    parseDevice(node);
                }
            }
        } finally {
            waitForDeviceEvents();
        }
    }

    // Parses the given node with device data and supplies the device.
    private void parseDevice(JsonNode node) {
        URI uri = URI.create(get(node, "uri"));
        Device.Type type = Device.Type.valueOf(get(node, "type", "SWITCH"));
        String mfr = get(node, "mfr", UNKNOWN);
        String hw = get(node, "hw", UNKNOWN);
        String sw = get(node, "sw", UNKNOWN);
        String serial = get(node, "serial", UNKNOWN);
        ChassisId cid = new ChassisId(get(node, "mac", "000000000000"));
        SparseAnnotations annotations = annotations(node.get("annotations"));

        DeviceDescription desc =
                new DefaultDeviceDescription(uri, type, mfr, hw, sw, serial,
                                             cid, annotations);
        DeviceId deviceId = deviceId(uri);
        deviceProviderService.deviceConnected(deviceId, desc);

        JsonNode ports = node.get("ports");
        if (ports != null) {
            parsePorts(deviceId, ports);
        }
    }

    // Parses the given node with list of device ports.
    private void parsePorts(DeviceId deviceId, JsonNode nodes) {
        List<PortDescription> ports = new ArrayList<>();
        for (JsonNode node : nodes) {
            ports.add(parsePort(deviceId, node));
        }
        deviceProviderService.updatePorts(deviceId, ports);
    }

    // Parses the given node with port information.
    private PortDescription parsePort(DeviceId deviceId, JsonNode node) {
        Port.Type type = Port.Type.valueOf(node.path("type").asText("COPPER"));
        // TL1-based ports have a name
        PortNumber port = null;
        if (node.has("name")) {
            for (Port p : deviceService.getPorts(deviceId)) {
                if (p.number().name().equals(node.get("name").asText())) {
                    port = p.number();
                    break;
                }
            }
        } else {
            port = portNumber(node.path("port").asLong(0));
        }

        if (port == null) {
            log.error("Cannot find port given in node {}", node);
            return null;
        }

        String portName = Strings.emptyToNull(port.name());
        SparseAnnotations annotations  = null;
        if (portName != null) {
            annotations = DefaultAnnotations.builder()
                    .set(AnnotationKeys.PORT_NAME, portName).build();
        }
        switch (type) {
            case COPPER:
                return new DefaultPortDescription(port, node.path("enabled").asBoolean(true),
                                                  type, node.path("speed").asLong(1_000),
                                                  annotations);
            case FIBER:
                // Currently, assume OMS when FIBER. Provide sane defaults.
                return new OmsPortDescription(port, node.path("enabled").asBoolean(true),
                                              CENTER, CENTER.add(TOTAL),
                                              Frequency.ofGHz(100), annotations);
            case ODUCLT:
                annotations = annotations(node.get("annotations"));
                OduCltPort oduCltPort = (OduCltPort) deviceService.getPort(deviceId, port);
                return new OduCltPortDescription(port, node.path("enabled").asBoolean(true),
                        oduCltPort.signalType(), annotations);
            case OCH:
                annotations = annotations(node.get("annotations"));
                OchPort ochPort = (OchPort) deviceService.getPort(deviceId, port);
                return new OchPortDescription(port, node.path("enabled").asBoolean(true),
                        ochPort.signalType(), ochPort.isTunable(),
                        ochPort.lambda(), annotations);
            case OMS:
                annotations = annotations(node.get("annotations"));
                OmsPort omsPort = (OmsPort) deviceService.getPort(deviceId, port);
                return new OmsPortDescription(port, node.path("enabled").asBoolean(true),
                        omsPort.minFrequency(), omsPort.maxFrequency(), omsPort.grid(), annotations);
            default:
                log.warn("{}: Unsupported Port Type");
        }
        return new DefaultPortDescription(port, node.path("enabled").asBoolean(true),
                                          type, node.path("speed").asLong(1_000),
                                          annotations);
    }

    // Parses the given JSON and provides links as configured.
    private void parseLinks() {
        JsonNode nodes = cfg.get("links");
        if (nodes != null) {
            for (JsonNode node : nodes) {
                parseLink(node, false);
                if (!node.has("halfplex")) {
                    parseLink(node, true);
                }
            }
        }
    }

    // Parses the given node with link data and supplies the link.
    private void parseLink(JsonNode node, boolean reverse) {
        ConnectPoint src = connectPoint(get(node, "src"));
        ConnectPoint dst = connectPoint(get(node, "dst"));
        Link.Type type = Link.Type.valueOf(get(node, "type", "DIRECT"));
        SparseAnnotations annotations = annotations(node.get("annotations"));
        // take annotations to update optical ports with correct attributes.
        updatePorts(src, dst, annotations);
        DefaultLinkDescription desc = reverse ?
                new DefaultLinkDescription(dst, src, type, annotations) :
                new DefaultLinkDescription(src, dst, type, annotations);
        linkProviderService.linkDetected(desc);

        connectPoints.add(src);
        connectPoints.add(dst);
    }

    private void updatePorts(ConnectPoint src, ConnectPoint dst, SparseAnnotations annotations) {
        final String linkType = annotations.value("optical.type");
        if ("cross-connect".equals(linkType)) {
            String value = annotations.value("bandwidth").trim();
            try {
                double bw = Double.parseDouble(value);
                updateOchPort(bw, src, dst);
            } catch (NumberFormatException e) {
                log.warn("Invalid bandwidth ({}), can't configure port(s)", value);
                return;
            }
        } else if ("WDM".equals(linkType)) {
            String value = annotations.value("optical.waves").trim();
            try {
                int numChls = Integer.parseInt(value);
                updateOMSPorts(numChls, src, dst);
            } catch (NumberFormatException e) {
                log.warn("Invalid channel ({}), can't configure port(s)", value);
                return;
            }
        }
    }

    // uses 'bandwidth' annotation to determine the channel spacing.
    private void updateOchPort(double bw, ConnectPoint srcCp, ConnectPoint dstCp) {
        Device src = deviceService.getDevice(srcCp.deviceId());
        Device dst = deviceService.getDevice(dstCp.deviceId());
        // bandwidth in MHz (assuming Hz - linc is not clear if that or Mb).
        Frequency spacing = Frequency.ofMHz(bw);
        // channel bandwidth is smaller than smallest standard channel spacing.
        ChannelSpacing chsp = null;
        if (spacing.compareTo(ChannelSpacing.CHL_6P25GHZ.frequency()) <= 0) {
            chsp = ChannelSpacing.CHL_6P25GHZ;
        }
        for (int i = 1; i < ChannelSpacing.values().length; i++) {
            Frequency val = ChannelSpacing.values()[i].frequency();
            // pick the next highest or equal channel interval.
            if (val.isLessThan(spacing)) {
                chsp = ChannelSpacing.values()[i - 1];
                break;
            }
        }
        if (chsp == null) {
            log.warn("Invalid channel spacing ({}), can't configure port(s)", spacing);
            return;
        }
        OchSignal signal = new OchSignal(GridType.DWDM, chsp, 1, 1);
        if (src.type() == Device.Type.ROADM) {
            PortDescription portDesc = new OchPortDescription(srcCp.port(), true,
                    OduSignalType.ODU4, true, signal);
            descriptions.put(srcCp, portDesc);
            deviceProviderService.portStatusChanged(srcCp.deviceId(), portDesc);
        }
        if (dst.type() == Device.Type.ROADM) {
            PortDescription portDesc = new OchPortDescription(dstCp.port(), true,
                    OduSignalType.ODU4, true, signal);
            descriptions.put(dstCp, portDesc);
            deviceProviderService.portStatusChanged(dstCp.deviceId(), portDesc);
        }
    }

    private void updateOMSPorts(int numChls, ConnectPoint srcCp, ConnectPoint dstCp) {
        // round down to largest slot that allows numChl channels to fit into C band range
        ChannelSpacing chl = null;
        Frequency perChl = TOTAL.floorDivision(numChls);
        for (int i = 0; i < ChannelSpacing.values().length; i++) {
            Frequency val = ChannelSpacing.values()[i].frequency();
            if (val.isLessThan(perChl)) {
                chl = ChannelSpacing.values()[i];
                break;
            }
        }
        if (chl == null) {
            chl = ChannelSpacing.CHL_6P25GHZ;
        }

        // if true, there was less channels than can be tightly packed.
        Frequency grid = chl.frequency();
        // say Linc's 1st slot starts at CENTER and goes up from there.
        Frequency min = CENTER.add(grid);
        Frequency max = CENTER.add(grid.multiply(numChls));

        PortDescription srcPortDesc = new OmsPortDescription(srcCp.port(), true, min, max, grid);
        PortDescription dstPortDesc = new OmsPortDescription(dstCp.port(), true, min, max, grid);
        descriptions.put(srcCp, srcPortDesc);
        descriptions.put(dstCp, dstPortDesc);
        deviceProviderService.portStatusChanged(srcCp.deviceId(), srcPortDesc);
        deviceProviderService.portStatusChanged(dstCp.deviceId(), dstPortDesc);
    }

    // Parses the given JSON and provides hosts as configured.
    private void parseHosts() {
        try {
            JsonNode nodes = cfg.get("hosts");
            if (nodes != null) {
                for (JsonNode node : nodes) {
                    parseHost(node);

                    // FIXME: hack to make sure host attributes take
                    // This will be fixed when GossipHostStore uses ECM
                    parseHost(node);
                }
            }
        } finally {
            hostProviderRegistry.unregister(this);
        }
    }

    // Parses the given node with host data and supplies the host.
    private void parseHost(JsonNode node) {
        MacAddress mac = MacAddress.valueOf(get(node, "mac"));
        VlanId vlanId = VlanId.vlanId((short) node.get("vlan").asInt(VlanId.UNTAGGED));
        HostId hostId = HostId.hostId(mac, vlanId);
        SparseAnnotations annotations = annotations(node.get("annotations"));
        HostLocation location = new HostLocation(connectPoint(get(node, "location")), 0);

        String[] ipStrings = get(node, "ip", "").split(",");
        Set<IpAddress> ips = new HashSet<>();
        for (String ip : ipStrings) {
            ips.add(IpAddress.valueOf(ip.trim()));
        }

        DefaultHostDescription desc =
                new DefaultHostDescription(mac, vlanId, location, ips, annotations);
        hostProviderService.hostDetected(hostId, desc);

        connectPoints.add(location);
    }

    // Adds any missing device ports for configured links and host locations.
    private void addMissingPorts() {
        deviceService.getDevices().forEach(this::addMissingPorts);
    }

    // Adds any missing device ports.
    private void addMissingPorts(Device device) {
        try {
            List<Port> ports = deviceService.getPorts(device.id());
            Set<ConnectPoint> existing = ports.stream()
                    .map(p -> new ConnectPoint(device.id(), p.number()))
                    .collect(Collectors.toSet());
            Set<ConnectPoint> missing = connectPoints.stream()
                    .filter(cp -> cp.deviceId().equals(device.id()))
                    .filter(cp -> !existing.contains(cp))
                    .collect(Collectors.toSet());

            if (!missing.isEmpty()) {
                List<PortDescription> newPorts = Stream.concat(
                        ports.stream().map(this::description),
                        missing.stream().map(this::description)
                ).collect(Collectors.toList());
                deviceProviderService.updatePorts(device.id(), newPorts);
            }
        } catch (IllegalArgumentException e) {
            log.warn("Error pushing ports: {}", e.getMessage());
        }
    }

    // Creates a port description from the specified port.
    private PortDescription description(Port p) {
        switch (p.type()) {
            case OMS:
                OmsPort op = (OmsPort) p;
                return new OmsPortDescription(
                        op.number(), op.isEnabled(), op.minFrequency(), op.maxFrequency(), op.grid());
            case OCH:
                OchPort ochp = (OchPort) p;
                return new OchPortDescription(
                        ochp.number(), ochp.isEnabled(), ochp.signalType(), ochp.isTunable(), ochp.lambda());
            case ODUCLT:
                OduCltPort odup = (OduCltPort) p;
                return new OduCltPortDescription(
                        odup.number(), odup.isEnabled(), odup.signalType());
            default:
                return new DefaultPortDescription(p.number(), p.isEnabled(), p.type(), p.portSpeed());
        }
    }

    // Creates a port description from the specified connection point if none created earlier.
    private PortDescription description(ConnectPoint cp) {
        PortDescription saved = descriptions.get(cp);
        if (saved != null) {
            return saved;
        }
        Port p = deviceService.getPort(cp.deviceId(), cp.port());
        if (p == null) {
            return new DefaultPortDescription(cp.port(), true);
        }
        return description(p);
    }

    // Produces set of annotations from the given JSON node.
    private SparseAnnotations annotations(JsonNode node) {
        if (node == null) {
            return DefaultAnnotations.EMPTY;
        }

        DefaultAnnotations.Builder builder = DefaultAnnotations.builder();
        Iterator<String> it = node.fieldNames();
        while (it.hasNext()) {
            String k = it.next();
            builder.set(k, node.get(k).asText());
        }
        return builder.build();
    }

    // Produces a connection point from the specified uri/port text.
    private ConnectPoint connectPoint(String text) {
        int i = text.lastIndexOf("/");
        String portName = text.substring(i + 1);
        DeviceId deviceId = deviceId(text.substring(0, i));

        for (Port port : deviceService.getPorts(deviceId)) {
            PortNumber pn = port.number();
            if (pn.name().equals(portName)) {
                return new ConnectPoint(deviceId, pn);
            }
        }

        long portNum;
        try {
            portNum = Long.parseLong(portName);
        } catch (NumberFormatException e) {
            portNum = 0;
        }

        return new ConnectPoint(deviceId, portNumber(portNum, portName));
    }

    // Returns string form of the named property in the given JSON object.
    private String get(JsonNode node, String name) {
        return node.path(name).asText();
    }

    // Returns string form of the named property in the given JSON object.
    private String get(JsonNode node, String name, String defaultValue) {
        return node.path(name).asText(defaultValue);
    }

    @Override
    public void roleChanged(DeviceId device, MastershipRole newRole) {
        deviceProviderService.receivedRoleReply(device, newRole, newRole);
    }

    @Override
    public void triggerProbe(DeviceId deviceId) {
    }

    @Override
    public void triggerProbe(Host host) {
    }

    @Override
    public ProviderId id() {
        return PID;
    }

    @Override
    public boolean isReachable(DeviceId device) {
        return true;
    }

    /**
     * Prepares to count device added/available/removed events.
     *
     * @param count number of events to count
     */
    protected void prepareForDeviceEvents(int count) {
        deviceLatch = new CountDownLatch(count);
        deviceService.addListener(deviceEventCounter);
    }

    /**
     * Waits for all expected device added/available/removed events.
     */
    protected void waitForDeviceEvents() {
        try {
            deviceLatch.await(2, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            log.warn("Device events did not arrive in time");
        }
        deviceService.removeListener(deviceEventCounter);
    }

    // Counts down number of device added/available/removed events.
    private class DeviceEventCounter implements DeviceListener {
        @Override
        public void event(DeviceEvent event) {
            DeviceEvent.Type type = event.type();
            if (type == DEVICE_ADDED || type == DEVICE_AVAILABILITY_CHANGED) {
                deviceLatch.countDown();
            }
        }
    }

}
