/*
 * Copyright 2015-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.edgeservice.impl;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onosproject.common.event.impl.TestEventDispatcher;
import org.onosproject.event.Event;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultPort;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Link;
import org.onosproject.net.NetTestTools;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceServiceAdapter;
import org.onosproject.net.edge.EdgePortEvent;
import org.onosproject.net.edge.EdgePortListener;
import org.onosproject.net.link.LinkEvent;
import org.onosproject.net.link.LinkListener;
import org.onosproject.net.link.LinkServiceAdapter;
import org.onosproject.net.packet.OutboundPacket;
import org.onosproject.net.packet.PacketServiceAdapter;
import org.onosproject.net.topology.TopologyEvent;
import org.onosproject.net.topology.TopologyEvent.Type;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.onosproject.net.NetTestTools.injectEventDispatcher;
import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED;
import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_REMOVED;
import static org.onosproject.net.edge.EdgePortEvent.Type.EDGE_PORT_ADDED;
import static org.onosproject.net.edge.EdgePortEvent.Type.EDGE_PORT_REMOVED;
import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED;
import static org.onosproject.net.link.LinkEvent.Type.LINK_REMOVED;

/**
 * Test of the edge port manager. Each device has ports '0' through 'numPorts - 1'
 * as specified by the variable 'numPorts'.
 */
public class EdgeManagerTest {

    private EdgeManager mgr;
    private int totalPorts = 10;
    private boolean alwaysReturnPorts = false;
    private final Set<ConnectPoint> infrastructurePorts = Sets.newConcurrentHashSet();
    private List<EdgePortEvent> events = Lists.newArrayList();
    private final Map<DeviceId, Device> devices = Maps.newConcurrentMap();
    private Set<OutboundPacket> packets = Sets.newConcurrentHashSet();
    private final EdgePortListener testListener = new TestListener(events);
    private TestDeviceManager testDeviceManager;
    private TestLinkService testLinkService;

    @Before
    public void setUp() {
        mgr = new EdgeManager();
        injectEventDispatcher(mgr, new TestEventDispatcher());
        testDeviceManager = new TestDeviceManager(devices);
        mgr.deviceService = testDeviceManager;

        testLinkService = new TestLinkService();
        mgr.linkService = testLinkService;

        mgr.packetService = new TestPacketManager();
        mgr.activate();
        mgr.addListener(testListener);
    }

    @After
    public void tearDown() {
        mgr.removeListener(testListener);
        mgr.deactivate();
    }

    @Test
    public void testBasics() {
        //Setup
        int numDevices = 20;
        int numPorts = 4;
        defaultPopulator(numDevices, numPorts);

        assertEquals("Unexpected number of ports", numDevices * numPorts, infrastructurePorts.size());

        assertFalse("Expected isEdge to return false",
                    mgr.isEdgePoint(NetTestTools.connectPoint(Integer.toString(1), 1)));

        removeInfraPort(NetTestTools.connectPoint(Integer.toString(1), 1));
        postTopologyEvent(new LinkEvent(LINK_REMOVED, NetTestTools.link(Integer.toString(1), 1, "b", 2)));
        assertTrue("Expected isEdge to return true",
                   mgr.isEdgePoint(NetTestTools.connectPoint(Integer.toString(1), 1)));
    }

