/*
 *  Copyright 2016-present Open Networking Foundation
 *
 *  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.ui.impl.topo.model;

import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onosproject.cluster.ControllerNode;
import org.onosproject.cluster.NodeId;
import org.onosproject.cluster.RoleInfo;
import org.onosproject.event.EventDispatcher;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.EdgeLink;
import org.onosproject.net.Host;
import org.onosproject.net.HostId;
import org.onosproject.net.HostLocation;
import org.onosproject.net.Link;
import org.onosproject.net.region.Region;
import org.onosproject.net.region.RegionId;
import org.onosproject.ui.UiTopoLayoutService;
import org.onosproject.ui.impl.topo.Topo2Jsonifier;
import org.onosproject.ui.model.ServiceBundle;
import org.onosproject.ui.model.topo.UiClusterMember;
import org.onosproject.ui.model.topo.UiDevice;
import org.onosproject.ui.model.topo.UiDeviceLink;
import org.onosproject.ui.model.topo.UiEdgeLink;
import org.onosproject.ui.model.topo.UiElement;
import org.onosproject.ui.model.topo.UiHost;
import org.onosproject.ui.model.topo.UiLinkId;
import org.onosproject.ui.model.topo.UiModelEvent;
import org.onosproject.ui.model.topo.UiRegion;
import org.onosproject.ui.model.topo.UiSynthLink;
import org.onosproject.ui.model.topo.UiTopoLayout;
import org.onosproject.ui.model.topo.UiTopoLayoutId;
import org.onosproject.ui.model.topo.UiTopology;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
import static org.onosproject.ui.model.topo.UiModelEvent.Type.CLUSTER_MEMBER_ADDED_OR_UPDATED;
import static org.onosproject.ui.model.topo.UiModelEvent.Type.CLUSTER_MEMBER_REMOVED;
import static org.onosproject.ui.model.topo.UiModelEvent.Type.DEVICE_ADDED_OR_UPDATED;
import static org.onosproject.ui.model.topo.UiModelEvent.Type.DEVICE_REMOVED;
import static org.onosproject.ui.model.topo.UiModelEvent.Type.HOST_ADDED_OR_UPDATED;
import static org.onosproject.ui.model.topo.UiModelEvent.Type.HOST_MOVED;
import static org.onosproject.ui.model.topo.UiModelEvent.Type.HOST_REMOVED;
import static org.onosproject.ui.model.topo.UiModelEvent.Type.LINK_ADDED_OR_UPDATED;
import static org.onosproject.ui.model.topo.UiModelEvent.Type.LINK_REMOVED;
import static org.onosproject.ui.model.topo.UiModelEvent.Type.REGION_ADDED_OR_UPDATED;
import static org.onosproject.ui.model.topo.UiModelEvent.Type.REGION_REMOVED;
import static org.onosproject.ui.model.topo.UiLinkId.uiLinkId;

/**
 * UI Topology Model cache.
 */
class ModelCache {

    private static final String E_NO_ELEMENT = "Tried to remove non-member {}: {}";
    private static final String MEMO_ADDED = "added";
    private static final String MEMO_UPDATED = "updated";
    private static final String MEMO_REMOVED = "removed";
    private static final String MEMO_MOVED = "moved";

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

    // TODO: add NetworkConfigService to service bundle
//    private final NetworkConfigService cfgService =
//            DefaultServiceDirectory.getService(NetworkConfigService.class);

    private final ServiceBundle services;
    private final EventDispatcher dispatcher;
    private final UiTopology uiTopology;

    private Topo2Jsonifier t2json;

    ModelCache(ServiceBundle services, EventDispatcher eventDispatcher) {
        this.services = services;
        this.dispatcher = eventDispatcher;
        uiTopology = new UiTopology(services);
    }

    @Override
    public String toString() {
        return "ModelCache{" + uiTopology + "}";
    }

    private void postEvent(UiModelEvent.Type type, UiElement subject, String memo) {
        ObjectNode data = t2json != null ? t2json.jsonUiElement(subject) : null;
        dispatcher.post(new UiModelEvent(type, subject, data, memo));
    }

    void injectJsonifier(Topo2Jsonifier t2json) {
        this.t2json = t2json;
    }

    void clear() {
        uiTopology.clear();
    }

    /**
     * Create our internal model of the global topology. An assumption we are
     * making is that the topology is empty to start.
     */
    void load() {
        loadClusterMembers();
        loadRegions();
        loadDevices();
        loadDeviceLinks();
        loadHosts();
    }


    // === CLUSTER MEMBERS

