/*
 * 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.openflow.controller.impl;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.List;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onlab.junit.TestTools;
import org.onosproject.cfg.ComponentConfigService;
import org.onosproject.core.CoreService;
import org.onosproject.openflow.OpenflowSwitchDriverAdapter;
import org.onosproject.openflow.controller.Dpid;
import org.onosproject.openflow.controller.OpenFlowSwitch;
import org.onosproject.openflow.controller.OpenFlowSwitchListener;
import org.onosproject.openflow.controller.RoleState;
import org.osgi.service.component.ComponentContext;
import org.projectfloodlight.openflow.protocol.OFPortStatus;

import com.google.common.collect.ImmutableSet;

import static junit.framework.TestCase.fail;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.EasyMock.replay;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;

/**
 * Unit tests for the open flow controller implementation test.
 */
public class OpenFlowControllerImplTest {

    OpenFlowSwitch switch1;
    Dpid dpid1;
    OpenFlowSwitch switch2;
    Dpid dpid2;
    OpenFlowSwitch switch3;
    Dpid dpid3;

    OpenFlowControllerImpl controller;
    OpenFlowControllerImpl.OpenFlowSwitchAgent agent;
    TestSwitchListener switchListener;

    /**
     * Test harness for a switch listener.
     */
    static class TestSwitchListener implements OpenFlowSwitchListener {
        final List<Dpid> removedDpids = new ArrayList<>();
        final List<Dpid> addedDpids = new ArrayList<>();
        final List<Dpid> changedDpids = new ArrayList<>();

        @Override
        public void switchAdded(Dpid dpid) {
            addedDpids.add(dpid);
        }

        @Override
        public void switchRemoved(Dpid dpid) {
            removedDpids.add(dpid);
        }

        @Override
        public void switchChanged(Dpid dpid) {
            changedDpids.add(dpid);
        }

        @Override
        public void portChanged(Dpid dpid, OFPortStatus status) {
            // Stub
        }

        @Override
        public void receivedRoleReply(Dpid dpid, RoleState requested, RoleState response) {
            // Stub
        }
    }


    /**
     * Sets up switches to use as data, mocks and launches a controller instance.
     */
    @Before
    public void setUp() {
        try {
            switch1 = new OpenflowSwitchDriverAdapter();
            dpid1 = Dpid.dpid(new URI("of:0000000000000111"));
            switch2 = new OpenflowSwitchDriverAdapter();
            dpid2 = Dpid.dpid(new URI("of:0000000000000222"));
            switch3 = new OpenflowSwitchDriverAdapter();
            dpid3 = Dpid.dpid(new URI("of:0000000000000333"));
        } catch (URISyntaxException ex) {
            //  Does not happen
            fail();
        }

        controller = new OpenFlowControllerImpl();
        agent = controller.agent;

        switchListener = new TestSwitchListener();
        controller.addListener(switchListener);

        CoreService mockCoreService =
                EasyMock.createMock(CoreService.class);
        controller.coreService = mockCoreService;

        ComponentConfigService mockConfigService =
                EasyMock.createMock(ComponentConfigService.class);
        expect(mockConfigService.getProperties(anyObject())).andReturn(ImmutableSet.of());
        mockConfigService.registerProperties(controller.getClass());
        expectLastCall();
        mockConfigService.unregisterProperties(controller.getClass(), false);
        expectLastCall();
        expect(mockConfigService.getProperties(anyObject())).andReturn(ImmutableSet.of());
        controller.cfgService = mockConfigService;
        replay(mockConfigService);

        ComponentContext mockContext = EasyMock.createMock(ComponentContext.class);
        Dictionary<String, Object> properties = new Hashtable<>();
        properties.put("openflowPorts",
                       Integer.toString(TestTools.findAvailablePort(0)));
        expect(mockContext.getProperties()).andReturn(properties);
        replay(mockContext);
        controller.activate(mockContext);
    }

    @After
    public void tearDown() {
        controller.removeListener(switchListener);
        controller.deactivate();
    }

    /**
     * Converts an Iterable of some type into a stream of that type.
     *
     * @param items Iterable of objects
     * @param <T> type of the items in the iterable
     * @return stream of objects of type T
     */
    private <T> Stream<T> makeIntoStream(Iterable<T> items) {
        return StreamSupport.stream(
                Spliterators.spliteratorUnknownSize(
                        items.iterator(), Spliterator.ORDERED), false);
    }


