package com.daveme.chocolateCakePHP;

import com.daveme.chocolateCakePHP.ui.FullyQualifiedNameInsertHandler;
import com.daveme.chocolateCakePHP.ui.FullyQualifiedNameTextFieldCompletionProvider;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.util.textCompletion.TextFieldWithCompletion;
import com.jetbrains.php.completion.PhpCompletionUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.lang.reflect.InvocationTargetException;

class ConfigForm implements SearchableConfigurable {
    private Project project;
    private JPanel topPanel;
    private JCheckBox enableCake3SupportCheckBox;
    private JButton appNamespaceDefaultButton;
    private JTextField templateExtensionTextField;
    private JButton templateExtensionDefaultButton;
    private JCheckBox enableCake2SupportCheckBox;
    private JTextField cake2AppDirectoryTextField;
    private JButton cake2AppDirectoryDefaultButton;
    private JTextField cake2TemplateExtensionTextField;
    private JButton cake2TemplateExtensionDefaultButton;
    private TextFieldWithCompletion appNamespaceTextField;
    private JTextField appDirectoryTextField;
    private JButton appDirectoryDefaultButton;
    private JPanel cake3Panel;
    private JPanel cake2Panel;
     
    public ConfigForm(Project project) {
        this.project = project;
    }

    private void loadSettingsToUI(@NotNull Settings settings) {
        toggleCake3State(settings.getCake3Enabled());
        appDirectoryTextField.setText(settings.getAppDirectory());
        appNamespaceTextField.setText(settings.getAppNamespace());
        templateExtensionTextField.setText(settings.getCakeTemplateExtension());

        toggleCake2State(settings.getCake2Enabled());
        cake2TemplateExtensionTextField.setText(settings.getCakeTemplateExtension());
        cake2AppDirectoryTextField.setText(settings.getCake2AppDirectory());
    }

    private void copySettingsFromUI(@NotNull Settings settings) {
        SettingsState state = settings.getState();

        state.setCake3Enabled(enableCake3SupportCheckBox.isSelected());
        state.setAppDirectory(appDirectoryTextField.getText());
        state.setCakeTemplateExtension(templateExtensionTextField.getText());
        state.setAppNamespace(appNamespaceTextField.getText());

        state.setCake2Enabled(enableCake2SupportCheckBox.isSelected());
        state.setCake2TemplateExtension(cake2TemplateExtensionTextField.getText());
        state.setCake2AppDirectory(cake2AppDirectoryTextField.getText());

        settings.loadState(state);
    }

    @Override
    @NotNull
    @Nls
    public String getId() {
        return "ChocolateCakePHP.ConfigForm";
    }

    @Nls
    @Nullable
    public String getDisplayName() {
        return "Chocolate CakePHP";
    }

    @Override
    public void disposeUIResources() {
    }

    @Override
    @Nullable
    public JComponent createComponent() {
        Settings settings = Settings.getInstance(project);

        loadSettingsToUI(settings);
        final Settings defaults = Settings.getDefaults();

        appNamespaceDefaultButton.addActionListener(e ->
                this.appNamespaceTextField.setText(defaults.getAppNamespace())
        );
        appDirectoryDefaultButton.addActionListener(e ->
                this.appDirectoryTextField.setText(defaults.getAppDirectory())
        );
        templateExtensionDefaultButton.addActionListener(e ->
                this.templateExtensionTextField.setText(defaults.getCakeTemplateExtension())
        );
        cake2AppDirectoryDefaultButton.addActionListener(e ->
                this.cake2AppDirectoryTextField.setText(defaults.getCake2AppDirectory())
        );
        cake2TemplateExtensionDefaultButton.addActionListener(e ->
                this.cake2TemplateExtensionTextField.setText(defaults.getCake2TemplateExtension())
        );

        // Toggle enabled/disabled for panels based on checkboxes:
        enableCake3SupportCheckBox.addActionListener(e ->
            this.toggleCake3State(enableCake3SupportCheckBox.isSelected())
        );

        enableCake2SupportCheckBox.addActionListener(e ->
            this.toggleCake2State(enableCake2SupportCheckBox.isSelected())
        );

        return topPanel;
    }

    private void toggleCake3State(boolean enabled) {
        cake3Panel.setVisible(enabled);
        enableCake3SupportCheckBox.setSelected(enabled);
    }

    private void toggleCake2State(boolean enabled) {
        cake2Panel.setVisible(enabled);
        enableCake2SupportCheckBox.setSelected(enabled);
    }

    @Override
    public boolean isModified() {
        Settings originalSettings = Settings.getInstance(project);
        Settings newSettings = Settings.fromSettings(originalSettings);
        copySettingsFromUI(newSettings);
        return !newSettings.equals(originalSettings);
    }

    public void apply() {
        Settings settings = Settings.getInstance(project);
        copySettingsFromUI(settings);
    }

    private void createUIComponents() {
        FullyQualifiedNameInsertHandler insertHandler = new FullyQualifiedNameInsertHandler();
        try {
            SwingUtilities.invokeAndWait(() -> {
                PhpCompletionUtil.PhpFullyQualifiedNameTextFieldCompletionProvider completionProvider =
                        new FullyQualifiedNameTextFieldCompletionProvider(project, insertHandler);
                appNamespaceTextField = new TextFieldWithCompletion(
                        project,
                        completionProvider,
                        "",
                        true,
                        true,
                        true,
                        true
                );
            });
        } catch (InterruptedException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }

}

@@ -5366,53 +5366,457 @@
     
-SwingUtilities.invokeAndWait(() -%3E %7B%0A        
+if (!SwingUtilities.isEventDispatchThread()) %7B%0A                SwingUtilities.invokeAndWait(() -%3E %7B%0A                    setupHandler(insertHandler);%0A                %7D);%0A            %7D else %7B%0A                setupHandler(insertHandler);%0A            %7D%0A        %7D catch (InterruptedException %7C InvocationTargetException e) %7B%0A            e.printStackTrace();%0A        %7D%0A    %7D%0A%0A    private void setupHandler(FullyQualifiedNameInsertHandler insertHandler) %7B%0A
     
@@ -5923,24 +5923,16 @@
         
- 
-       
 new Full
@@ -5994,32 +5994,24 @@
 rtHandler);%0A
-        
         appN
@@ -6075,24 +6075,16 @@
         
-    
-    
 project,
@@ -6084,24 +6084,16 @@
 roject,%0A
-        
         
@@ -6140,28 +6140,12 @@
     
-       
- 
 %22%22,%0A
-        
     
@@ -6174,32 +6174,24 @@
             
-        
 true,%0A      
@@ -6196,32 +6196,24 @@
             
-  
-      
 true,%0A      
@@ -6218,32 +6218,24 @@
             
-    
-    
 true%0A       
@@ -6239,154 +6239,15 @@
     
-      
-  
 );%0A    
-        %7D);%0A        %7D catch (InterruptedException %7C InvocationTargetException e) %7B%0A            e.printStackTrace();%0A        %7D%0A    %7D%0A
+%7D
 %0A%7D%0A

Handle running on event dispatcher thread in config form