package org.jivesoftware.spark.ui.login;

import org.jivesoftware.resource.Default;
import org.jivesoftware.resource.Res;
import org.jivesoftware.spark.util.ModelUtil;
import org.jivesoftware.spark.util.ResourceUtils;
import org.jivesoftware.sparkimpl.settings.local.LocalPreferences;

import javax.swing.*;
import java.awt.*;
import java.util.Properties;

import static java.awt.GridBagConstraints.*;

/**
 * Internal class to allow setting of proxies within Spark.
 */
class ProxyLoginSettingsPanel extends JPanel
{
    private final static Insets DEFAULT_INSETS = new Insets( 5, 5, 5, 5 );
    private final LocalPreferences localPreferences;
    private final JCheckBox useProxyBox = new JCheckBox();
    private final JComboBox<String> protocolBox = new JComboBox<>();
    private final JTextField hostField = new JTextField();
    private final JTextField portField = new JTextField();
    private final JTextField usernameField = new JTextField();
    private final JPasswordField passwordField = new JPasswordField();
    private final JDialog optionsDialog;

    public ProxyLoginSettingsPanel( LocalPreferences localPreferences, JDialog optionsDialog )
    {
        this.localPreferences = localPreferences;
        this.optionsDialog = optionsDialog;
        final JLabel protocolLabel = new JLabel();
        final JLabel hostLabel = new JLabel();
        final JLabel portLabel = new JLabel();
        final JLabel usernameLabel = new JLabel();
        final JLabel passwordLabel = new JLabel();

        protocolBox.addItem( "SOCKS" );
        protocolBox.addItem( "HTTP" );

        ResourceUtils.resButton( useProxyBox, Res.getString( "checkbox.use.proxy.server" ) );
        ResourceUtils.resLabel( protocolLabel, protocolBox, Res.getString( "label.protocol" ) );
        ResourceUtils.resLabel( hostLabel, hostField, Res.getString( "label.host" ) );
        ResourceUtils.resLabel( portLabel, portField, Res.getString( "label.port" ) );
        ResourceUtils.resLabel( usernameLabel, usernameField, Res.getString( "label.username" ) );
        ResourceUtils.resLabel( passwordLabel, passwordField, Res.getString( "label.password" ) );

        setLayout( new GridBagLayout() );
        add( useProxyBox,   new GridBagConstraints( 0, 0, 2, 1, 1.0, 0.0, NORTHWEST, NONE,       DEFAULT_INSETS, 0, 0 ) );
        add( protocolLabel, new GridBagConstraints( 0, 1, 1, 1, 0.0, 0.0, NORTHWEST, NONE,       DEFAULT_INSETS, 0, 0 ) );
        add( protocolBox,   new GridBagConstraints( 1, 1, 1, 1, 1.0, 0.0, NORTHWEST, HORIZONTAL, DEFAULT_INSETS, 0, 0 ) );
        add( hostLabel,     new GridBagConstraints( 0, 2, 1, 1, 0.0, 0.0, NORTHWEST, NONE,       DEFAULT_INSETS, 0, 0 ) );
        add( hostField,     new GridBagConstraints( 1, 2, 1, 1, 1.0, 0.0, NORTHWEST, HORIZONTAL, DEFAULT_INSETS, 0, 0 ) );
        add( portLabel,     new GridBagConstraints( 0, 3, 1, 1, 0.0, 0.0, NORTHWEST, NONE,       DEFAULT_INSETS, 0, 0 ) );
        add( portField,     new GridBagConstraints( 1, 3, 1, 1, 1.0, 0.0, NORTHWEST, HORIZONTAL, DEFAULT_INSETS, 0, 0 ) );
        add( usernameLabel, new GridBagConstraints( 0, 4, 1, 1, 0.0, 0.0, NORTHWEST, NONE,       DEFAULT_INSETS, 0, 0 ) );
        add( usernameField, new GridBagConstraints( 1, 4, 1, 1, 1.0, 0.0, NORTHWEST, HORIZONTAL, DEFAULT_INSETS, 0, 0 ) );
        add( passwordLabel, new GridBagConstraints( 0, 5, 1, 1, 0.0, 0.0, NORTHWEST, NONE,       DEFAULT_INSETS, 0, 0 ) );
        add( passwordField, new GridBagConstraints( 1, 5, 1, 1, 1.0, 1.0, NORTHWEST, HORIZONTAL, DEFAULT_INSETS, 0, 0 ) );

        useProxyBox.addActionListener( e -> enableFields( useProxyBox.isSelected() ) );

        // Check localSettings
        if ( localPreferences.isProxyEnabled() )
        {
            useProxyBox.setSelected( true );
        }

        enableFields( useProxyBox.isSelected() );

        if ( ModelUtil.hasLength( localPreferences.getHost() ) )
        {
            hostField.setText( localPreferences.getHost() );
        }

        if (localPreferences.getPort() != 0) {
            portField.setText(String.valueOf(localPreferences.getPort()));
        }

        if ( ModelUtil.hasLength( localPreferences.getProxyPassword() ) )
        {
            passwordField.setText( localPreferences.getProxyPassword() );
        }

        if ( ModelUtil.hasLength( localPreferences.getProxyUsername() ) )
        {
            usernameField.setText( localPreferences.getProxyUsername() );
        }

        if ( ModelUtil.hasLength( localPreferences.getProtocol() ) )
        {
            protocolBox.setSelectedItem( localPreferences.getProtocol() );
        }

        if (!Default.getString(Default.PROXY_PROTOCOL).isEmpty())
        {
            protocolBox.setSelectedItem( Default.getString( Default.PROXY_PROTOCOL ) );
            protocolBox.setEnabled( false );
            useProxyBox.setSelected( true );
            useProxyBox.setVisible( false );
        }
        if (!Default.getString(Default.PROXY_HOST).isEmpty())
        {
            hostField.setText( Default.getString( Default.PROXY_HOST ) );
            hostField.setEnabled( false );
            useProxyBox.setSelected( true );
            useProxyBox.setVisible( false );
        }
        if (!Default.getString(Default.PROXY_PORT).isEmpty())
        {
            portField.setText( Default.getString( Default.PROXY_PORT ) );
            portField.setEnabled( false );
        }
    }

