package cz.martinstainer.gui;

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

import javax.swing.JLabel;
import javax.swing.*;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JCheckBox;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;

import cz.martinstainer.sampler.IPerfSampler;

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;

public class IPerfSamplerGui extends AbstractSamplerGui {

    private static final long serialVersionUID = 240L;
    private JTextArea data;
    private ArgumentsPanel argsPanel;
    private final ButtonGroup transportTypeGroup = new ButtonGroup();
    private final JTextField portNumber = new JTextField();
    private final JTextField connectTimeoutTextField = new JTextField();
    private final JCheckBox useConnectTimeout = new JCheckBox("timeout for control connection setup (ms)");
    private final JCheckBox useBandwith = new JCheckBox("target bitrate in bits/sec (0 for unlimited)\n" +
            "                            (default 1 Mbit/sec for UDP, unlimited for TCP)\n" +
            "                            (optional slash and packet count for burst mode)");
    private final JTextField bitrate = new JTextField();
    private final JTextField pacingTimer = new JTextField();
    private final JTextField fqRate = new JTextField();
    private final JTextField parallelStream = new JTextField();
    private final JCheckBox reverseModeCheckBox = new JCheckBox("run in reverse mode (server sends, client receives)");
    public JComboBox congestionSelectBox;
    private final JCheckBox checkboxWindow = new JCheckBox("set window size / socket buffer size");
    private final JTextField window = new JTextField();
    private final JCheckBox checkboxMss = new JCheckBox("set TCP/SCTP maximum segment size (MTU - 40 bytes)");
    private final JTextField mss = new JTextField();
    private final JCheckBox noDelay = new JCheckBox("set TCP/SCTP no delay, disabling Nagle's Algorithm");
    private final JCheckBox ipv4 = new JCheckBox("only use IPv4");
    private final JCheckBox ipv6 = new JCheckBox("only use IPv6");
    private final JCheckBox checkBoxTos = new JCheckBox("set the IP type of service");
    private final JTextField tos = new JTextField();
    private final JCheckBox checkDscp = new JCheckBox("set the IP dscp value, either 0-63 or symbolic");
    private final JTextField dscp = new JTextField();
    private final JCheckBox checkBoxflowLabel = new JCheckBox("set the IPv6 flow label (only supported on Linux)");
    private final JTextField flowLabel = new JTextField();
    private final JCheckBox checkBoxZeroCopy = new JCheckBox("use a 'zero copy' method of sending data");
    private final JTextField omit = new JTextField();
    private JRadioButton tcp;
    private JRadioButton udp;
    private JRadioButton stcp;

    public IPerfSamplerGui() {
        init();
    }
    public JTextField serverIpAddress;
    public JTextField timeValue;
    public JTextField interval;
    /** TCP OR UDP */
    public ButtonGroup group;

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

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

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

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

    /**
     * {@inheritDoc}
     */
    @Override
    public void modifyTestElement(TestElement te) {
        super.configureTestElement(te);
        IPerfSampler iPerfSampler = (IPerfSampler) te;
        iPerfSampler.setProperty("congestion", "tcp");
        iPerfSampler.setProperty("time", this.timeValue.getText());
        Arguments args = new Arguments();
        args.addArgument(new Argument("Client mode", "--client"));
        args.addArgument(new Argument("IP Address", this.serverIpAddress.getText()));
        args.addArgument(new Argument("Port argument", "--port"));
        args.addArgument(new Argument("Port value", this.portNumber.getText()));
        args.addArgument(new Argument("Interval argument", "--interval"));
        args.addArgument(new Argument("Interval value", this.interval.getText()));
        args.addArgument(new Argument("Format argument", "-f"));
        args.addArgument(new Argument("Format value", "m"));
        if(this.reverseModeCheckBox.isSelected()) {
            args.addArgument(new Argument("Reverse mode", "--reverse"));
        }
        if(this.transportTypeGroup.getSelection() == this.stcp.getModel()) {
            args.addArgument(new Argument("SCTP mode", "--sctp"));
        }
        if(this.transportTypeGroup.getSelection() == this.udp.getModel()) {

            args.addArgument(new Argument("UDP mode", "--udp"));
        }
        args.addArgument(new Argument("Congestion control", "--congestion"));
        args.addArgument(new Argument("Congestion value", (String) this.congestionSelectBox.getSelectedItem()));
        args.addArgument(new Argument("Parallel stream argument", "--parallel"));
        args.addArgument(new Argument("Parallel stream value", (String) this.parallelStream.getText()));
        args.addArgument(new Argument("Bitrate argument", "--bitrate"));
        args.addArgument(new Argument("Bitrate value", (String) this.bitrate.getText()));
        args.addArgument(new Argument("Pacing argument", "--pacing-timer"));
        args.addArgument(new Argument("Pacing value", (String) this.pacingTimer.getText()));
        args.addArgument(new Argument("FQ argument", "--fq-rate"));
        args.addArgument(new Argument("FQ value", (String) this.fqRate.getText()));
        if(this.checkboxWindow.isSelected()) {
            args.addArgument(new Argument("Window argument", "--window"));
            args.addArgument(new Argument("Window value", (String) this.window.getText()));
        }
        if(this.checkboxMss.isSelected()) {
            args.addArgument(new Argument("MSS argument", "--set-mss"));
            args.addArgument(new Argument("MSS value", (String) this.mss.getText()));
        }
        if(this.noDelay.isSelected()) {
            args.addArgument(new Argument("No delay", "--no-delay"));
        }
        if(this.ipv4.isSelected()) {
            args.addArgument(new Argument("IPV4", "--version4"));
        }
        if(this.ipv6.isSelected()) {
            args.addArgument(new Argument("IPV6", "--version6"));
        }
        if(this.checkBoxTos.isSelected()) {
            args.addArgument(new Argument("TOSS argument", "--tos"));
            args.addArgument(new Argument("TOSS value", (String) this.tos.getText()));
        }

        if(this.checkDscp.isSelected()) {
            args.addArgument(new Argument("DSCP argument", "--dscp"));
            args.addArgument(new Argument("DSCP value", (String) this.dscp.getText()));
        }
        if(this.checkBoxflowLabel.isSelected()) {
            args.addArgument(new Argument("Flow argument", "--flowlabel"));
            args.addArgument(new Argument("Flow value", (String) this.flowLabel.getText()));
        }
        if(this.checkBoxZeroCopy.isSelected()) {
            args.addArgument(new Argument("Flow argument", "--zerocopy"));
        }
        iPerfSampler.setArguments(args);
    }