    @Test
    public void testLinkUpdates() {
        //Setup
        ConnectPoint testPoint, referencePoint;

        //Testing link removal
        devices.put(NetTestTools.did("a"), NetTestTools.device("a"));
        devices.put(NetTestTools.did("b"), NetTestTools.device("b"));
        postTopologyEvent(new LinkEvent(LINK_REMOVED, NetTestTools.link("a", 1, "b", 2)));

        assertEquals("The list contained an unexpected number of events",
                     2, events.size());
        assertTrue("The first element is of the wrong type.",
                   events.get(0).type() == EDGE_PORT_ADDED);

        testPoint = events.get(0).subject();
        referencePoint = NetTestTools.connectPoint("a", 1);
        assertTrue("The port numbers of the first element are incorrect",
                   testPoint.port().toLong() == referencePoint.port().toLong());
        assertTrue("The device id of the first element is incorrect.",
                   testPoint.deviceId().equals(referencePoint.deviceId()));

        testPoint = events.get(1).subject();
        referencePoint = NetTestTools.connectPoint("b", 2);
        assertTrue("The port numbers of the second element are incorrect",
                   testPoint.port().toLong() == referencePoint.port().toLong());
        assertTrue("The device id of the second element is incorrect.",
                   testPoint.deviceId().equals(referencePoint.deviceId()));

        //Rebroadcast event to ensure it results in no additional events
        postTopologyEvent(new LinkEvent(LINK_REMOVED, NetTestTools.link("a", 1, "b", 2)));
        assertTrue("The list contained an unexpected number of events", events.size() == 2);

        //Testing link adding when links to remove exist
        events.clear();
        postTopologyEvent(new LinkEvent(LINK_ADDED, NetTestTools.link("a", 1, "b", 2)));

        assertTrue("The list contained an unexpected number of events", events.size() == 2);
        assertTrue("The first element is of the wrong type.",
                   events.get(0).type() == EDGE_PORT_REMOVED);
        assertTrue("The second element is of the wrong type.",
                   events.get(1).type() == EDGE_PORT_REMOVED);

        testPoint = events.get(0).subject();
        referencePoint = NetTestTools.connectPoint("a", 1);
        assertTrue("The port numbers of the first element are incorrect",
                   testPoint.port().toLong() == referencePoint.port().toLong());
        assertTrue("The device id of the first element is incorrect.",
                   testPoint.deviceId().equals(referencePoint.deviceId()));

        testPoint = events.get(1).subject();
        referencePoint = NetTestTools.connectPoint("b", 2);
        assertTrue("The port numbers of the second element are incorrect",
                   testPoint.port().toLong() == referencePoint.port().toLong());
        assertTrue("The device id of the second element is incorrect.",
                   testPoint.deviceId().equals(referencePoint.deviceId()));

        //Apparent duplicate of previous method tests removal when the elements have already been removed
        events.clear();
        postTopologyEvent(new LinkEvent(LINK_ADDED, NetTestTools.link("a", 1, "b", 2)));
        assertTrue("The list should contain no events, the removed elements don't exist.", events.size() == 0);
    }


    @Test
    public void testDeviceUpdates() {
        //Setup

        Device referenceDevice;
        DeviceEvent event;
        int numDevices = 10;
        int numInfraPorts = 5;
        totalPorts = 10;

        defaultPopulator(numDevices, numInfraPorts);

        events.clear();

        //Test response to device added events

        referenceDevice = NetTestTools.device("11");
        devices.put(referenceDevice.id(), referenceDevice);
        for (int port = 1; port <= numInfraPorts; port++) {
            infrastructurePorts.add(NetTestTools.connectPoint("11", port));
        }
        event = new DeviceEvent(DEVICE_ADDED, referenceDevice,
                                new DefaultPort(referenceDevice, PortNumber.portNumber(1), true));
        postTopologyEvent(event);

        //Check that ports were populated correctly
        assertTrue("Unexpected number of new ports added",
                   mgr.deviceService.getPorts(NetTestTools.did("11")).size() == 10);

        //Check that of the ten ports the half that are infrastructure ports aren't added
        assertEquals("Unexpected number of new edge ports added", (totalPorts - numInfraPorts), events.size());

        for (int index = 0; index < numInfraPorts; index++) {
            assertTrue("Unexpected type of event", events.get(index).type() == EDGE_PORT_ADDED);
        }
        //Names here are irrelevant, the first 5 ports are populated as infrastructure, 6-10 are edge
        for (int index = 0; index < events.size(); index++) {
            assertEquals("Port added had unexpected port number.",
                         events.get(index).subject().port(),
                         NetTestTools.connectPoint("a", index + numInfraPorts + 1).port());
        }
        events.clear();

        //Repost the event to test repeated posts
        postTopologyEvent(event);
        assertEquals("The redundant notification should not have created additional notifications.",
                     0, events.size());
        //Calculate the size of the returned iterable of edge points.
        Iterable<ConnectPoint> pts = mgr.getEdgePoints();
        Iterator pointIterator = pts.iterator();
        int count = 0;
        for (; pointIterator.hasNext(); count++) {
            pointIterator.next();
        }
        assertEquals("Unexpected number of edge points", (numDevices + 1) * numInfraPorts, count);
        //Testing device removal
        events.clear();
        event = (new DeviceEvent(DEVICE_REMOVED, referenceDevice,
                                 new DefaultPort(referenceDevice, PortNumber.portNumber(1), true)));
        postTopologyEvent(event);

        assertEquals("There should be five new events from removal of edge points",
                     totalPorts - numInfraPorts, events.size());
        for (int index = 0; index < events.size(); index++) {
            //Assert that the correct port numbers were removed in the correct order
            assertThat("Port removed had unexpected port number.",
                       events.get(index).subject().port().toLong(),
                       is(greaterThanOrEqualTo((long) numInfraPorts)));
            //Assert that the events are of the correct type
            assertEquals("Unexpected type of event", events.get(index).type(), EDGE_PORT_REMOVED);
        }
        events.clear();
        //Rebroadcast event to check that it triggers no new behavior
        postTopologyEvent(event);
        assertEquals("Rebroadcast of removal event should not produce additional events",
                     0, events.size());

        //Testing device status change, changed from unavailable to available
        events.clear();
        //Make sure that the devicemanager shows the device as available.
        addDevice(referenceDevice, "1", 5);
        devices.put(referenceDevice.id(), referenceDevice);

        event = new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, referenceDevice);
        postTopologyEvent(event);
        //An earlier setup set half of the reference device ports to infrastructure
        assertEquals("An unexpected number of events were generated.", totalPorts - numInfraPorts, events.size());
        for (int i = 0; i < 5; i++) {
            assertEquals("The event was not of the right type", events.get(i).type(), EDGE_PORT_ADDED);
        }
        events.clear();
        postTopologyEvent(event);
        assertEquals("No events should have been generated for a set of existing ports.", 0, events.size());

