/*
 * 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.flow.TrafficTreatment;
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.<TrafficTreatment>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.<TrafficTreatment>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);
        }
    }
}