    /*
     * Helper method to set up the GUI screen
     */
    private void init() {
        setLayout(new BorderLayout(0, 5));
        setBorder(makeBorder());
        add(makeTitlePanel(), BorderLayout.NORTH); // Add the standard title

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

    private JPanel createTransportModePanel() {
        FlowLayout flowLayout = new FlowLayout(FlowLayout.LEFT);
        JPanel tcpOrUdpPanel = new JPanel(flowLayout);

        tcp = new JRadioButton("TCP");
        tcp.setSelected(true);
        udp = new JRadioButton("UDP");
        stcp = new JRadioButton("STCP");
        transportTypeGroup.add(tcp);
        transportTypeGroup.add(udp);
        transportTypeGroup.add(stcp);

        tcpOrUdpPanel.add(tcp);
        tcpOrUdpPanel.add(udp);
        tcpOrUdpPanel.add(stcp);

        return tcpOrUdpPanel;
    }

    private JPanel createIpAddresAndPortPanel() {
        FlowLayout flowLayout = new FlowLayout(FlowLayout.LEFT);
        JPanel panel = new JPanel(flowLayout);
        serverIpAddress = new JTextField();
        serverIpAddress.setSize(200,20);
        serverIpAddress.setColumns(20);
        portNumber.setSize(100,20);
        portNumber.setColumns(5);
        JLabel ipAddressLabel = new JLabel("Ip address");
        JLabel portLabel = new JLabel("Port");
        panel.add(ipAddressLabel);
        panel.add(serverIpAddress);
        panel.add(portLabel);
        panel.add(portNumber);
        return panel;
    }

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

        connectTimeoutTextField.setColumns(10);

        panel.add(useConnectTimeout);
        panel.add(connectTimeoutTextField);

        return panel;
    }

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

        JLabel label = new JLabel("target bitrate in bits/sec (0 for unlimited)");
        bitrate.setColumns(10);
        bitrate.setText("0");

        panel.add(label);
        panel.add(bitrate);