        //Test removal when state changes when the device becomes unavailable

        //Ensure that the deviceManager shows the device as unavailable
        removeDevice(referenceDevice);
        // This variable copies the behavior of the topology by returning ports
        // attached to an unavailable device this behavior is necessary for the
        // following event to execute properly, if these statements are removed
        // no events will be generated since no ports will be provided in
        // getPorts() to EdgeManager.
        alwaysReturnPorts = true;
        postTopologyEvent(event);
        alwaysReturnPorts = false;
        assertEquals("An unexpected number of events were created.", totalPorts - numInfraPorts, events.size());
        for (int i = 0; i < 5; i++) {
            EdgePortEvent edgeEvent = events.get(i);
            assertEquals("The event is of an unexpected type.",
                         EdgePortEvent.Type.EDGE_PORT_REMOVED, edgeEvent.type());
            assertThat("The event pertains to an unexpected port",
                       edgeEvent.subject().port().toLong(),
                       is(greaterThanOrEqualTo((long) numInfraPorts)));
        }
    }


    @Test
    public void testInternalCache() {
        int numDevices = 10;
        //Number of infrastructure ports per device
        int numPorts = 5;
        //Total ports per device when requesting all devices
        totalPorts = 10;
        defaultPopulator(numDevices, numPorts);
        for (int i = 0; i < numDevices; i++) {
            Device newDevice = NetTestTools.device(Integer.toString(i));
            devices.put(newDevice.id(), newDevice);
            postTopologyEvent(new DeviceEvent(DEVICE_ADDED, newDevice));
        }
        //Check all ports have correct designations
        ConnectPoint testPoint;
        for (int deviceNum = 0; deviceNum < numDevices; deviceNum++) {
            for (int portNum = 1; portNum <= totalPorts; portNum++) {
                testPoint = NetTestTools.connectPoint(Integer.toString(deviceNum), portNum);
                if (portNum <= numPorts) {
                    assertFalse("This should not be an edge point", mgr.isEdgePoint(testPoint));
                } else {
                    assertTrue("This should be an edge point", mgr.isEdgePoint(testPoint));
                }
            }
        }
        int count = 0;
        for (ConnectPoint ignored : mgr.getEdgePoints()) {
            count++;
        }
        assertEquals("There are an unexpeceted number of edge points returned.",
                     (totalPorts - numPorts) * numDevices, count);
        for (int deviceNumber = 0; deviceNumber < numDevices; deviceNumber++) {
            count = 0;
            for (ConnectPoint ignored : mgr.getEdgePoints(NetTestTools.did("1"))) {
                count++;
            }
            assertEquals("This element has an unexpected number of edge points.", (totalPorts - numPorts), count);
        }
    }

    @Test
    public void testEmit() {
        byte[] arr = new byte[10];
        Device referenceDevice;
        DeviceEvent event;
        int numDevices = 10;
        int numInfraPorts = 5;
        totalPorts = 10;
        defaultPopulator(numDevices, numInfraPorts);
        for (byte byteIndex = 0; byteIndex < arr.length; byteIndex++) {
            arr[byteIndex] = byteIndex;
        }
        for (int i = 0; i < numDevices; i++) {
            referenceDevice = NetTestTools.device(Integer.toString(i));
            testDeviceManager.listener.event(new DeviceEvent(DEVICE_ADDED, referenceDevice,
                                                             new DefaultPort(referenceDevice,
                                                                             PortNumber.portNumber(1),
                                                                             true)));
        }

        mgr.emitPacket(ByteBuffer.wrap(arr), Optional.empty());

        assertEquals("There were an unexpected number of emitted packets",
                     (totalPorts - numInfraPorts) * numDevices, packets.size());
        Iterator<OutboundPacket> packetIter = packets.iterator();
        OutboundPacket packet;
        while (packetIter.hasNext()) {
            packet = packetIter.next();
            assertEquals("The packet had an incorrect payload.", arr, packet.data().array());
        }
        //Start testing emission to a specific device
        packets.clear();
        mgr.emitPacket(NetTestTools.did(Integer.toString(1)), ByteBuffer.wrap(arr), Optional.empty());

        assertEquals("Unexpected number of outbound packets were emitted.",
                     totalPorts - numInfraPorts, packets.size());
        packetIter = packets.iterator();
        while (packetIter.hasNext()) {
            packet = packetIter.next();
            assertEquals("The packet had an incorrect payload", arr, packet.data().array());
        }
    }


    /**
     * Creates TopologyEvent triggered by {@code event}.
     *
     * @param event reason of the TopologyEvent
     * @return TopologyEvent
     */
    private TopologyEvent topologyEventOf(Event event) {
        return new TopologyEvent(Type.TOPOLOGY_CHANGED, null, ImmutableList.of(event));
    }


    /**
     * Post Event dispatched from TopologyManager.
     *
     * @param event Event
     */
    private void postTopologyEvent(Event event) {
        if (event instanceof DeviceEvent) {
            testDeviceManager.listener.event((DeviceEvent) event);
        }
        if (event instanceof LinkEvent) {
            testLinkService.listener.event((LinkEvent) event);
        }
        //testTopologyManager.listener.event(topologyEventOf(event));
    }


    /**
     * @param numDevices    the number of devices to populate.
     * @param numInfraPorts the number of ports to be set as infrastructure on each device, numbered base 0, ports 0
     *                      through numInfraPorts - 1
     */
    private void defaultPopulator(int numDevices, int numInfraPorts) {
        for (int device = 0; device < numDevices; device++) {
            String str = Integer.toString(device);
            Device deviceToAdd = NetTestTools.device(str);
            devices.put(deviceToAdd.id(), deviceToAdd);
            testDeviceManager.listener.event(new DeviceEvent(DEVICE_ADDED, deviceToAdd));
            for (int port = 1; port <= numInfraPorts; port++) {
                testLinkService.listener.event(new LinkEvent(LINK_ADDED, NetTestTools.link(str, port, "other", 1)));
                infrastructurePorts.add(NetTestTools.connectPoint(str, port));
            }
        }
    }

    /**
     * Adds the specified device with the specified number of edge ports so long as it is less than the total ports.
     *
     * @param device        The device to be added
     * @param deviceName    The name given to generate the devices DID
     * @param numInfraPorts The number of ports to be added numbered 1 ... numInfraPorts
     */
    private void addDevice(Device device, String deviceName, int numInfraPorts) {
        if (!devices.keySet().contains(device.id())) {
            devices.put(device.id(), device);
            for (int i = 1; i <= numInfraPorts && i <= totalPorts; i++) {
                infrastructurePorts.add(NetTestTools.connectPoint(deviceName, i));
            }
        }
    }

    private void removeDevice(Device device) {
        devices.remove(device.id());
    }

    private void removeInfraPort(ConnectPoint port) {
        infrastructurePorts.remove(port);
    }

    private class TestDeviceManager extends DeviceServiceAdapter {
        private DeviceListener listener;

        private Map<DeviceId, Device> devices;

        public TestDeviceManager(Map<DeviceId, Device> devices) {
            this.devices = devices;
        }

        @Override
        public boolean isAvailable(DeviceId deviceId) {
            for (DeviceId id : devices.keySet()) {
                if (id.equals(deviceId)) {
                    return true;
                }
            }
            return false;
        }

        @Override
        public List<Port> getPorts(DeviceId deviceId) {
            List<Port> ports = new ArrayList<>();
            Device device = devices.get(deviceId);
            if (device == null && !alwaysReturnPorts) {
                return ports;
            }
            for (int portNum = 1; portNum <= totalPorts; portNum++) {
                //String is generated using 'of:' + the passed name, this creates a
                ports.add(new DefaultPort(device, PortNumber.portNumber(portNum), true));
            }
            return ports;
        }

        @Override
        public Iterable<Device> getAvailableDevices() {
            return devices.values();
        }


        @Override
        public void addListener(DeviceListener listener) {
            this.listener = listener;
        }

        @Override
        public void removeListener(DeviceListener listener) {
            this.listener = null;
        }
    }

    private class TestLinkService extends LinkServiceAdapter {

        private LinkListener listener;

        @Override
        public Set<Link> getLinks(ConnectPoint connectPoint) {
            if (infrastructurePorts.contains(connectPoint)) {
                return Collections.singleton(NetTestTools.link("1", 1, "2", 1));
            } else {
                return Collections.emptySet();
            }
        }

        @Override
        public void addListener(LinkListener listener) {
            this.listener = listener;
        }
    }

    private class TestPacketManager extends PacketServiceAdapter {
        @Override
        public void emit(OutboundPacket packet) {
            packets.add(packet);
        }
    }

    private class TestListener implements EdgePortListener {
        private List<EdgePortEvent> events;

        public TestListener(List<EdgePortEvent> events) {
            this.events = events;
        }

        @Override
        public void event(EdgePortEvent event) {
            events.add(event);
        }
    }
}