    /**
     * Enables the fields of the proxy panel.
     *
     * @param enable true if all fields should be enabled, otherwise false.
     */
    private void enableFields( boolean enable )
    {
        Component[] comps = getComponents();
        for ( Component comp1 : comps )
        {
            if ( comp1 instanceof JTextField || comp1 instanceof JComboBox )
            {
                JComponent comp = (JComponent) comp1;
                comp.setEnabled( enable );
            }
        }
    }

    /**
     * Returns the protocol to use for this proxy.
     *
     * @return the protocol.
     */
    public String getProtocol()
    {
        return (String) protocolBox.getSelectedItem();
    }

    /**
     * Returns the host to use for this proxy.
     *
     * @return the host.
     */
    public String getHost()
    {
        return hostField.getText();
    }

    /**
     * Returns the port to use with this proxy.
     */
    public int getPort()
    {
        return !portField.getText().isBlank() ? Integer.parseInt(portField.getText().trim()) : 0;
    }

    /**
     * Returns the username to use with this proxy.
     *
     * @return the username.
     */
    public String getUsername()
    {
        return usernameField.getText();
    }

    /**
     * Returns the password to use with this proxy.
     *
     * @return the password.
     */
    public String getPassword()
    {
        return new String( passwordField.getPassword() );
    }

    public boolean validate_settings()
    {
        boolean valid = true;
        if ( useProxyBox.isSelected() )
        {
            try
            {
                Integer.valueOf( portField.getText() );
            }
            catch ( NumberFormatException numberFormatException )
            {
                JOptionPane.showMessageDialog( optionsDialog,
                        Res.getString( "message.supply.valid.port" ),
                        Res.getString( "title.error" ),
                        JOptionPane.ERROR_MESSAGE );
                portField.requestFocus();
                valid = false;
            }

            if ( !ModelUtil.hasLength( hostField.getText() ) )
            {
                JOptionPane.showMessageDialog( optionsDialog,
                        Res.getString( "message.supply.valid.host" ),
                        Res.getString( "title.error" ),
                        JOptionPane.ERROR_MESSAGE );
                hostField.requestFocus();
                valid = false;
            }
        }
        return valid;
    }

    public void useDefault() {
        useProxyBox.setSelected(Default.getBoolean(Default.PROXY_ENABLED));
        enableFields(useProxyBox.isSelected());
    }
    
    /**
     * Persist the proxy settings to local preferences.
     */
    public void saveSettings()
    {
        localPreferences.setProxyEnabled( useProxyBox.isSelected() );

        if ( ModelUtil.hasLength( getProtocol() ) )
        {
            localPreferences.setProtocol( getProtocol() );
        }

        if ( ModelUtil.hasLength( getHost() ) )
        {
            localPreferences.setHost( getHost() );
        }

        if (getPort() != 0) {
            localPreferences.setPort(getPort());
        }

        if (getUsername().isEmpty() || getUsername() == null )
        {
            localPreferences.setProxyUsername( "" );
        }

        if ( ModelUtil.hasLength( getUsername() ) )
        {
            localPreferences.setProxyUsername( getUsername() );
        }

        if (getPassword().isEmpty() || getPassword() == null )
        {
            localPreferences.setProxyPassword( "" );
        }

        if ( ModelUtil.hasLength( getPassword() ) )
        {
            localPreferences.setProxyPassword( getPassword() );
        }

        if ( !localPreferences.isProxyEnabled() )
        {
            Properties props = System.getProperties();
            props.remove( "socksProxyHost" );
            props.remove( "socksProxyPort" );
            props.remove( "http.proxyHost" );
            props.remove( "http.proxyPort" );
            props.remove( "http.proxySet" );
        }
        else
        {
            String host = localPreferences.getHost();
            int port = localPreferences.getPort();
            String protocol = localPreferences.getProtocol();
            boolean isValid = ModelUtil.hasLength( host ) && port != 0;
            if ( isValid )
            {
                if ( protocol.equals( "SOCKS" ) )
                {
                    System.setProperty( "socksProxyHost", host );
                    System.setProperty( "socksProxyPort", String.valueOf(port));
                }
                else
                {
                    System.setProperty( "http.proxySet", "true" );
                    // Set https settings
                    System.setProperty( "https.proxyHost", host );
                    System.setProperty( "https.proxyPort", String.valueOf(port));
                    // Set http settings
                    System.setProperty( "http.proxyHost", host );
                    System.setProperty( "http.proxyPort", String.valueOf(port));
                }
            }
            else
            {
                localPreferences.setProxyEnabled( false );
            }
        }
    }
}
