/**
 * Copyright (c) 2014 Richard Warburton (richard.warburton@gmail.com)
 * <p>
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 * <p>
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 * <p>
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 **/
package com.insightfullogic.honest_profiler.system_tests;

import com.insightfullogic.honest_profiler.core.MachineListener;
import com.insightfullogic.honest_profiler.core.Monitor;
import com.insightfullogic.honest_profiler.core.profiles.Profile;
import com.insightfullogic.honest_profiler.core.sources.VirtualMachine;
import com.insightfullogic.honest_profiler.ports.sources.FileLogSource;
import com.insightfullogic.honest_profiler.ports.sources.LocalMachineSource;
import com.insightfullogic.honest_profiler.testing_utilities.AgentRunner;
import com.insightfullogic.honest_profiler.testing_utilities.NonInteractiveAgentRunner;
import com.insightfullogic.lambdabehave.JunitSuiteRunner;
import com.insightfullogic.lambdabehave.expectations.Expect;
import org.hamcrest.Matcher;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.atomic.AtomicReference;

import static com.insightfullogic.lambdabehave.Suite.describe;
import static java.util.concurrent.TimeUnit.SECONDS;
import static java.util.concurrent.locks.LockSupport.parkNanos;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;

@RunWith(JunitSuiteRunner.class)
public class AgentIntegrationTest
{

    private static Logger logger = LoggerFactory.getLogger(AgentIntegrationTest.class);

    private AtomicReference<FileLogSource> file = new AtomicReference<>();

    {

        describe("Agent Integration", it -> {

            it.isConcludedWith(() ->
            {
                final FileLogSource source = file.get();
                if (source != null)
                {
                    source.getFile().delete();
                }
            });

            it.should("should result in a monitorable JVM", expect ->
            {
                AgentRunner.run("InfiniteExample", AgentRunner.DEFAULT_AGENT_INTERVAL,
                        runner ->
                {
                    int seenTraceCount = 0;

                    AtomicReference<Profile> lastProfile = discoverVirtualMachines();

                    seenTraceCount = expectIncreasingTraceCount(expect, seenTraceCount, lastProfile);

                    seenTraceCount = expectIncreasingTraceCount(expect, seenTraceCount, lastProfile);

                    seenTraceCount = expectIncreasingTraceCount(expect, seenTraceCount, lastProfile);
                });
            });

            it.should("should be able to start/stop the JVM", expect ->
            {
                AgentRunner.run("InfiniteExample", new String[] { "start=0", AgentRunner.DEFAULT_AGENT_INTERVAL },
                        runner ->
                {
                    int seenTraceCount = 0;

                    AtomicReference<Profile> lastProfile = discoverVirtualMachines();

                    seenTraceCount = expectNonIncreasingTraceCount(expect, seenTraceCount, lastProfile);

                    runner.startProfiler();
                    
                    parkNanos(SECONDS.toNanos(2));
                    
                    seenTraceCount = expectIncreasingTraceCount(expect, seenTraceCount, lastProfile);
                    
                    parkNanos(SECONDS.toNanos(2));
                    
                    runner.stopProfiler();

                    seenTraceCount = expectIncreasingTraceCount(expect, seenTraceCount, lastProfile);
                    seenTraceCount = expectNonIncreasingTraceCount(expect, seenTraceCount, lastProfile);
                });
            });

            it.should("should be able to change agent settings", expect ->
            {
                NonInteractiveAgentRunner.run("AgentApiExample", "start=0", runner ->
                {
                    expect.that(runner.isSuccessful()).is(equalTo(true));

                    if (!runner.isSuccessful())
                        logger.debug("Errors in agent profiled process {}", runner.getErrorMessages());
                });
            });
        });

    }

    private AtomicReference<Profile> discoverVirtualMachines()
    {
        AtomicReference<Profile> lastProfile = new AtomicReference<>();
        parkNanos(SECONDS.toNanos(1));

        new LocalMachineSource(logger, new MachineListener()
        {
            @Override
            public void onNewMachine(final VirtualMachine machine)
            {
                if (machine.isAgentLoaded())
                {
                    final FileLogSource logSource = (FileLogSource) machine.getLogSource();
                    file.set(logSource);
                    Monitor.pipeFile(logSource, lastProfile::set);
                }
            }

            @Override
            public void onClosedMachine(final VirtualMachine machine)
            {

            }
        }).discoverVirtualMachines();

        return lastProfile;
    }

    private int expectIncreasingTraceCount(Expect expect, int seenTraceCount, AtomicReference<Profile> lastProfile)
    {
        return expectTraceCount(expect, seenTraceCount, greaterThan(seenTraceCount), lastProfile);
    }

    private int expectNonIncreasingTraceCount(Expect expect, int seenTraceCount, AtomicReference<Profile> lastProfile)
    {
        return expectTraceCount(expect, seenTraceCount, equalTo(seenTraceCount), lastProfile);
    }

    private int expectTraceCount(final Expect expect,
                                 final int seenTraceCount,
                                 final Matcher<Integer> matcher,
                                 final AtomicReference<Profile> lastProfile)
    {
        logger.debug("Last seen trace count is {}", seenTraceCount);
        parkNanos(SECONDS.toNanos(1));
        Profile profile = lastProfile.get();
        int currentTraceCount = profile == null ? 0 : profile.getTraceCount();
        expect.that(currentTraceCount).is(matcher);
        return currentTraceCount;
    }
}

@@ -4149,80 +4149,8 @@
    %0A
-                    parkNanos(SECONDS.toNanos(2));%0A                    %0A
     
@@ -4272,80 +4272,8 @@
    %0A
-                    parkNanos(SECONDS.toNanos(2));%0A                    %0A
     

remove redundant code