/**
 *    Copyright 2011, Big Switch Networks, Inc.
 *    Originally created by David Erickson, Stanford University
 *
 *    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 net.floodlightcontroller.core.util;

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

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import net.floodlightcontroller.core.IOFMessageListener;
import net.floodlightcontroller.test.FloodlightTestCase;

import org.junit.Test;
import org.openflow.protocol.OFType;

public class MessageDispatcherTest extends FloodlightTestCase {

    IOFMessageListener createLMock(String name) {
        IOFMessageListener mock = createNiceMock(IOFMessageListener.class);
        expect(mock.getName()).andReturn(name).anyTimes();
        return mock;
    }

    void addPrereqs(IOFMessageListener mock, String... deps) {
        for (String dep : deps) {
            expect(mock.isCallbackOrderingPrereq(OFType.PACKET_IN, dep)).andReturn(true).anyTimes();
        }
    }

    void testOrdering(ArrayList<IOFMessageListener> inputListeners) {
        ListenerDispatcher<OFType, IOFMessageListener> ld =
                new ListenerDispatcher<OFType, IOFMessageListener>();

        for (IOFMessageListener l : inputListeners) {
            ld.addListener(OFType.PACKET_IN, l);
        }
        for (IOFMessageListener l : inputListeners) {
            verify(l);
        }

        List<IOFMessageListener> result = ld.getOrderedListeners();
        System.out.print("Ordering: ");
        for (IOFMessageListener l : result) {
            System.out.print(l.getName());
            System.out.print(",");
        }
        System.out.print("\n");

        for (int ind_i = 0; ind_i < result.size(); ind_i++) {
            IOFMessageListener i = result.get(ind_i);
            for (int ind_j = ind_i + 1; ind_j < result.size(); ind_j++) {
                IOFMessageListener j = result.get(ind_j);

                boolean orderwrong =
                        (i.isCallbackOrderingPrereq(OFType.PACKET_IN, j.getName()) ||
                                j.isCallbackOrderingPostreq(OFType.PACKET_IN, i.getName()));
                assertFalse("Invalid order: " +
                        ind_i + " (" + i.getName() + ") " +
                        ind_j + " (" + j.getName() + ") ", orderwrong);
            }
        }
    }

    void randomTestOrdering(ArrayList<IOFMessageListener> mocks) {
        Random rand = new Random(0);
        ArrayList<IOFMessageListener> random =
                new ArrayList<IOFMessageListener>();
        random.addAll(mocks);
        for (int i = 0; i < 20; i++) {
            for (int j = 0; j < random.size(); j++) {
                int ind = rand.nextInt(mocks.size() - 1);
                IOFMessageListener tmp = random.get(j);
                random.set(j, random.get(ind));
                random.set(ind, tmp);
            }
            testOrdering(random);
        }
    }

    @Test
    public void testCallbackOrderingSimple() throws Exception {
        ArrayList<IOFMessageListener> mocks =
                new ArrayList<IOFMessageListener>();
        for (int i = 0; i < 10; i++) {
            mocks.add(createLMock("" + i));
        }
        for (int i = 1; i < 10; i++) {
            addPrereqs(mocks.get(i), "" + (i - 1));
        }
        for (IOFMessageListener l : mocks) {
            replay(l);
        }
        randomTestOrdering(mocks);
    }

    @Test
    public void testCallbackOrderingPartial() throws Exception {
        ArrayList<IOFMessageListener> mocks =
                new ArrayList<IOFMessageListener>();
        for (int i = 0; i < 10; i++) {
            mocks.add(createLMock("" + i));
        }
        for (int i = 1; i < 5; i++) {
            addPrereqs(mocks.get(i), "" + (i - 1));
        }
        for (int i = 6; i < 10; i++) {
            addPrereqs(mocks.get(i), "" + (i - 1));
        }
        for (IOFMessageListener l : mocks) {
            replay(l);
        }
        randomTestOrdering(mocks);
    }


    @Test
    public void testCallbackOrderingPartial2() throws Exception {
        ArrayList<IOFMessageListener> mocks =
                new ArrayList<IOFMessageListener>();
        for (int i = 0; i < 10; i++) {
            mocks.add(createLMock("" + i));
        }
        for (int i = 2; i < 5; i++) {
            addPrereqs(mocks.get(i), "" + (i - 1));
        }
        for (int i = 6; i < 9; i++) {
            addPrereqs(mocks.get(i), "" + (i - 1));
        }
        for (IOFMessageListener l : mocks) {
            replay(l);
        }
        randomTestOrdering(mocks);
    }
}

@@ -931,16 +931,73 @@
 erify;%0A%0A
+import java.io.PrintWriter;%0Aimport java.io.StringWriter;%0A
 import j
@@ -1239,16 +1239,73 @@
 .OFType;
+%0Aimport org.slf4j.Logger;%0Aimport org.slf4j.LoggerFactory;
 %0A%0Apublic
@@ -1361,16 +1361,108 @@
 stCase %7B
+%0A    private static final Logger log = LoggerFactory.getLogger(MessageDispatcherTest.class);
 %0A%0A    IO
@@ -2354,38 +2354,125 @@
 ers();%0A        S
-ystem.
+tringWriter sw = new StringWriter();%0A        PrintWriter out = new PrintWriter(sw);%0A%0A        
 out.print(%22Order
@@ -2530,39 +2530,32 @@
 ) %7B%0A            
-System.
 out.print(l.getN
@@ -2566,39 +2566,32 @@
 ));%0A            
-System.
 out.print(%22,%22);%0A
@@ -2612,15 +2612,8 @@
     
-System.
 out.
@@ -2624,16 +2624,50 @@
 t(%22%5Cn%22);
+%0A        log.debug(sw.toString());
 %0A%0A      

Make MessageDispatcherTest quiet.