/*
 * 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.opencord.cordmcast;

import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;

import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onlab.junit.TestUtils;
import org.onlab.packet.IpAddress;
import org.onlab.packet.VlanId;
import org.onosproject.cfg.ComponentConfigAdapter;
import org.onosproject.cfg.ComponentConfigService;
import org.onosproject.mcast.api.McastEvent;
import org.onosproject.mcast.api.McastRoute;
import org.onosproject.mcast.api.McastRouteUpdate;
import org.onosproject.mcast.api.MulticastRouteService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.HostId;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.IPCriterion;
import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
import org.onosproject.net.flowobjective.Objective;
import org.onosproject.store.service.StorageServiceAdapter;
import org.onosproject.store.service.TestConsistentMap;
import org.osgi.service.component.ComponentContext;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;

import java.util.Dictionary;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Set;
import java.util.Map;
import java.util.Arrays;
import java.util.Collection;

import static org.junit.Assert.*;
import static org.onlab.junit.TestTools.assertAfter;

public class McastTest extends McastTestBase {

  private CordMcast cordMcast;
  private CordMcastStatisticsManager cordMcastStatisticsManager;

  private MockCordMcastStatisticsEventListener mockListener = new MockCordMcastStatisticsEventListener();

  private static final int WAIT_TIMEOUT = 1000;
  private static final int WAIT = 250;
  McastRouteUpdate previousSubject, currentSubject;

  @Before
  public void setUp() {
      cordMcast = new CordMcast();
      cordMcastStatisticsManager = new CordMcastStatisticsManager();

      cordMcast.coreService = new MockCoreService();
      cordMcast.networkConfig = new TestNetworkConfigRegistry();
      cordMcast.flowObjectiveService = new MockFlowObjectiveService();
      cordMcast.mastershipService = new TestMastershipService();
      cordMcast.deviceService = new MockDeviceService();
      cordMcast.componentConfigService = new ComponentConfigAdapter();
      cordMcastStatisticsManager.componentConfigService = new ComponentConfigAdapter();
      cordMcastStatisticsManager.addListener(mockListener);
      cordMcast.sadisService = new MockSadisService();
      cordMcast.cordMcastStatisticsService = cordMcastStatisticsManager;

      cordMcast.storageService = EasyMock.createMock(StorageServiceAdapter.class);
      expect(cordMcast.storageService.consistentMapBuilder()).andReturn(new TestConsistentMap.Builder<>());
      replay(cordMcast.storageService);

      Dictionary<String, Object> cfgDict = new Hashtable<String, Object>();
      cfgDict.put("vlanEnabled", false);
      cfgDict.put("eventGenerationPeriodInSeconds", EVENT_GENERATION_PERIOD);

      cordMcast.componentConfigService = EasyMock.createNiceMock(ComponentConfigService.class);
      replay(cordMcast.componentConfigService);

      Set<McastRoute> route1Set = new HashSet<McastRoute>();
      route1Set.add(route1);

      cordMcast.mcastService = EasyMock.createNiceMock(MulticastRouteService.class);
      expect(cordMcast.mcastService.getRoutes()).andReturn(Sets.newHashSet());
      replay(cordMcast.mcastService);

      cordMcastStatisticsManager.mcastService = EasyMock.createNiceMock(MulticastRouteService.class);
      expect(cordMcastStatisticsManager.mcastService.getRoutes()).andReturn(route1Set).times(2);
      replay(cordMcastStatisticsManager.mcastService);

      TestUtils.setField(cordMcastStatisticsManager, "eventDispatcher", new TestEventDispatcher());

      ComponentContext componentContext = EasyMock.createMock(ComponentContext.class);
      expect(componentContext.getProperties()).andReturn(cfgDict).times(2);
      replay(componentContext);
      cordMcast.cordMcastStatisticsService = cordMcastStatisticsManager;
      cordMcastStatisticsManager.activate(componentContext);

      cordMcast.activate(componentContext);
   }

    @After
    public void tearDown() {
      cordMcast.deactivate();
      forwardMap.clear();
      nextMap.clear();
    }

    @Test
    public void testAddingSinkEvent() throws InterruptedException {

      Set<ConnectPoint> sinks2Cp = new HashSet<ConnectPoint>(Arrays.asList(CONNECT_POINT_B));
      Map<HostId, Set<ConnectPoint>> sinks2 = ImmutableMap.of(HOST_ID_NONE, sinks2Cp);

      //Adding the details to create different routes
      previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
      currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks2);
      // Creating new mcast event for adding sink
      McastEvent event = new McastEvent(McastEvent.Type.SINKS_ADDED, previousSubject, currentSubject);
      cordMcast.listener.event(event);
      synchronized (forwardMap) {
        forwardMap.wait(WAIT_TIMEOUT);
      }

      // ForwardMap will contain the operation "Add" in the flowObjective. None -> CP_B
      assertNotNull(forwardMap.get(DEVICE_ID_OF_A));
      assertTrue(forwardMap.get(DEVICE_ID_OF_A).op() == Objective.Operation.ADD);

      // Output port number will be PORT_B i.e. 16
      Collection<TrafficTreatment> traffictreatMentCollection =
           nextMap.get(DEVICE_ID_OF_A).next();
      assertTrue(1 == traffictreatMentCollection.size());
      OutputInstruction output = null;
      for (TrafficTreatment trafficTreatment : traffictreatMentCollection) {
         output = outputPort(trafficTreatment);
      }
      assertNotNull(output);
      assertTrue(PORT_B == output.port());
      // Checking the group ip address
      TrafficSelector trafficSelector = forwardMap.get(DEVICE_ID_OF_A).selector();
      IPCriterion ipCriterion = ipAddress(trafficSelector);
      assertNotNull(ipCriterion);
      assertTrue(MULTICAST_IP.equals(ipCriterion.ip().address()));

    }

    @Test
    public void testAddToExistingSinkEvent() throws InterruptedException {

       // Adding first sink (none --> CP_B)
       testAddingSinkEvent();

       Set<ConnectPoint> sinksCp = new HashSet<ConnectPoint>(Arrays.asList(CONNECT_POINT_B));
       Map<HostId, Set<ConnectPoint>> sinks = ImmutableMap.of(HOST_ID_NONE, sinksCp);
       previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
       sinksCp = new HashSet<ConnectPoint>(Arrays.asList(CONNECT_POINT_B, CONNECT_POINT_C));
       sinks = ImmutableMap.of(HOST_ID_NONE, sinksCp);
       currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
       // Again listening the mcast event with different output port ( none --> CP_B, CP_C)
       McastEvent event = new McastEvent(McastEvent.Type.SINKS_ADDED, previousSubject, currentSubject);
       cordMcast.listener.event(event);

       // NextMap will contain the operation "ADD_TO_EXISTING" in the DefaultNextObjective.
       assertAfter(WAIT_TIMEOUT, WAIT_TIMEOUT * 2, () ->
       assertTrue(nextMap.get(DEVICE_ID_OF_A).op() == Objective.Operation.ADD_TO_EXISTING));
       // Output port number will be changed to 24 i.e. PORT_C
       Collection<TrafficTreatment> traffictreatMentCollection = nextMap.get(DEVICE_ID_OF_A).next();
       assertTrue(1 == traffictreatMentCollection.size());
       OutputInstruction output = null;
       for (TrafficTreatment trafficTreatment : traffictreatMentCollection) {
          output = outputPort(trafficTreatment);
       }
       assertNotNull(output);
       assertTrue(PORT_C == output.port());
    }

    @Test
    public void testRemoveSinkEvent() throws InterruptedException {

       testAddToExistingSinkEvent();
       // Handling the mcast event for removing sink.
       Set<ConnectPoint> sinksCp = new HashSet<ConnectPoint>(Arrays.asList(CONNECT_POINT_B, CONNECT_POINT_C));
       Map<HostId, Set<ConnectPoint>> sinks = ImmutableMap.of(HOST_ID_NONE, sinksCp);
       previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
       sinksCp = new HashSet<ConnectPoint>(Arrays.asList(CONNECT_POINT_C));
       sinks = ImmutableMap.of(HOST_ID_NONE, sinksCp);
       currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
       McastEvent event = new McastEvent(McastEvent.Type.SINKS_REMOVED, previousSubject, currentSubject);
       cordMcast.listener.event(event);
       // Operation will be REMOVE_FROM_EXISTING and nextMap will be updated. ( None --> CP_C)
       assertAfter(WAIT_TIMEOUT, WAIT_TIMEOUT * 2, () ->
       assertTrue(nextMap.get(DEVICE_ID_OF_A).op() == Objective.Operation.REMOVE_FROM_EXISTING));

       // Output port number will be PORT_B i.e. 16
       // Port_B is removed from the group.
       Collection<TrafficTreatment> traffictreatMentCollection =
            nextMap.get(DEVICE_ID_OF_A).next();
       assertTrue(1 == traffictreatMentCollection.size());
       OutputInstruction output = null;
       for (TrafficTreatment trafficTreatment : traffictreatMentCollection) {
          output = outputPort(trafficTreatment);
       }
       assertNotNull(output);
       assertTrue(PORT_B == output.port());

    }

    @Test
    public void testRemoveLastSinkEvent() throws InterruptedException {

       testRemoveSinkEvent();
       // Handling the mcast event for removing sink.
       Set<ConnectPoint> sinksCp = new HashSet<ConnectPoint>(Arrays.asList(CONNECT_POINT_C));
       Map<HostId, Set<ConnectPoint>> sinks = ImmutableMap.of(HOST_ID_NONE, sinksCp);
       previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
       sinksCp = new HashSet<ConnectPoint>(Arrays.asList());
       sinks = ImmutableMap.of(HOST_ID_NONE, sinksCp);
       currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
       McastEvent event = new McastEvent(McastEvent.Type.SINKS_REMOVED, previousSubject, currentSubject);
       cordMcast.listener.event(event);

       // Operation will be REMOVE_FROM_EXISTING and nextMap will be updated.  None --> { }
       assertAfter(WAIT_TIMEOUT, WAIT_TIMEOUT * 2, () ->
       assertTrue(nextMap.get(DEVICE_ID_OF_A).op() == Objective.Operation.REMOVE_FROM_EXISTING));

       // Output port number will be changed to 24 i.e. PORT_C
       Collection<TrafficTreatment> traffictreatMentCollection = nextMap.get(DEVICE_ID_OF_A).next();
       assertTrue(1 == traffictreatMentCollection.size());
       OutputInstruction output = null;
       for (TrafficTreatment trafficTreatment : traffictreatMentCollection) {
          output = outputPort(trafficTreatment);
       }
       assertNotNull(output);
       assertTrue(PORT_C == output.port());
  }

  @Test
  public void testUnkownOltDevice() throws InterruptedException {

       // Configuration of mcast event for unknown olt device
       final DeviceId deviceIdOfB = DeviceId.deviceId("of:1");

       ConnectPoint connectPointA = new ConnectPoint(deviceIdOfB, PORT_A);
       ConnectPoint connectPointB = new ConnectPoint(deviceIdOfB, PORT_B);
       Set<ConnectPoint> sourcesCp = new HashSet<ConnectPoint>(Arrays.asList(connectPointA));
       Set<ConnectPoint> sinksCp = new HashSet<ConnectPoint>(Arrays.asList());
       Set<ConnectPoint> sinks2Cp = new HashSet<ConnectPoint>(Arrays.asList(connectPointB));
       Map<HostId, Set<ConnectPoint>> sources = ImmutableMap.of(HOST_ID_NONE, sourcesCp);

       Map<HostId, Set<ConnectPoint>> sinks = ImmutableMap.of(HOST_ID_NONE, sinksCp);
       Map<HostId, Set<ConnectPoint>> sinks2 = ImmutableMap.of(HOST_ID_NONE, sinks2Cp);
       //Adding the details to create different routes
       McastRouteUpdate previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
       McastRouteUpdate currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks2);
       // Creating new mcast event for adding sink
       McastEvent event = new McastEvent(McastEvent.Type.SINKS_ADDED, previousSubject, currentSubject);
       cordMcast.listener.event(event);
       // OltInfo flag is set to true when olt device is unkown
       assertAfter(WAIT, WAIT * 2, () -> assertTrue(knownOltFlag));
       assertTrue(0 == forwardMap.size());
       assertTrue(0 == nextMap.size());

  }

  @Test
  public void testRouteAddedEvent() throws InterruptedException {

      //Adding the details to create different routes
      previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, emptySource, sinks);
      currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, emptySource, sinks);
      // Creating new mcast event for route adding
      McastEvent event = new McastEvent(McastEvent.Type.ROUTE_ADDED, previousSubject, currentSubject);
      cordMcast.listener.event(event);
      // There will be no forwarding objective
      assertAfter(WAIT, WAIT * 2, () -> assertTrue(0 == forwardMap.size()));
      assertTrue(0 == nextMap.size());

   }


  @Test
  public void testRouteRemovedEvent() throws InterruptedException {

      testRouteAddedEvent();

      //Adding the details to create different routes
      previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, emptySource, sinks);
      currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, emptySource, sinks);
      // Creating new mcast event for route removing
      McastEvent event = new McastEvent(McastEvent.Type.ROUTE_REMOVED, previousSubject, currentSubject);
      cordMcast.listener.event(event);
      // There will be no forwarding objective
      assertAfter(WAIT, WAIT * 2, () -> assertTrue(0 == forwardMap.size()));
      assertTrue(0 == nextMap.size());

   }

  @Test
  public void testSourceAddedEvent() throws InterruptedException {

      // Adding route before adding source.
      testRouteAddedEvent();

      //Adding the details to create different routes
      previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, emptySource, sinks);
      currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
      // Creating new mcast event for source adding
      McastEvent event = new McastEvent(McastEvent.Type.SOURCES_ADDED, previousSubject, currentSubject);
      cordMcast.listener.event(event);
      // There will be no forwarding objective
      assertAfter(WAIT, WAIT * 2, () -> assertTrue(0 == forwardMap.size()));
      assertTrue(0 == nextMap.size());

   }

  @Test
  public void testSourcesRemovedEvent() throws InterruptedException {

      testSourceAddedEvent();

      //Adding the details to create different routes
      previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
      currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, emptySource, sinks);
      // Creating new mcast event for removing source
      // Warning message of unknown event will be displayed.
      McastEvent event = new McastEvent(McastEvent.Type.SOURCES_REMOVED, previousSubject, currentSubject);
      cordMcast.listener.event(event);
      assertAfter(WAIT, WAIT * 2, () -> assertTrue(0 == forwardMap.size()));
      assertTrue(0 == nextMap.size());
   }

    @Test
    public void mcastTestEventGeneration() throws InterruptedException {
      //fetching route details used to push CordMcastStatisticsEvent.
      IpAddress testGroup = route1.group();
      String testSource = route1.source().isEmpty() ? "*" : route1.source().get().toString();
      VlanId testVlan = cordMcast.assignedVlan();

      // Thread is scheduled without any delay
      assertAfter(WAIT, WAIT * 2, () ->
              assertEquals(1, mockListener.mcastEventList.size()));

      for (CordMcastStatisticsEvent event: mockListener.mcastEventList) {
           assertEquals(event.type(), CordMcastStatisticsEvent.Type.STATUS_UPDATE);
      }

      CordMcastStatistics cordMcastStatistics = mockListener.mcastEventList.get(0).subject().get(0);
      assertEquals(VlanId.NONE, cordMcastStatistics.getVlanId());
      assertEquals(testVlan, cordMcastStatistics.getVlanId());
      assertEquals(testSource, cordMcastStatistics.getSourceAddress());
      assertEquals(testGroup, cordMcastStatistics.getGroupAddress());

      // Test for vlanEnabled
      Dictionary<String, Object> cfgDict = new Hashtable<>();
      cfgDict.put("vlanEnabled", true);

      ComponentContext componentContext = EasyMock.createMock(ComponentContext.class);
      expect(componentContext.getProperties()).andReturn(cfgDict);
      replay(componentContext);
      cordMcast.modified(componentContext);
      testVlan = cordMcast.assignedVlan();

      assertAfter(EVENT_GENERATION_PERIOD, EVENT_GENERATION_PERIOD * 1000, () ->
              assertEquals(2, mockListener.mcastEventList.size()));

      for (CordMcastStatisticsEvent event: mockListener.mcastEventList) {
          assertEquals(event.type(), CordMcastStatisticsEvent.Type.STATUS_UPDATE);
      }

      cordMcastStatistics = mockListener.mcastEventList.get(1).subject().get(0);
      assertNotEquals(VlanId.NONE, cordMcastStatistics.getVlanId());
      assertEquals(testVlan, cordMcastStatistics.getVlanId());
      assertEquals(testSource, cordMcastStatistics.getSourceAddress());
      assertEquals(testGroup, cordMcastStatistics.getGroupAddress());
    }
}
