/*
 * 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.
                annotations = annotations(node.get("annotations"));
                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();
            }
        }
    }

}
