/*
 * Copyright 2014-2015 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.intent.impl;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.onosproject.TestApplicationId;
import org.onosproject.cfg.ComponentConfigAdapter;
import org.onosproject.common.event.impl.TestEventDispatcher;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.impl.TestCoreManager;
import org.onosproject.net.NetworkResource;
import org.onosproject.net.intent.FlowRuleIntent;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentCompiler;
import org.onosproject.net.intent.IntentData;
import org.onosproject.net.intent.IntentEvent;
import org.onosproject.net.intent.IntentEvent.Type;
import org.onosproject.net.intent.IntentExtensionService;
import org.onosproject.net.intent.IntentId;
import org.onosproject.net.intent.IntentListener;
import org.onosproject.net.intent.IntentService;
import org.onosproject.net.intent.IntentState;
import org.onosproject.net.intent.Key;
import org.onosproject.net.resource.link.LinkResourceAllocations;
import org.onosproject.store.trivial.SimpleIntentStore;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.*;
import static org.onlab.junit.TestTools.assertAfter;
import static org.onlab.util.Tools.delay;
import static org.onosproject.net.NetTestTools.injectEventDispatcher;
import static org.onosproject.net.intent.IntentState.*;
import static org.onosproject.net.intent.IntentTestsMocks.MockFlowRule;
import static org.onosproject.net.intent.IntentTestsMocks.MockIntent;

/**
 * Test intent manager and transitions.
 *
 * TODO implement the following tests:
 *  - {submit, withdraw, update, replace} intent
 *  - {submit, update, recompiling} intent with failed compilation
 *  - failed reservation
 *  - push timeout recovery
 *  - failed items recovery
 *
 *  in general, verify intents store, flow store, and work queue
 */

public class IntentManagerTest {

    private static final int SUBMIT_TIMEOUT_MS = 1000;
    private static final ApplicationId APPID = new TestApplicationId("manager-test");

    private IntentManager manager;
    private MockFlowRuleService flowRuleService;

    protected IntentService service;
    protected IntentExtensionService extensionService;
    protected TestListener listener = new TestListener();
    protected TestIntentCompiler compiler = new TestIntentCompiler();

    private static class TestListener implements IntentListener {
        final Multimap<IntentEvent.Type, IntentEvent> events = HashMultimap.create();
        Map<IntentEvent.Type, CountDownLatch> latchMap = Maps.newHashMap();

        @Override
        public void event(IntentEvent event) {
            events.put(event.type(), event);
            if (latchMap.containsKey(event.type())) {
                latchMap.get(event.type()).countDown();
            }
        }

        public int getCounts(IntentEvent.Type type) {
            return events.get(type).size();
        }

        public void setLatch(int count, IntentEvent.Type type) {
            latchMap.put(type, new CountDownLatch(count));
        }