    private UiClusterMember addNewClusterMember(ControllerNode n) {
        UiClusterMember member = new UiClusterMember(uiTopology, n);
        uiTopology.add(member);
        return member;
    }

    private void updateClusterMember(UiClusterMember member) {
        // maybe something to update in the future?
    }

    private void loadClusterMembers() {
        for (ControllerNode n : services.cluster().getNodes()) {
            UiClusterMember member = addNewClusterMember(n);
            updateClusterMember(member);
        }
    }

    // invoked from UiSharedTopologyModel cluster event listener
    void addOrUpdateClusterMember(ControllerNode cnode) {
        NodeId id = cnode.id();
        String memo = MEMO_UPDATED;
        UiClusterMember member = uiTopology.findClusterMember(id);
        if (member == null) {
            member = addNewClusterMember(cnode);
            memo = MEMO_ADDED;
        }
        updateClusterMember(member);

        postEvent(CLUSTER_MEMBER_ADDED_OR_UPDATED, member, memo);
    }

    // package private for unit test access
    UiClusterMember accessClusterMember(NodeId id) {
        return uiTopology.findClusterMember(id);
    }

    // invoked from UiSharedTopologyModel cluster event listener
    void removeClusterMember(ControllerNode cnode) {
        NodeId id = cnode.id();
        UiClusterMember member = uiTopology.findClusterMember(id);
        if (member != null) {
            uiTopology.remove(member);
            postEvent(CLUSTER_MEMBER_REMOVED, member, MEMO_REMOVED);
        } else {
            log.warn(E_NO_ELEMENT, "cluster node", id);
        }
    }

    List<UiClusterMember> getAllClusterMembers() {
        return uiTopology.allClusterMembers();
    }


    // === MASTERSHIP CHANGES

    // invoked from UiSharedTopologyModel mastership listener
    void updateMasterships(DeviceId deviceId, RoleInfo roleInfo) {
        // To think about:: do we need to store mastership info?
        //  or can we rely on looking it up live?
        // TODO: store the updated mastership information
        // TODO: post event
    }

    // === THE NULL REGION

    UiRegion nullRegion() {
        return uiTopology.nullRegion();
    }

    // === REGIONS

    private UiRegion addNewRegion(Region r) {
        UiRegion region = new UiRegion(uiTopology, r);
        uiTopology.add(region);
        log.debug("Region {} added to topology", region);
        return region;
    }

    private void updateRegion(UiRegion region) {
        RegionId rid = region.id();
        Set<DeviceId> deviceIds = services.region().getRegionDevices(rid);
        Set<HostId> hostIds = services.region().getRegionHosts(rid);

        // Make sure device objects refer to their region
        deviceIds.forEach(d -> {
            UiDevice dev = uiTopology.findDevice(d);
            if (dev != null) {
                dev.setRegionId(rid);
            } else {
                // if we don't have the UiDevice in the topology, what can we do?
                log.warn("Region device {}, but we don't have UiDevice in topology", d);
            }
        });

        hostIds.forEach(d -> {
            UiHost host = uiTopology.findHost(d);
            if (host != null) {
                host.setRegionId(rid);
            } else {
                // if we don't have the UiDevice in the topology, what can we do?
                log.warn("Region host {}, but we don't have UiHost in topology", d);
            }
        });

        // Make sure the region object refers to the devices
        region.reconcileDevices(deviceIds);
        region.reconcileHosts(hostIds);

        fixupContainmentHierarchy(region);
    }

    private void fixupContainmentHierarchy(UiRegion region) {
        UiTopoLayoutService ls = services.layout();
        RegionId regionId = region.id();

        UiTopoLayout layout = ls.getLayout(regionId);
        if (layout == null) {
            // no layout backed by this region
            log.warn("No layout backed by region {}", regionId);
            return;
        }

        UiTopoLayoutId layoutId = layout.id();

        if (!layout.isRoot()) {
            UiTopoLayoutId parentId = layout.parent();
            UiTopoLayout parentLayout = ls.getLayout(parentId);
            RegionId parentRegionId = parentLayout.regionId();
            region.setParent(parentRegionId);
        }

        Set<UiTopoLayout> kids = ls.getChildren(layoutId);
        Set<RegionId> kidRegionIds = new HashSet<>(kids.size());
        kids.forEach(k -> kidRegionIds.add(k.regionId()));
        region.setChildren(kidRegionIds);
    }

    private void loadRegions() {
        for (Region r : services.region().getRegions()) {
            UiRegion region = addNewRegion(r);
            updateRegion(region);
        }
    }