    /**
     * Tests adding and removing connected switches.
     */
    @Test
    public void testAddRemoveConnectedSwitch() {

        // test adding connected switches
        boolean addSwitch1 = agent.addConnectedSwitch(dpid1, switch1);
        assertThat(addSwitch1, is(true));
        boolean addSwitch2 = agent.addConnectedSwitch(dpid2, switch2);
        assertThat(addSwitch2, is(true));
        boolean addSwitch3 = agent.addConnectedSwitch(dpid3, switch3);
        assertThat(addSwitch3, is(true));

        // Make sure the listener add callbacks fired
        assertThat(switchListener.addedDpids, hasSize(3));
        assertThat(switchListener.addedDpids, hasItems(dpid1, dpid2, dpid3));

        // Test adding a switch twice - it should fail
        boolean addBadSwitch1 = agent.addConnectedSwitch(dpid1, switch1);
        assertThat(addBadSwitch1, is(false));

        assertThat(controller.connectedSwitches.size(), is(3));

        // test querying the switch list
        Stream<OpenFlowSwitch> fetchedSwitches =
                makeIntoStream(controller.getSwitches());
        long switchCount = fetchedSwitches.count();
        assertThat(switchCount, is(3L));

        // test querying the individual switch
        OpenFlowSwitch queriedSwitch = controller.getSwitch(dpid1);
        assertThat(queriedSwitch, is(switch1));

        // Remove a switch
        agent.removeConnectedSwitch(dpid3);
        Stream<OpenFlowSwitch> fetchedSwitchesAfterRemove =
                makeIntoStream(controller.getSwitches());
        long switchCountAfterRemove = fetchedSwitchesAfterRemove.count();
        assertThat(switchCountAfterRemove, is(2L));

        // Make sure the listener delete callbacks fired
        assertThat(switchListener.removedDpids, hasSize(1));
        assertThat(switchListener.removedDpids, hasItems(dpid3));

        // test querying the removed switch
        OpenFlowSwitch queriedSwitchAfterRemove = controller.getSwitch(dpid3);
        assertThat(queriedSwitchAfterRemove, nullValue());
    }

    /**
     * Tests adding master switches.
     */
    @Test
    public void testMasterSwitch() {
        agent.addConnectedSwitch(dpid1, switch1);
        agent.transitionToMasterSwitch(dpid1);

        Stream<OpenFlowSwitch> fetchedMasterSwitches =
                makeIntoStream(controller.getMasterSwitches());
        assertThat(fetchedMasterSwitches.count(), is(1L));
        Stream<OpenFlowSwitch> fetchedActivatedSwitches =
                makeIntoStream(controller.getEqualSwitches());
        assertThat(fetchedActivatedSwitches.count(), is(0L));
        OpenFlowSwitch fetchedSwitch1 = controller.getMasterSwitch(dpid1);
        assertThat(fetchedSwitch1, is(switch1));

        agent.addConnectedSwitch(dpid2, switch2);
        boolean addSwitch2 = agent.addActivatedMasterSwitch(dpid2, switch2);
        assertThat(addSwitch2, is(true));
        OpenFlowSwitch fetchedSwitch2 = controller.getMasterSwitch(dpid2);
        assertThat(fetchedSwitch2, is(switch2));
    }

    /**
     * Tests adding equal switches.
     */
    @Test
    public void testEqualSwitch() {
        agent.addConnectedSwitch(dpid1, switch1);
        agent.transitionToEqualSwitch(dpid1);

        Stream<OpenFlowSwitch> fetchedEqualSwitches =
                makeIntoStream(controller.getEqualSwitches());
        assertThat(fetchedEqualSwitches.count(), is(1L));
        Stream<OpenFlowSwitch> fetchedActivatedSwitches =
                makeIntoStream(controller.getMasterSwitches());
        assertThat(fetchedActivatedSwitches.count(), is(0L));
        OpenFlowSwitch fetchedSwitch1 = controller.getEqualSwitch(dpid1);
        assertThat(fetchedSwitch1, is(switch1));

        agent.addConnectedSwitch(dpid2, switch2);
        boolean addSwitch2 = agent.addActivatedEqualSwitch(dpid2, switch2);
        assertThat(addSwitch2, is(true));
        OpenFlowSwitch fetchedSwitch2 = controller.getEqualSwitch(dpid2);
        assertThat(fetchedSwitch2, is(switch2));
    }

    /**
     * Tests changing switch role.
     */
    @Test
    public void testRoleSetting() {
        agent.addConnectedSwitch(dpid2, switch2);

        // check that state can be changed for a connected switch
        assertThat(switch2.getRole(), is(RoleState.MASTER));
        controller.setRole(dpid2, RoleState.EQUAL);
        assertThat(switch2.getRole(), is(RoleState.EQUAL));

        // check that changing state on an unconnected switch does not crash
        controller.setRole(dpid3, RoleState.SLAVE);
    }
}
