package cz.martinstainer.sampler;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;

import cz.martinstainer.helper.IPerfResultGetter;

import org.apache.jmeter.config.Argument;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.samplers.AbstractSampler;
import org.apache.jmeter.samplers.Entry;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.services.FileServer;
import org.apache.jmeter.testelement.property.TestElementProperty;
import org.apache.jorphan.exec.SystemCommand;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.regex.Matcher;

public class IPerfSampler extends AbstractSampler {

    private static final long serialVersionUID = 240L;

    public static final String ARGUMENTS = "IPerfSampler.arguments";

    private static final Logger log = LoggerFactory.getLogger(IPerfSampler.class);

    // The name of the property used to hold our data
    public static final String DATA = "IPerf.data"; //$NON-NLS-1$

    private static AtomicInteger classCount = new AtomicInteger(0); // keep track of classes created

    // (for instructional purposes only!)
    public IPerfSampler() {
        classCount.incrementAndGet();
        trace("IPerfSampler()");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public SampleResult sample(Entry e) {
        trace("sample()");
        SampleResult sampleResults = new SampleResult();
        sampleResults.setContentType("iperf");
        String data = getData(); // Sampler data
        sampleResults.setSampleLabel(getTitle());
        String command = "iperf3";
        ArrayList<String> cmds = new ArrayList<String>(1);
        cmds.add(command);
        SystemCommand nativeCommand = null;
        File directory = new File(FileServer.getDefaultBase());
        Arguments args = getArguments();
        for (int i=0; i < args.getArgumentCount(); i++) {
            Argument arg = args.getArgument(i);
            cmds.add(arg.getPropertyAsString(Argument.VALUE));
        }
        try {
            if(log.isDebugEnabled()) {
                log.debug("Running iperf");
            }
            nativeCommand = new SystemCommand(directory, null);
            sampleResults.sampleStart();
            int returnCode = nativeCommand.run(cmds);

            sampleResults.sampleEnd();
            sampleResults.setResponseCode(Integer.toString(returnCode));
            sampleResults.setLatency(1);
            sampleResults.setResponseData(nativeCommand.getOutResult());
            Matcher matcher = IPerfResultGetter.get(nativeCommand.getOutResult(), "Gbit");
            SampleResult sr = new SampleResult();
            while(matcher.find()) {
                String substr = matcher.group().substring(0, 4);
                float number = Float.parseFloat(substr);
                sr.setSentBytes((long) (number * 1024.0));

                break;
            }
            sampleResults.setBytes(sr.getSentBytes());
            sampleResults.setSentBytes(sr.getSentBytes());
            if ((returnCode != 0)) {
                sampleResults.setSuccessful(false);
                sampleResults.setResponseMessage("Unexpected return code.  Expected ["+ 1 +"]. Actual ["+returnCode+"].");
            } else {
                sampleResults.setSuccessful(true);
                sampleResults.setResponseMessage("OK");
            }
        } catch (IOException ioe) {
            sampleResults.sampleEnd();
            sampleResults.setSuccessful(false);
            sampleResults.setResponseCode("500"); //$NON-NLS-1$
            sampleResults.setResponseMessage("Exception occurred whilst executing system call: " + ioe);
        } catch (InterruptedException ie) {
            sampleResults.sampleEnd();
            sampleResults.setSuccessful(false);
            sampleResults.setResponseCode("500"); //$NON-NLS-1$
            sampleResults.setResponseMessage("System Sampler interrupted whilst executing system call: " + ie);
            Thread.currentThread().interrupt();
        } catch (TimeoutException ee) {
            sampleResults.sampleEnd();
            sampleResults.setSuccessful(false);
            sampleResults.setResponseCode("500");
            sampleResults.setResponseMessage(ee.getMessage());
        }

        return sampleResults;
    }


    public Arguments getArguments() {
        return (Arguments) getProperty(ARGUMENTS).getObjectValue();
    }

    /**
     * @return a string for the sampleResult Title
     */
    private String getTitle() {
        return this.getName();
    }

    /**
     * @return the data for the sample
     */
    public String getData() {
        return getPropertyAsString(DATA);
    }

    public String getName() {
        return "IPerf Sampler";
    }

    public void setArguments(Arguments args) {
        setProperty(new TestElementProperty(ARGUMENTS, args));
    }

    /*
     * Helper method
     */
    private void trace(String s) {
        if (log.isDebugEnabled()) {
            log.debug("{} ({}) {} {} {}", Thread.currentThread().getName(), Integer.valueOf(classCount.get()),
                    getTitle(), s, this.toString());
        }
    }
}