        return panel;
    }

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

        JLabel label = new JLabel("set the timing for pacing, in microseconds");
        //bitrate.setColumns(10);
        pacingTimer.setColumns(10);
        pacingTimer.setText("1000");

        panel.add(label);
        panel.add(pacingTimer);

        return panel;
    }

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

        JLabel label = new JLabel("enable fair-queuing based socket pacing in bits/sec");
        //bitrate.setColumns(10);
        fqRate.setColumns(10);
        fqRate.setText("1000");

        panel.add(label);
        panel.add(fqRate);

        return panel;
    }

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

        window.setColumns(10);
        window.setText("");

        panel.add(checkboxWindow);
        panel.add(window);

        return panel;
    }

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

        mss.setColumns(10);
        mss.setText("");

        panel.add(checkboxMss);
        panel.add(mss);

        return panel;
    }

    private JPanel createNoDelayPanel() {
        FlowLayout flowLayout = new FlowLayout(FlowLayout.LEFT);
        JPanel panel = new JPanel(flowLayout);
        panel.add(noDelay);
        return panel;
    }

    private JPanel createIpv4Panel() {
        FlowLayout flowLayout = new FlowLayout(FlowLayout.LEFT);
        JPanel panel = new JPanel(flowLayout);
        panel.add(ipv4);
        return panel;
    }

    private JPanel createIpv6Panel() {
        FlowLayout flowLayout = new FlowLayout(FlowLayout.LEFT);
        JPanel panel = new JPanel(flowLayout);
        panel.add(ipv6);
        return panel;
    }

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

        tos.setColumns(10);
        tos.setText("");

        panel.add(checkBoxTos);
        panel.add(tos);

        return panel;
    }

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

        dscp.setColumns(10);
        dscp.setText("");

        panel.add(checkDscp);
        panel.add(dscp);

        return panel;
    }

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

        tos.setColumns(10);
        tos.setText("");

        panel.add(checkBoxflowLabel);
        panel.add(flowLabel);

        return panel;
    }

    private JPanel createZeroCopyPanel() {
        FlowLayout flowLayout = new FlowLayout(FlowLayout.LEFT);
        JPanel panel = new JPanel(flowLayout);
        panel.add(checkBoxZeroCopy);
        return panel;
    }

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

        JLabel label = new JLabel("Omit first n seconds");
        omit.setColumns(10);
        omit.setText("0");

        panel.add(label);
        panel.add(omit);

        return panel;
    }

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

        JCheckBox useTimer = new JCheckBox("Pouzit vlastni cas testu (-t, --time)");
        timeValue = new JTextField();
        timeValue.setText("60");
        timeValue.setColumns(10);

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

        return panel;
    }

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

        JCheckBox useTimer = new JCheckBox("Interval (-i, --interval)");
        interval = new JTextField();
        interval.setText("1");
        interval.setColumns(10);

        panel.add(useTimer);
        panel.add(interval);

        return panel;
    }

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

        JCheckBox kNumberOfBlocks = new JCheckBox("Pocet packetu (-k, ----blockcount )");
        JTextField kNumberOfBlocksInput = new JTextField();
        kNumberOfBlocksInput.setColumns(10);

        panel.add(kNumberOfBlocks);
        panel.add(kNumberOfBlocksInput);

        return panel;
    }

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

        JCheckBox kNumberOfBlocks = new JCheckBox("Pocet vyrovnavacich pameti k odeslani (-n, --num )");
        JTextField kNumberOfBlocksInput = new JTextField();
        kNumberOfBlocksInput.setColumns(10);

        panel.add(kNumberOfBlocks);
        panel.add(kNumberOfBlocksInput);

        return panel;
    }

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

        JCheckBox lengthOption = new JCheckBox("Delka vyrovnavaci pameti (-l, --length)");
        JTextField lengthOptionInput = new JTextField();
        lengthOptionInput.setColumns(10);

        panel.add(lengthOption);
        panel.add(lengthOptionInput);

        return panel;
    }

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

        JLabel label = new JLabel("number of parallel client streams to run");

        parallelStream.setText("1");
        parallelStream.setColumns(10);

        panel.add(label);
        panel.add(parallelStream);

        return panel;
    }



    private JPanel createReverseModePanel() {
        FlowLayout flowLayout = new FlowLayout(FlowLayout.LEFT);
        JPanel panel = new JPanel(flowLayout);
        panel.add(reverseModeCheckBox);

        return panel;
    }

    private JPanel createCongestionPanel() {
        FlowLayout flowLayout = new FlowLayout(FlowLayout.LEFT);
        JPanel panel = new JPanel(flowLayout);
        String s1[] = { "newreno", "cubic", "bbr"};
        congestionSelectBox = new JComboBox(s1);
        congestionSelectBox.setSelectedIndex(1);

        JLabel label = new JLabel("Congestion");

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

        return panel;
    }


    private JPanel createNetworkOptionsPanel() {
        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
        panel.add(createTransportModePanel());
        panel.add(createCongestionPanel());
        panel.add(createIpAddresAndPortPanel());
        panel.add(createConnectTimeOptionPanel());
        panel.add(createBitrateOptionPanel());
        panel.add(createPacingTimerOptionPanel());
        panel.add(createParallelOptionPanel());
        panel.add(createReverseModePanel());
        panel.add(createFQRateOptionPanel());
        panel.add(createWindowOptionPanel());
        panel.add(createMssOptionPanel());
        panel.add(createNoDelayPanel());
        panel.add(createIpv4Panel());
        panel.add(createIpv6Panel());
        panel.add(createTosOptionPanel());
        panel.add(createDscpOptionPanel());
        panel.add(createFlowLabelOptionPanel());
        panel.add(createZeroCopyPanel());
        panel.add(createOmitOptionPanel());
        panel.setBorder(new TitledBorder("iPerf options"));

        return panel;
    }

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

        panel.add(createTimeOptionPanel());
        panel.add(createIntervalOptionPanel());
        panel.setBorder(new TitledBorder("Time settings"));

        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$
    }
}