    // invoked from UiSharedTopologyModel region listener
    void addOrUpdateRegion(Region region) {
        RegionId id = region.id();
        String memo = MEMO_UPDATED;
        UiRegion uiRegion = uiTopology.findRegion(id);
        if (uiRegion == null) {
            uiRegion = addNewRegion(region);
            memo = MEMO_ADDED;
        }
        updateRegion(uiRegion);

        postEvent(REGION_ADDED_OR_UPDATED, uiRegion, memo);
    }

    // package private for unit test access
    UiRegion accessRegion(RegionId id) {
        return id == null ? null : uiTopology.findRegion(id);
    }

    // invoked from UiSharedTopologyModel region listener
    void removeRegion(Region region) {
        RegionId id = region.id();
        UiRegion uiRegion = uiTopology.findRegion(id);
        if (uiRegion != null) {
            uiTopology.remove(uiRegion);
            postEvent(REGION_REMOVED, uiRegion, MEMO_REMOVED);
        } else {
            log.warn(E_NO_ELEMENT, "region", id);
        }
    }

    Set<UiRegion> getAllRegions() {
        return uiTopology.allRegions();
    }


    // === DEVICES

    private UiDevice addNewDevice(Device d) {
        UiDevice device = new UiDevice(uiTopology, d);
        updateDevice(device);
        uiTopology.add(device);
        log.debug("Device {} added to topology", device);
        return device;
    }

    // make sure the UiDevice is tagged with the region it belongs to
    private void updateDevice(UiDevice device) {
        Region r = services.region().getRegionForDevice(device.id());
        RegionId rid = r == null ? UiRegion.NULL_ID : r.id();
        device.setRegionId(rid);
    }

    private void loadDevices() {
        for (Device d : services.device().getDevices()) {
            addNewDevice(d);
        }
    }

    // invoked from UiSharedTopologyModel device listener
    void addOrUpdateDevice(Device device) {
        DeviceId id = device.id();
        String memo = MEMO_UPDATED;
        UiDevice uiDevice = uiTopology.findDevice(id);
        if (uiDevice == null) {
            uiDevice = addNewDevice(device);
            memo = MEMO_ADDED;
        } else {
            updateDevice(uiDevice);
        }

        postEvent(DEVICE_ADDED_OR_UPDATED, uiDevice, memo);
    }

    // package private for unit test access
    UiDevice accessDevice(DeviceId id) {
        return uiTopology.findDevice(id);
    }

    // invoked from UiSharedTopologyModel device listener
    void removeDevice(Device device) {
        DeviceId id = device.id();
        UiDevice uiDevice = uiTopology.findDevice(id);
        if (uiDevice != null) {
            uiTopology.remove(uiDevice);
            postEvent(DEVICE_REMOVED, uiDevice, MEMO_REMOVED);
        } else {
            log.warn(E_NO_ELEMENT, "device", id);
        }
    }

    Set<UiDevice> getAllDevices() {
        return uiTopology.allDevices();
    }


    // === LINKS ===

    private UiDeviceLink addNewDeviceLink(UiLinkId id) {
        UiDeviceLink uiDeviceLink = new UiDeviceLink(uiTopology, id);
        uiTopology.add(uiDeviceLink);
        return uiDeviceLink;
    }

    private UiEdgeLink addNewEdgeLink(UiLinkId id) {
        UiEdgeLink uiEdgeLink = new UiEdgeLink(uiTopology, id);
        uiTopology.add(uiEdgeLink);
        return uiEdgeLink;
    }

    private void updateDeviceLink(UiDeviceLink uiDeviceLink, Link link) {
        uiDeviceLink.attachBackingLink(link);
    }

    private void loadDeviceLinks() {
        for (Link link : services.link().getLinks()) {
            UiLinkId id = uiLinkId(link);

            UiDeviceLink uiDeviceLink = uiTopology.findDeviceLink(id);
            if (uiDeviceLink == null) {
                uiDeviceLink = addNewDeviceLink(id);
            }
            updateDeviceLink(uiDeviceLink, link);
        }
    }

    // invoked from UiSharedTopologyModel link listener
    void addOrUpdateDeviceLink(Link link) {
        UiLinkId id = uiLinkId(link);
        String memo = MEMO_UPDATED;
        UiDeviceLink uiDeviceLink = uiTopology.findDeviceLink(id);
        if (uiDeviceLink == null) {
            uiDeviceLink = addNewDeviceLink(id);
            memo = MEMO_ADDED;
        }
        updateDeviceLink(uiDeviceLink, link);

        postEvent(LINK_ADDED_OR_UPDATED, uiDeviceLink, memo);
    }

