package eu.gity.jmeter.ddos.slowloris;

import eu.gity.jmeter.ddos.common.DDoSInputVerifier;
import org.apache.jmeter.engine.StandardJMeterEngine;
import org.apache.jmeter.gui.util.VerticalPanel;
import org.apache.jmeter.samplers.gui.AbstractSamplerGui;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.testelement.TestStateListener;
import org.apache.jmeter.util.JMeterUtils;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.Collection;

import static eu.gity.jmeter.ddos.properties.strings.DdosPropertiesStrings.*;

/**
 * This GUI class provides user interface to setup Slowloris DoS attack
 *
 * @author Gity a.s.
 */
public class SlowLorisGui extends AbstractSamplerGui {

    private static final long serialVersionUID = 240L;

    private JTextField targetIP;
    private JTextField number;
    private JTextField port;
    private JCheckBox useHttps;
    private JCheckBox randomize; //Randomize browsed identification

    private final DDoSInputVerifier verifier = new DDoSInputVerifier();

    /**
     * Ctor which starts GUI initialization
     */
    public SlowLorisGui() {
        init();
        registerTestStateListener();
    }

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

    /**
     * @return The name of component used in title, tree and name of the test
     */
    @Override
    public String getStaticLabel() {
        return JMeterUtils.getLocaleString(DDOS_SLOWLORIS_TITLE);
    }

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

    /**
     * {@inheritDoc}
     */
    @Override
    public void modifyTestElement(TestElement te) {
        te.clear();
        configureTestElement(te);
        te.setProperty(SlowLorisSampler.TARGETIP, targetIP.getText());
        te.setProperty(SlowLorisSampler.NUMBER, number.getText());
        te.setProperty(SlowLorisSampler.PORT, port.getText());
        te.setProperty(SlowLorisSampler.USEHTTPS, useHttps.isSelected());
        te.setProperty(SlowLorisSampler.RANDOMIZE, randomize.isSelected());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void configure(TestElement element) {
        super.configure(element);
        targetIP.setText(element.getPropertyAsString(SlowLorisSampler.TARGETIP));
        number.setText(element.getPropertyAsString(SlowLorisSampler.NUMBER));
        port.setText(element.getPropertyAsString(SlowLorisSampler.PORT));
        useHttps.setSelected(element.getPropertyAsBoolean(SlowLorisSampler.USEHTTPS));
        randomize.setSelected(element.getPropertyAsBoolean(SlowLorisSampler.RANDOMIZE));
    }

    /**
     * Creates a panel for target IP setting
     *
     * @return panel containing GUI components for setting target IP
     */
    private JPanel createServerPanel() {
        JLabel label = new JLabel(JMeterUtils.getLocaleString(DDOS_IP_ADDRESS)); //$NON-NLS-1$
        targetIP = new JTextField("192.168.0.254");
        targetIP.setName("ip");
        targetIP.setInputVerifier(verifier);
        label.setLabelFor(targetIP);
        JPanel serverPanel = new JPanel(new BorderLayout(5, 0));
        serverPanel.add(label, BorderLayout.WEST);
        serverPanel.add(targetIP, BorderLayout.CENTER);
        return serverPanel;
    }

    /**
     * Creates a panel for setting a number of sockets to be opened
     *
     * @return panel containing GUI components for setting number of sockets to be opened
     */
    private JPanel numberPanel() {
        JLabel label = new JLabel(JMeterUtils.getLocaleString(DDOS_SOCKET_COUNT)); //$NON-NLS-1$
        number = new JTextField("5");
        number.setName("naturalOrNothing");
        number.setInputVerifier(verifier);
        label.setLabelFor(number);
        JPanel numberPanel = new JPanel(new BorderLayout(5, 0));
        numberPanel.add(label, BorderLayout.WEST);
        numberPanel.add(number, BorderLayout.CENTER);
        return numberPanel;
    }

    /**
     * Creates a panel for port setting
     *
     * @return panel containing GUI components for setting port
     */
    private JPanel portPanel() {
        JLabel label = new JLabel(JMeterUtils.getLocaleString(DDOS_SLOWLORIS_PORT)); //$NON-NLS-1$
        port = new JTextField("80");
        port.setName("port");
        port.setInputVerifier(verifier);
        label.setLabelFor(port);
        JPanel portPanel = new JPanel(new BorderLayout(5, 0));
        portPanel.add(label, BorderLayout.WEST);
        portPanel.add(port, BorderLayout.CENTER);
        return portPanel;
    }

    /**
     * Creates a panel for options setting
     *
     * @return panel containing GUI components for setting options
     */
    private JPanel optionsPanel() {
        useHttps = new JCheckBox(JMeterUtils.getLocaleString(DDOS_USE_HTTPS));
        randomize = new JCheckBox(JMeterUtils.getLocaleString(DDOS_SLOWLORIS_RANDOMIZE));

        useHttps.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(final ItemEvent e) {
                enableHTTPs(e.getStateChange() == ItemEvent.SELECTED);
            }

            private void enableHTTPs(boolean b) {
                if (b) {
                    port.setText("443");
                } else {
                    port.setText("80");
                }
            }
        });

        JPanel optionsPanel = new JPanel(new BorderLayout(5, 0));
        optionsPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(Color.LIGHT_GRAY, Color.BLACK), JMeterUtils.getLocaleString(DDOS_OPTIONS)));

        optionsPanel.add(useHttps, BorderLayout.WEST);
        optionsPanel.add(randomize, BorderLayout.CENTER);

        return optionsPanel;
    }

    /**
     * Performs GUI initialization
     */
    private void init() {
        setLayout(new BorderLayout(5, 5));
        setBorder(makeBorder());
        add(makeTitlePanel(), BorderLayout.NORTH);

        VerticalPanel mainPanel = new VerticalPanel();
        mainPanel.add(optionsPanel());
        mainPanel.add(createServerPanel());
        mainPanel.add(portPanel());
        mainPanel.add(numberPanel());

        add(mainPanel, BorderLayout.CENTER);
    }

    /**
     * Enables/disables GUI components (used when test starts/ends)
     *
     * @param en true if the components should be enabled, false if disabled
     */
    private void enableGUIComponents(boolean en) {
        targetIP.setEnabled(en);
        port.setEnabled(en);
        useHttps.setEnabled(en);
        randomize.setEnabled(en);
        number.setEnabled(en);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void clearGui() {
        super.clearGui();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Collection<String> getMenuCategories() {
        return new ArrayList<String>();
    }

    /**
     * Registers a listener which reacts to start/end of the test events
     */
    private void registerTestStateListener() {
        TestStateListener testStateListener = new TestStateListener() {

            @Override
            public void testStarted() {
                enableGUIComponents(false);
            }

            @Override
            public void testStarted(String host) {
                testStarted();
            }

            @Override
            public void testEnded() {
                //Register again for a next run
                registerTestStateListener();
                enableGUIComponents(true);
            }

            @Override
            public void testEnded(String host) {
                testEnded();
            }
        };
        StandardJMeterEngine.register(testStateListener);
    }
}