        public void await(IntentEvent.Type type) {
            try {
                assertTrue("Timed out waiting for: " + type,
                        latchMap.get(type).await(5, TimeUnit.SECONDS));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private static class TestIntentTracker implements ObjectiveTrackerService {
        private TopologyChangeDelegate delegate;
        @Override
        public void setDelegate(TopologyChangeDelegate delegate) {
            this.delegate = delegate;
        }

        @Override
        public void unsetDelegate(TopologyChangeDelegate delegate) {
            if (delegate.equals(this.delegate)) {
                this.delegate = null;
            }
        }

        @Override
        public void addTrackedResources(Key key, Collection<NetworkResource> resources) {
            //TODO
        }

        @Override
        public void removeTrackedResources(Key key, Collection<NetworkResource> resources) {
            //TODO
        }

        @Override
        public void trackIntent(IntentData intentData) {
            //TODO
        }
    }

    private static class MockInstallableIntent extends FlowRuleIntent {

        public MockInstallableIntent() {
            super(APPID, Collections.singletonList(new MockFlowRule(100)));
        }
    }

    private static class TestIntentCompiler implements IntentCompiler<MockIntent> {
        @Override
        public List<Intent> compile(MockIntent intent, List<Intent> installable,
                                    Set<LinkResourceAllocations> resources) {
            return Lists.newArrayList(new MockInstallableIntent());
        }
    }

    private static class TestIntentCompilerMultipleFlows implements IntentCompiler<MockIntent> {
        @Override
        public List<Intent> compile(MockIntent intent, List<Intent> installable,
                                    Set<LinkResourceAllocations> resources) {

            return IntStream.rangeClosed(1, 5)
                            .mapToObj(mock -> (new MockInstallableIntent()))
                            .collect(Collectors.toList());
        }
    }


    private static class TestIntentCompilerError implements IntentCompiler<MockIntent> {
        @Override
        public List<Intent> compile(MockIntent intent, List<Intent> installable,
                                    Set<LinkResourceAllocations> resources) {
            throw new IntentCompilationException("Compilation always fails");
        }
    }

    /**
     * Hamcrest matcher to check that a collection of Intents contains an
     * Intent with the specified Intent Id.
     */
    public static class EntryForIntentMatcher extends TypeSafeMatcher<Collection<Intent>> {
        private final IntentId id;

        public EntryForIntentMatcher(IntentId idValue) {
            id = idValue;
        }

        @Override
        public boolean matchesSafely(Collection<Intent> intents) {
            for (Intent intent : intents) {
                if (intent.id().equals(id)) {
                    return true;
                }
            }
            return false;
        }

        @Override
        public void describeTo(Description description) {
            description.appendText("an intent with id \" ").
                    appendText(id.toString()).
                    appendText("\"");
        }
    }

    private static EntryForIntentMatcher hasIntentWithId(IntentId id) {
        return new EntryForIntentMatcher(id);
    }

    @Before
    public void setUp() {
        manager = new IntentManager();
        flowRuleService = new MockFlowRuleService();
        manager.store = new SimpleIntentStore();
        injectEventDispatcher(manager, new TestEventDispatcher());
        manager.trackerService = new TestIntentTracker();
        manager.flowRuleService = flowRuleService;
        manager.coreService = new TestCoreManager();
        service = manager;
        extensionService = manager;

        manager.activate();
        service.addListener(listener);
        extensionService.registerCompiler(MockIntent.class, compiler);

        assertTrue("store should be empty",
                   Sets.newHashSet(service.getIntents()).isEmpty());
        assertEquals(0L, flowRuleService.getFlowRuleCount());
    }

    public void verifyState() {
        // verify that all intents are parked and the batch operation is unblocked
        Set<IntentState> parked = Sets.newHashSet(INSTALLED, WITHDRAWN, FAILED, CORRUPT);
        for (Intent i : service.getIntents()) {
            IntentState state = service.getIntentState(i.key());
            assertTrue("Intent " + i.id() + " is in invalid state " + state,
                       parked.contains(state));
        }
        //the batch has not yet been removed when we receive the last event
        // FIXME: this doesn't guarantee to avoid the race

        //FIXME
//        for (int tries = 0; tries < 10; tries++) {
//            if (manager.batchService.getPendingOperations().isEmpty()) {
//                break;
//            }
//            delay(10);
//        }
//        assertTrue("There are still pending batch operations.",
//                   manager.batchService.getPendingOperations().isEmpty());

    }

    @After
    public void tearDown() {
        extensionService.unregisterCompiler(MockIntent.class);
        service.removeListener(listener);
        manager.deactivate();
        // TODO null the other refs?
    }

    @Test
    public void submitIntent() {
        flowRuleService.setFuture(true);

        listener.setLatch(1, Type.INSTALL_REQ);
        listener.setLatch(1, Type.INSTALLED);
        Intent intent = new MockIntent(MockIntent.nextId());
        service.submit(intent);
        listener.await(Type.INSTALL_REQ);
        listener.await(Type.INSTALLED);
        assertEquals(1L, service.getIntentCount());
        assertEquals(1L, flowRuleService.getFlowRuleCount());
        verifyState();
    }

    @Test
    public void withdrawIntent() {
        flowRuleService.setFuture(true);

        listener.setLatch(1, Type.INSTALLED);
        Intent intent = new MockIntent(MockIntent.nextId());
        service.submit(intent);
        listener.await(Type.INSTALLED);
        assertEquals(1L, service.getIntentCount());
        assertEquals(1L, flowRuleService.getFlowRuleCount());

        listener.setLatch(1, Type.WITHDRAWN);
        service.withdraw(intent);
        listener.await(Type.WITHDRAWN);
        assertEquals(0L, flowRuleService.getFlowRuleCount());
        verifyState();
    }

    @Test
    @Ignore("This is disabled because we are seeing intermittent failures on Jenkins")
    public void stressSubmitWithdrawUnique() {
        flowRuleService.setFuture(true);

        int count = 500;
        Intent[] intents = new Intent[count];

        listener.setLatch(count, Type.WITHDRAWN);

        for (int i = 0; i < count; i++) {
            intents[i] = new MockIntent(MockIntent.nextId());
            service.submit(intents[i]);
        }

        for (int i = 0; i < count; i++) {
            service.withdraw(intents[i]);
        }

        listener.await(Type.WITHDRAWN);
        assertEquals(0L, flowRuleService.getFlowRuleCount());
        verifyState();
    }

    @Test
    public void stressSubmitWithdrawSame() {
        flowRuleService.setFuture(true);

        int count = 50;

        Intent intent = new MockIntent(MockIntent.nextId());
        for (int i = 0; i < count; i++) {
            service.submit(intent);
            service.withdraw(intent);
        }

        assertAfter(SUBMIT_TIMEOUT_MS, () -> {
            assertEquals(1L, service.getIntentCount());
            assertEquals(0L, flowRuleService.getFlowRuleCount());
        });
        verifyState();
    }


    /**
     * Tests for proper behavior of installation of an intent that triggers
     * a compilation error.
     */
    @Test
    public void errorIntentCompile() {
        final TestIntentCompilerError errorCompiler = new TestIntentCompilerError();
        extensionService.registerCompiler(MockIntent.class, errorCompiler);
        MockIntent intent = new MockIntent(MockIntent.nextId());
        listener.setLatch(1, Type.INSTALL_REQ);
        listener.setLatch(1, Type.FAILED);
        service.submit(intent);
        listener.await(Type.INSTALL_REQ);
        listener.await(Type.FAILED);
        verifyState();
    }

    /**
     * Tests handling a future that contains an error as a result of
     * installing an intent.
     */
    @Ignore("skipping until we fix update ordering problem")
    @Test
    public void errorIntentInstallFromFlows() {
        final Long id = MockIntent.nextId();
        flowRuleService.setFuture(false);
        MockIntent intent = new MockIntent(id);
        listener.setLatch(1, Type.FAILED);
        listener.setLatch(1, Type.INSTALL_REQ);
        service.submit(intent);
        listener.await(Type.INSTALL_REQ);
        listener.await(Type.FAILED);
        // FIXME the intent will be moved into INSTALLED immediately which overrides FAILED
        // ... the updates come out of order
        verifyState();
    }

    /**
     * Tests handling a future that contains an unresolvable error as a result of
     * installing an intent.
     */
    @Test
    public void errorIntentInstallNeverTrue() {
        final Long id = MockIntent.nextId();
        flowRuleService.setFuture(false);
        MockIntent intent = new MockIntent(id);
        listener.setLatch(1, Type.CORRUPT);
        listener.setLatch(1, Type.INSTALL_REQ);
        service.submit(intent);
        listener.await(Type.INSTALL_REQ);
        // The delay here forces the retry loop in the intent manager to time out
        delay(100);
        flowRuleService.setFuture(false);
        service.withdraw(intent);
        listener.await(Type.CORRUPT);
        verifyState();
    }

    /**
     * Tests that a compiler for a subclass of an intent that already has a
     * compiler is automatically added.
     */
    @Test
    public void intentSubclassCompile() {
        class MockIntentSubclass extends MockIntent {
            public MockIntentSubclass(Long number) {
                super(number);
            }
        }
        flowRuleService.setFuture(true);

        listener.setLatch(1, Type.INSTALL_REQ);
        listener.setLatch(1, Type.INSTALLED);
        Intent intent = new MockIntentSubclass(MockIntent.nextId());
        service.submit(intent);
        listener.await(Type.INSTALL_REQ);
        listener.await(Type.INSTALLED);
        assertEquals(1L, service.getIntentCount());
        assertEquals(1L, flowRuleService.getFlowRuleCount());

        final Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> compilers =
                extensionService.getCompilers();
        assertEquals(2, compilers.size());
        assertNotNull(compilers.get(MockIntentSubclass.class));
        assertNotNull(compilers.get(MockIntent.class));
        verifyState();
    }

    /**
     * Tests an intent with no compiler.
     */
    @Test
    public void intentWithoutCompiler() {
        class IntentNoCompiler extends Intent {
            IntentNoCompiler() {
                super(APPID, null, Collections.emptyList(),
                        Intent.DEFAULT_INTENT_PRIORITY);
            }
        }

        Intent intent = new IntentNoCompiler();
        listener.setLatch(1, Type.INSTALL_REQ);
        listener.setLatch(1, Type.FAILED);
        service.submit(intent);
        listener.await(Type.INSTALL_REQ);
        listener.await(Type.FAILED);
        verifyState();
    }

    /**
     * Tests an intent with no installer.
     */
    @Test
    public void intentWithoutInstaller() {
        MockIntent intent = new MockIntent(MockIntent.nextId());
        listener.setLatch(1, Type.INSTALL_REQ);
        listener.setLatch(1, Type.CORRUPT);
        service.submit(intent);
        listener.await(Type.INSTALL_REQ);
        listener.await(Type.CORRUPT);
        verifyState();
    }

    /**
     * Tests that the intent fetching methods are correct.
     */
    @Test
    public void testIntentFetching() {
        List<Intent> intents;

        flowRuleService.setFuture(true);

        intents = Lists.newArrayList(service.getIntents());
        assertThat(intents, hasSize(0));

        final MockIntent intent1 = new MockIntent(MockIntent.nextId());
        final MockIntent intent2 = new MockIntent(MockIntent.nextId());

        listener.setLatch(2, Type.INSTALL_REQ);
        listener.setLatch(2, Type.INSTALLED);
        service.submit(intent1);
        service.submit(intent2);
        listener.await(Type.INSTALL_REQ);
        listener.await(Type.INSTALL_REQ);
        listener.await(Type.INSTALLED);
        listener.await(Type.INSTALLED);

        intents = Lists.newArrayList(service.getIntents());
        assertThat(intents, hasSize(2));

        assertThat(intents, hasIntentWithId(intent1.id()));
        assertThat(intents, hasIntentWithId(intent2.id()));
        verifyState();
    }

    /**
     * Tests that removing all intents results in no flows remaining.
     */
    @Test
    public void testFlowRemoval() {
        List<Intent> intents;

        flowRuleService.setFuture(true);

        intents = Lists.newArrayList(service.getIntents());
        assertThat(intents, hasSize(0));

        final MockIntent intent1 = new MockIntent(MockIntent.nextId());
        final MockIntent intent2 = new MockIntent(MockIntent.nextId());

        listener.setLatch(1, Type.INSTALL_REQ);
        listener.setLatch(1, Type.INSTALLED);

        service.submit(intent1);
        listener.await(Type.INSTALL_REQ);
        listener.await(Type.INSTALLED);


        listener.setLatch(1, Type.INSTALL_REQ);
        listener.setLatch(1, Type.INSTALLED);

        service.submit(intent2);
        listener.await(Type.INSTALL_REQ);
        listener.await(Type.INSTALLED);

        assertThat(listener.getCounts(Type.INSTALLED), is(2));
        assertThat(flowRuleService.getFlowRuleCount(), is(2));

        listener.setLatch(1, Type.WITHDRAWN);
        service.withdraw(intent1);
        listener.await(Type.WITHDRAWN);

        listener.setLatch(1, Type.WITHDRAWN);
        service.withdraw(intent2);
        listener.await(Type.WITHDRAWN);

        assertThat(listener.getCounts(Type.WITHDRAWN), is(2));
        assertThat(flowRuleService.getFlowRuleCount(), is(0));
    }

    /**
     * Test failure to install an intent, then succeed on retry via IntentCleanup.
     */
    @Test
    public void testCorruptCleanup() {
        IntentCleanup cleanup = new IntentCleanup();
        cleanup.service = manager;
        cleanup.store = manager.store;
        cleanup.cfgService = new ComponentConfigAdapter();

        try {
            cleanup.activate();

            final TestIntentCompilerMultipleFlows errorCompiler = new TestIntentCompilerMultipleFlows();
            extensionService.registerCompiler(MockIntent.class, errorCompiler);
            List<Intent> intents;

            flowRuleService.setFuture(false);

            intents = Lists.newArrayList(service.getIntents());
            assertThat(intents, hasSize(0));

            final MockIntent intent1 = new MockIntent(MockIntent.nextId());

            listener.setLatch(1, Type.INSTALL_REQ);
            listener.setLatch(1, Type.CORRUPT);
            listener.setLatch(1, Type.INSTALLED);

            service.submit(intent1);

            listener.await(Type.INSTALL_REQ);
            listener.await(Type.CORRUPT);

            flowRuleService.setFuture(true);

            listener.await(Type.INSTALLED);

            assertThat(listener.getCounts(Type.CORRUPT), is(1));
            assertThat(listener.getCounts(Type.INSTALLED), is(1));
            assertEquals(INSTALLED, manager.getIntentState(intent1.key()));
            assertThat(flowRuleService.getFlowRuleCount(), is(5));
        } finally {
            cleanup.deactivate();
        }
    }

    /**
     * Test failure to install an intent, and verify retries.
     */
    @Test
    public void testCorruptRetry() {
        IntentCleanup cleanup = new IntentCleanup();
        cleanup.service = manager;
        cleanup.store = manager.store;
        cleanup.cfgService = new ComponentConfigAdapter();
        cleanup.period = 1_000_000;
        cleanup.retryThreshold = 3;

        try {
            cleanup.activate();

            final TestIntentCompilerMultipleFlows errorCompiler = new TestIntentCompilerMultipleFlows();
            extensionService.registerCompiler(MockIntent.class, errorCompiler);
            List<Intent> intents;

            flowRuleService.setFuture(false);

            intents = Lists.newArrayList(service.getIntents());
            assertThat(intents, hasSize(0));

            final MockIntent intent1 = new MockIntent(MockIntent.nextId());

            listener.setLatch(1, Type.INSTALL_REQ);
            listener.setLatch(cleanup.retryThreshold, Type.CORRUPT);
            listener.setLatch(1, Type.INSTALLED);

            service.submit(intent1);

            listener.await(Type.INSTALL_REQ);
            listener.await(Type.CORRUPT);
            assertEquals(CORRUPT, manager.getIntentState(intent1.key()));
            assertThat(listener.getCounts(Type.CORRUPT), is(cleanup.retryThreshold));

        } finally {
            cleanup.deactivate();
        }
    }

    /**
     * Tests that an intent that fails installation results in no flows remaining.
     */
    @Test
    @Ignore("MockFlowRule numbering issue") //test works if run independently
    public void testFlowRemovalInstallError() {
        final TestIntentCompilerMultipleFlows errorCompiler = new TestIntentCompilerMultipleFlows();
        extensionService.registerCompiler(MockIntent.class, errorCompiler);
        List<Intent> intents;

        flowRuleService.setFuture(true);
        //FIXME relying on "3" is brittle
        flowRuleService.setErrorFlow(3);

        intents = Lists.newArrayList(service.getIntents());
        assertThat(intents, hasSize(0));

        final MockIntent intent1 = new MockIntent(MockIntent.nextId());

        listener.setLatch(1, Type.INSTALL_REQ);
        listener.setLatch(1, Type.CORRUPT);

        service.submit(intent1);
        listener.await(Type.INSTALL_REQ);
        listener.await(Type.CORRUPT);

        assertThat(listener.getCounts(Type.CORRUPT), is(1));
        // in this test, there will still be flows abandoned on the data plane
        //assertThat(flowRuleService.getFlowRuleCount(), is(0));
    }
}