    // package private for unit test access
    UiDeviceLink accessDeviceLink(UiLinkId id) {
        return uiTopology.findDeviceLink(id);
    }

    // invoked from UiSharedTopologyModel link listener
    void removeDeviceLink(Link link) {
        UiLinkId id = uiLinkId(link);
        UiDeviceLink uiDeviceLink = uiTopology.findDeviceLink(id);
        if (uiDeviceLink != null) {
            boolean remaining = uiDeviceLink.detachBackingLink(link);
            if (remaining) {
                postEvent(LINK_ADDED_OR_UPDATED, uiDeviceLink, MEMO_UPDATED);
            } else {
                uiTopology.remove(uiDeviceLink);
                postEvent(LINK_REMOVED, uiDeviceLink, MEMO_REMOVED);
            }
        } else {
            log.warn(E_NO_ELEMENT, "Device link", id);
        }
    }

    Set<UiDeviceLink> getAllDeviceLinks() {
        return uiTopology.allDeviceLinks();
    }

    // === HOSTS

    private EdgeLink synthesizeLink(Host h) {
        return createEdgeLink(h, true);
    }

    private UiHost addNewHost(Host h) {
        UiHost host = new UiHost(uiTopology, h);
        uiTopology.add(host);

        EdgeLink elink = synthesizeLink(h);
        UiLinkId elinkId = uiLinkId(elink);
        host.setEdgeLinkId(elinkId);

        // add synthesized edge link to the topology
        addNewEdgeLink(elinkId);

        return host;
    }

    private void insertNewUiEdgeLink(UiLinkId id) {
        addNewEdgeLink(id);
    }

    private void updateHost(UiHost uiHost, Host h) {
        UiEdgeLink existing = uiTopology.findEdgeLink(uiHost.edgeLinkId());

        // TODO: review - do we need EdgeLink now that we are creating from id only?
        EdgeLink currentElink = synthesizeLink(h);
        UiLinkId currentElinkId = uiLinkId(currentElink);

        if (existing != null) {
            if (!currentElinkId.equals(existing.id())) {
                // edge link has changed
                insertNewUiEdgeLink(currentElinkId);
                uiHost.setEdgeLinkId(currentElinkId);

                uiTopology.remove(existing);
            }

        } else {
            // no previously existing edge link
            insertNewUiEdgeLink(currentElinkId);
            uiHost.setEdgeLinkId(currentElinkId);

        }

        HostLocation hloc = h.location();
        uiHost.setLocation(hloc.deviceId(), hloc.port());
    }

    private void loadHosts() {
        for (Host h : services.host().getHosts()) {
            UiHost host = addNewHost(h);
            updateHost(host, h);
        }
    }

    // invoked from UiSharedTopologyModel host listener
    void addOrUpdateHost(Host host) {
        HostId id = host.id();
        String memo = MEMO_UPDATED;
        UiHost uiHost = uiTopology.findHost(id);
        if (uiHost == null) {
            uiHost = addNewHost(host);
            memo = MEMO_ADDED;
        }
        updateHost(uiHost, host);

        postEvent(HOST_ADDED_OR_UPDATED, uiHost, memo);
        // Link event must be sent after the host event
        UiEdgeLink uiEdgeLink = uiTopology.findEdgeLink(uiHost.edgeLinkId());
        postEvent(LINK_ADDED_OR_UPDATED, uiEdgeLink, memo);
    }

    // invoked from UiSharedTopologyModel host listener
    void moveHost(Host host, Host prevHost) {
        UiHost uiHost = uiTopology.findHost(prevHost.id());
        if (uiHost != null) {
            updateHost(uiHost, host);
            postEvent(HOST_MOVED, uiHost, MEMO_MOVED);
        } else {
            log.warn(E_NO_ELEMENT, "host", prevHost.id());
        }
    }

    // package private for unit test access
    UiHost accessHost(HostId id) {
        return uiTopology.findHost(id);
    }

    // invoked from UiSharedTopologyModel host listener
    void removeHost(Host host) {
        HostId id = host.id();
        UiHost uiHost = uiTopology.findHost(id);
        if (uiHost != null) {
            UiEdgeLink edgeLink = uiTopology.findEdgeLink(uiHost.edgeLinkId());
            uiTopology.remove(edgeLink);
            postEvent(LINK_REMOVED, edgeLink, MEMO_REMOVED);
            uiTopology.remove(uiHost);
            postEvent(HOST_REMOVED, uiHost, MEMO_REMOVED);
        } else {
            log.warn(E_NO_ELEMENT, "host", id);
        }
    }

    Set<UiHost> getAllHosts() {
        return uiTopology.allHosts();
    }


