/*
 * 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.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.packet.OutboundPacket;
import org.onosproject.net.packet.PacketServiceAdapter;
import org.onosproject.net.topology.Topology;
import org.onosproject.net.topology.TopologyEvent;
import org.onosproject.net.topology.TopologyEvent.Type;
import org.onosproject.net.topology.TopologyListener;
import org.onosproject.net.topology.TopologyServiceAdapter;

import java.nio.ByteBuffer;
import java.util.ArrayList;
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.*;
import static org.junit.Assert.*;
import static org.onosproject.net.NetTestTools.injectEventDispatcher;
import static org.onosproject.net.device.DeviceEvent.Type.*;
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 TestTopologyManager testTopologyManager;

    @Before
    public void setUp() {
        mgr = new EdgeManager();
        injectEventDispatcher(mgr, new TestEventDispatcher());
        testTopologyManager = new TestTopologyManager(infrastructurePorts);
        mgr.topologyService = testTopologyManager;
        testDeviceManager = new TestDeviceManager(devices);
        mgr.deviceService = testDeviceManager;
        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("no ports expected", mgr.getEdgePoints().iterator().hasNext());

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

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

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

        //Testing link removal
        postTopologyEvent(new LinkEvent(LINK_REMOVED, 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_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);

        //Test response to device added events
        referenceDevice = NetTestTools.device("1");
        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("1")).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", totalPorts - 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));
            postTopologyEvent(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) {
        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);
            for (int port = 1; port <= numInfraPorts; port++) {
                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 TestTopologyManager extends TopologyServiceAdapter {
        private TopologyListener listener;
        private Set<ConnectPoint> infrastructurePorts;

        public TestTopologyManager(Set<ConnectPoint> infrastructurePorts) {
            this.infrastructurePorts = infrastructurePorts;
        }

        @Override
        public boolean isInfrastructure(Topology topology, ConnectPoint connectPoint) {
            return infrastructurePorts.contains(connectPoint);
        }

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

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

    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 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);
        }
    }
}
