package cz.martinstainer.gui;

import java.awt.*;
import java.io.InputStream;

import javax.swing.*;
import javax.swing.border.TitledBorder;

import cz.martinstainer.sampler.TPerfSampler;

import org.apache.jmeter.config.Argument;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.config.gui.ArgumentsPanel;
import org.apache.jmeter.samplers.gui.AbstractSamplerGui;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.gui.ObjectTableModel;
import org.apache.jorphan.reflect.Functor;

import cz.martinstainer.sampler.IPerfSampler;

public class TPerfSamplerGui extends AbstractSamplerGui {

    private static final long serialVersionUID = 240L;

    private JTextArea data;

    public InputStream inputStream = null;

    private ArgumentsPanel argsPanel;

    public TPerfSamplerGui() {
        init();
    }

    public JCheckBox checkbox;

    public JTextField serverIpAddress;

    public JTextField port;

    public JTextField timeValue;

    public JTextField interval;

    public JTextField blockSize;

    public JTextField bytesPerStream;

    public JTextField clientTransportTimeResolutionMs;

    public JTextField maxCwndMss;

    public JTextField windowSize;

    public JTextField writesPerLoop;

    public JTextField numberOfStreams;

    public JComboBox congestionSelectBox;

    public JCheckBox gso;

    public JCheckBox pacing;

    public JComboBox pacingType;

    /** TCP OR UDP */
    public ButtonGroup group;

    /**
     * {@inheritDoc}
     */
    @Override
    public String getLabelResource() {
        return "TPerf sampler"; // $NON-NLS-1$
    }