    // === SYNTHETIC LINKS

    List<UiSynthLink> getSynthLinks(RegionId regionId) {
        return uiTopology.findSynthLinks(regionId);
    }

    Map<UiLinkId, UiSynthLink> relevantSynthLinks(RegionId regionId) {
        Map<UiLinkId, UiSynthLink> result = new HashMap<>();
        for (UiSynthLink sl : getSynthLinks(regionId)) {
            result.put(sl.original().id(), sl);
        }
        return result;
    }

    /**
     * Refreshes the internal state.
     */
    public void refresh() {
        // fix up internal linkages to ensure they are correct

        // make sure regions reflect layout containment hierarchy
        fixupContainmentHierarchy(uiTopology.nullRegion());
        uiTopology.allRegions().forEach(this::fixupContainmentHierarchy);

        // make sure devices and hosts are in the correct region
        Set<UiDevice> allDevices = uiTopology.allDevices();
        Set<UiHost> allHosts = uiTopology.allHosts();

        services.region().getRegions().forEach(r -> {
            RegionId rid = r.id();
            UiRegion region = uiTopology.findRegion(rid);
            if (region != null) {
                reconcileDevicesAndHostsWithRegion(allDevices, allHosts, rid, region);
            } else {
                log.warn("No UiRegion in topology for ID {}", rid);
            }
        });

        // what is left over, must belong to the null-region
        Set<DeviceId> leftOver = new HashSet<>(allDevices.size());
        allDevices.forEach(d -> leftOver.add(d.id()));
        uiTopology.nullRegion().reconcileDevices(leftOver);

        Set<HostId> leftOverHosts = new HashSet<>(allHosts.size());
        allHosts.forEach(h -> leftOverHosts.add(h.id()));
        uiTopology.nullRegion().reconcileHosts(leftOverHosts);

        // now that we have correct region hierarchy, and devices are in their
        //  respective regions, we can compute synthetic links for each region.
        uiTopology.computeSynthLinks();
    }

    private void reconcileDevicesAndHostsWithRegion(Set<UiDevice> allDevices,
                                                    Set<UiHost> allHosts,
                                                    RegionId rid,
                                                    UiRegion region) {
        Set<DeviceId> deviceIds = services.region().getRegionDevices(rid);
        Set<HostId> hostIds = new HashSet<>();
        region.reconcileDevices(deviceIds);

        deviceIds.forEach(devId -> {
            UiDevice dev = uiTopology.findDevice(devId);
            if (dev != null) {
                dev.setRegionId(rid);
                allDevices.remove(dev);
            } else {
                log.warn("Region device ID {} but no UiDevice in topology",
                         devId);
            }

            Set<Host> hosts = services.host().getConnectedHosts(devId);
            for (Host h : hosts) {
                HostId hid = h.id();
                hostIds.add(hid);
                UiHost host = uiTopology.findHost(hid);

                if (host != null) {
                    host.setRegionId(rid);
                    allHosts.remove(host);
                } else {
                    log.warn("Region host ID {} but no UiHost in topology",
                             hid);
                }
            }
        });

        region.reconcileHosts(hostIds);
    }


    // === CACHE STATISTICS

    /**
     * Returns a detailed (multi-line) string showing the contents of the cache.
     *
     * @return detailed string
     */
    public String dumpString() {
        return uiTopology.dumpString();
    }

    /**
     * Returns the number of members in the cluster.
     *
     * @return number of cluster members
     */
    public int clusterMemberCount() {
        return uiTopology.clusterMemberCount();
    }

    /**
     * Returns the number of regions in the topology.
     *
     * @return number of regions
     */
    public int regionCount() {
        return uiTopology.regionCount();
    }

    /**
     * Returns the number of devices in the topology.
     *
     * @return number of devices
     */
    public int deviceCount() {
        return uiTopology.deviceCount();
    }

    /**
     * Returns the number of device links in the topology.
     *
     * @return number of device links
     */
    public int deviceLinkCount() {
        return uiTopology.deviceLinkCount();
    }

    /**
     * Returns the number of edge links in the topology.
     *
     * @return number of edge links
     */
    public int edgeLinkCount() {
        return uiTopology.edgeLinkCount();
    }

    /**
     * Returns the number of hosts in the topology.
     *
     * @return number of hosts
     */
    public int hostCount() {
        return uiTopology.hostCount();
    }

    /**
     * Returns the number of synthetic links in the topology.
     *
     * @return the number of synthetic links
     */
    public int synthLinkCount() {
        return uiTopology.synthLinkCount();
    }
}