    /**
     * {@inheritDoc}
     */
    public String getStaticLabelResource() {
        return "TPerf sampler"; // $NON-NLS-1$
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void configure(TestElement element) {
        TPerfSampler tPerfSampler = (TPerfSampler) element;
        data.setText(element.getPropertyAsString(IPerfSampler.DATA));
        argsPanel.configure(tPerfSampler.getArguments());
        super.configure(element);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public TestElement createTestElement() {
        TPerfSampler sampler = new TPerfSampler();
        modifyTestElement(sampler);
        return sampler;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void modifyTestElement(TestElement te) {
        super.configureTestElement(te);
        TPerfSampler tPerfSampler = (TPerfSampler) te;

        Arguments args = (Arguments) argsPanel.createTestElement();

        tPerfSampler.setProperty("time", this.timeValue.getText());

        args.addArgument(new Argument("--mode", "--mode"));
        args.addArgument(new Argument("--mode", "client"));
        args.addArgument(new Argument("-host", "-host"));
        args.addArgument(new Argument("ipAddress", this.serverIpAddress.getText()));
        args.addArgument(new Argument("-port", "-port"));
        args.addArgument(new Argument("portValue", this.port.getText()));
        args.addArgument(new Argument("timeArg", "-duration"));
        args.addArgument(new Argument("time", this.timeValue.getText()));
        args.addArgument(new Argument("blocksize arg", "-block_size"));
        args.addArgument(new Argument("blocksize value", this.blockSize.getText()));
        args.addArgument(new Argument("window arg", "-window"));
        args.addArgument(new Argument("window value", this.windowSize.getText()));
        args.addArgument(new Argument("window arg", "-congestion"));
        args.addArgument(new Argument("window value", "bbr"));
        args.addArgument(new Argument("pacing", "-pacing"));
        args.addArgument(new Argument("pacing", "true"));
        args.addArgument(new Argument("gso", "-gso"));
        args.addArgument(new Argument("pacing", "true"));

        tPerfSampler.setArguments(args);
    }

    /*
     * Helper method to set up the GUI screen
     */
    private void init() { // WARNING: called from ctor so must not be overridden (i.e. must be private or final)
        // Standard setup
        setLayout(new BorderLayout(0, 5));
        setBorder(makeBorder());
        add(makeTitlePanel(), BorderLayout.NORTH); // Add the standard title

        // Specific setup
        add(createDataPanel(), BorderLayout.CENTER);
    }

    private JPanel createBlockSizePanel() {
        FlowLayout flowLayout = new FlowLayout(FlowLayout.LEFT);
        JPanel panel = new JPanel(flowLayout);

        blockSize = new JTextField();
        blockSize.setText("4096");

        JLabel blockSizeLabel = new JLabel("Block size (Amount of data written to stream each iteration)");

        panel.add(blockSizeLabel);
        panel.add(blockSize);

        return panel;
    }

    private JPanel createBytesPerStreamPanel() {
        FlowLayout flowLayout = new FlowLayout(FlowLayout.LEFT);
        JPanel panel = new JPanel(flowLayout);

        bytesPerStream = new JTextField();
        bytesPerStream.setText("0");

        JLabel label = new JLabel("Maximum number of bytes per stream. 0 (the default)  " +
                "      means the stream lives for the whole duration of the test.");

        panel.add(label);
        panel.add(bytesPerStream);

        return panel;
    }

    private JPanel createClientTransportTimeResolutionMsPanel() {
        FlowLayout flowLayout = new FlowLayout(FlowLayout.LEFT);
        JPanel panel = new JPanel(flowLayout);

        clientTransportTimeResolutionMs = new JTextField();
        clientTransportTimeResolutionMs.setText("1");

        JLabel label = new JLabel("Timer resolution for Ack and Loss " +
                "      tiemout in client transport");

        panel.add(label);
        panel.add(clientTransportTimeResolutionMs);

        return panel;
    }

    private JPanel createCongestionPanel() {
        FlowLayout flowLayout = new FlowLayout(FlowLayout.LEFT);
        JPanel panel = new JPanel(flowLayout);


        String s1[] = { "newreno", "cubic", "bbr", "none"};
        congestionSelectBox = new JComboBox(s1);
        congestionSelectBox.setSelectedIndex(1);

        JLabel label = new JLabel("Congestion ");

        panel.add(label);
        panel.add(congestionSelectBox);

        return panel;
    }

    private JPanel createGsoPanel() {
        FlowLayout flowLayout = new FlowLayout(FlowLayout.LEFT);
        JPanel panel = new JPanel(flowLayout);

        gso = new JCheckBox("Enable GSO writes to the socket");

        panel.add(gso);

        return panel;
    }

    private JPanel createPacingPanel() {
        FlowLayout flowLayout = new FlowLayout(FlowLayout.LEFT);
        JPanel panel = new JPanel(flowLayout);

        pacing = new JCheckBox("Enable pacing");

        String s1[] = { "none", "time", "rtt", "ack"};
        pacingType = new JComboBox(s1);

        panel.add(pacing);
        panel.add(pacingType);

        return panel;
    }

    private JPanel createWindowSizePanel() {
        FlowLayout flowLayout = new FlowLayout(FlowLayout.LEFT);
        JPanel panel = new JPanel(flowLayout);

        windowSize = new JTextField();
        windowSize.setText("65536");

        JLabel label = new JLabel("Flow control window size");

        panel.add(label);
        panel.add(windowSize);

        return panel;
    }

    private JPanel createWritesPerLoopPanel() {
        FlowLayout flowLayout = new FlowLayout(FlowLayout.LEFT);
        JPanel panel = new JPanel(flowLayout);

        writesPerLoop = new JTextField();
        writesPerLoop.setText("5");

        JLabel label = new JLabel("Amount of socket writes per event loop");

        panel.add(label);
        panel.add(writesPerLoop);

        return panel;
    }

    private JPanel createMaxCwndMssPanel() {
        FlowLayout flowLayout = new FlowLayout(FlowLayout.LEFT);
        JPanel panel = new JPanel(flowLayout);

        maxCwndMss = new JTextField();
        maxCwndMss.setText("860000");

        JLabel label = new JLabel("Max cwnd in the unit of mss");

        panel.add(label);
        panel.add(maxCwndMss);

        return panel;
    }

    private JPanel createNumStreamsPanel() {
        FlowLayout flowLayout = new FlowLayout(FlowLayout.LEFT);
        JPanel panel = new JPanel(flowLayout);

        numberOfStreams = new JTextField();
        numberOfStreams.setText("1");

        JLabel label = new JLabel("Number of streams to send on simultaneously");

        panel.add(label);
        panel.add(numberOfStreams);

        return panel;
    }

    private JPanel createIpAddresAndPortPanel() {
        FlowLayout flowLayout = new FlowLayout(FlowLayout.LEFT);
        JPanel panel = new JPanel(flowLayout);

        serverIpAddress = new JTextField();
        port = new JTextField();

        serverIpAddress.setSize(200,20);
        serverIpAddress.setColumns(20);
        port.setText("6666");
        port.setSize(100,20);
        port.setColumns(5);

        JLabel ipAddressLabel = new JLabel("Ip adresa");
        JLabel portLabel = new JLabel("Port");
        panel.add(ipAddressLabel);
        panel.add(serverIpAddress);
        panel.add(portLabel);
        panel.add(port);

        return panel;
    }


    private JPanel createTimeOptionPanel() {
        FlowLayout flowLayout = new FlowLayout(FlowLayout.LEFT);
        JPanel panel = new JPanel(flowLayout);

        JCheckBox useTimer = new JCheckBox("Duration of test");
        timeValue = new JTextField();
        timeValue.setText("60");
        timeValue.setColumns(10);

        panel.add(useTimer);
        panel.add(timeValue);

        return panel;
    }

    private JPanel createNetworkOptionsPanel() {
        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));

        panel.add(createIpAddresAndPortPanel());
        panel.add(createBlockSizePanel());
        panel.add(createBytesPerStreamPanel());
        panel.add(createClientTransportTimeResolutionMsPanel());
        panel.add(createCongestionPanel());
        panel.add(createGsoPanel());
        panel.add(createMaxCwndMssPanel());
        panel.add(createNumStreamsPanel());
        panel.add(createPacingPanel());
        panel.add(createWindowSizePanel());
        panel.add(createWritesPerLoopPanel());
        panel.setBorder(new TitledBorder("tPerf Settings"));

        return panel;
    }

    private JPanel createTimeOptionsPanel() {
        JPanel panel = new JPanel(new GridLayout(1,2));
        FlowLayout flowLayoutLeft = new FlowLayout(FlowLayout.LEFT);
        JPanel left = new JPanel(flowLayoutLeft);
        JPanel right = new JPanel(flowLayoutLeft);

        left.add(createTimeOptionPanel());
        panel.setBorder(new TitledBorder("Duration of test"));

        panel.add(left);
        panel.add(right);

        return panel;
    }


    /*
     * Create a data input text field
     *
     * @return the panel for entering the data
     */
    private Component createDataPanel() {
        JLabel label = new JLabel(JMeterUtils.getResString("example_data")); //$NON-NLS-1$

        data = new JTextArea();
        data.setName(IPerfSampler.DATA);
        label.setLabelFor(data);

        JPanel dataPanel = new JPanel();
        dataPanel.setLayout(new BoxLayout(dataPanel, BoxLayout.PAGE_AXIS));

        dataPanel.add(createNetworkOptionsPanel());
        dataPanel.add(createTimeOptionsPanel());
        dataPanel.add(makeArgumentsPanel());

        return dataPanel;
    }

    private JPanel makeArgumentsPanel() {
        argsPanel = new ArgumentsPanel(JMeterUtils.getResString("arguments_panel_title"), null, true, false ,  // $NON-NLS-1$
                new ObjectTableModel(new String[] { ArgumentsPanel.COLUMN_RESOURCE_NAMES_1 },
                        Argument.class,
                        new Functor[] {
                                new Functor("getValue") },  // $NON-NLS-1$
                        new Functor[] {
                                new Functor("setValue") }, // $NON-NLS-1$
                        new Class[] {String.class }));
        return argsPanel;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void clearGui() {
        super.clearGui();
        data.setText(""); // $NON-NLS-1$
    }
}
