package com.chrisfolger.needsmoredojo.intellij.configurable;

import com.chrisfolger.needsmoredojo.core.amd.autodetection.SourcesAutoDetector;
import com.chrisfolger.needsmoredojo.core.amd.filesystem.SourcesLocator;
import com.chrisfolger.needsmoredojo.core.settings.DojoSettings;
import com.intellij.ide.DataManager;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.ComponentWithBrowseButton;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.TextComponentAccessor;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Collection;

public class DojoSettingsConfigurable implements Configurable {
    private JComponent myComponent;
    private JButton autoDetectDojoSources;
    private JPanel myPanel;
    private TextFieldWithBrowseButton projectSourcesText;
    private TextFieldWithBrowseButton dojoSourcesText;
    private JTable moduleExceptionsTable;
    private JButton addMapping;
    private JTextField addModuleText;
    private JTextField addParameterText;
    private JButton removeMapping;
    private JCheckBox preferRelativePathsWhenCheckBox;
    private JButton autoDetectProjectSources;
    private JTable removeUnusedImportExceptionsTable;
    private JTextField addRUIExceptionModuleText;
    private JTextField addRUIExceptionParameterText;
    private JButton addRUIModule;
    private JButton removeRUIModule;
    private JCheckBox dojoSourcesIsTheSame;
    private JCheckBox pluginEnabled;
    private JCheckBox addModulesIfThereAreNoneDetected;
    private JCheckBox allowCaseInsensitiveSearch;
    private JTextField supportedFileTypes;
    private JCheckBox displayWarningIfSourcesCheckBox;
    private JCheckBox enableRefactoringSupportForCheckBox;
    private JRadioButton singleQuotesRadioButton;
    private JRadioButton doubleQuotesRadioButton;
    private ButtonGroup quotesButtonGroup;
    private Project project;
    private String dojoSourceString;
    private String projectSourceString;
    private DojoSettings settingsService;
    private boolean modified = false;
    private boolean initialized = false;

    public String getDisplayName() {
        return "Needs More Dojo";
    }

    public boolean isModified() {
        return modified;
    }

    private class ProjectSourcesChosen extends ComponentWithBrowseButton.BrowseFolderActionListener<JTextField>
    {
        public ProjectSourcesChosen(@Nullable String title, @Nullable String description, FileChooserDescriptor fileChooserDescriptor) {
            super(title, description, projectSourcesText, null, fileChooserDescriptor, TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            super.actionPerformed(e);

            projectSourceString = projectSourcesText.getText().replace('\\', '/');;
            projectSourcesText.setText(projectSourceString);
        }
    }

    private class AutoDetectDojoSources implements ActionListener
    {
        @Override
        public void actionPerformed(ActionEvent e)
        {
            autoDetectDojoSources.setEnabled(false);
            VirtualFile directory = SourcesLocator.getDojoSourcesDirectory(project, false);

            if(directory == null)
            {
                Messages.showInfoMessage("Could not find any dojo sources via auto-detection", "Auto-detect Dojo Sources");
                autoDetectDojoSources.setEnabled(true);
                return;
            }

            dojoSourcesText.setText(directory.getCanonicalPath());
            dojoSourceString = directory.getCanonicalPath();
            autoDetectDojoSources.setEnabled(true);

            updateModifiedState();
        }
    }

    private class DojoSourcesChosen extends ComponentWithBrowseButton.BrowseFolderActionListener<JTextField>
    {
        public DojoSourcesChosen(@Nullable String title, @Nullable String description, FileChooserDescriptor fileChooserDescriptor) {
            super(title, description, dojoSourcesText, null, fileChooserDescriptor, TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            super.actionPerformed(e);

            dojoSourceString = dojoSourcesText.getText().replace('\\', '/');
            dojoSourcesText.setText(dojoSourceString);
        }
    }

    private class TextChangedListener implements KeyListener
    {
        @Override
        public void keyTyped(KeyEvent e) {
        }

        @Override
        public void keyPressed(KeyEvent e) {}

        @Override
        public void keyReleased(KeyEvent e) {
            updateModifiedState();
        }
    }

    private void updateModifiedState()
    {
        modified = !dojoSourcesText.getText().equals(settingsService.getDojoSourcesDirectory()) ||
                !projectSourcesText.getText().equals(settingsService.getProjectSourcesDirectory()) ||
                preferRelativePathsWhenCheckBox.isSelected() != settingsService.isPreferRelativeImports() ||
                dojoSourcesIsTheSame.isSelected() != settingsService.isDojoSourcesShareProjectSourcesRoot() ||
                pluginEnabled.isSelected() != settingsService.isNeedsMoreDojoEnabled() ||
                addModulesIfThereAreNoneDetected.isSelected() != settingsService.isAddModuleIfThereAreNoneDefined() ||
                allowCaseInsensitiveSearch.isSelected() != settingsService.isAllowCaseInsensitiveSearch() ||
                !supportedFileTypes.getText().equals(settingsService.getSupportedFileTypes()) ||
                enableRefactoringSupportForCheckBox.isSelected() != settingsService.isRefactoringEnabled() ||
                singleQuotesRadioButton.isSelected() != settingsService.isSingleQuotedModuleIDs() ||
                // this flag is true if it's unchecked
                displayWarningIfSourcesCheckBox.isSelected() == settingsService.isSetupWarningDisabled();

    }

    public JComponent createComponent() {
        myComponent = (JComponent) myPanel;
        FileChooserDescriptor projectDescriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
        // have to use a custom one to allow jar file contents to be selected
        FileChooserDescriptor dojoDescriptor = new FileChooserDescriptor(true, true, true, false, true, false);

        projectSourcesText.addBrowseFolderListener(null, new ProjectSourcesChosen("Project Sources", "Select the root of your project's sources to support certain features of Needs More Dojo", projectDescriptor));
        dojoSourcesText.addBrowseFolderListener(null, new DojoSourcesChosen("Dojo Sources", "Select the root of the dojo library sources to support certain features of Needs More Dojo", dojoDescriptor));

        autoDetectDojoSources.addActionListener(new AutoDetectDojoSources());

        // don't know how else to get the current project???
        DataContext context = DataManager.getInstance().getDataContext();
        final Project project = PlatformDataKeys.PROJECT.getData(context);
        this.project = project;

        settingsService = ServiceManager.getService(project, DojoSettings.class);

        dojoSourceString = settingsService.getDojoSourcesDirectory();
        dojoSourcesText.setText(dojoSourceString);

        projectSourceString =settingsService.getProjectSourcesDirectory();
        projectSourcesText.setText(projectSourceString);

        final ExceptionsListTableBuilder builder = new ExceptionsListTableBuilder(moduleExceptionsTable, project, settingsService.getAmdImportNamingExceptionsList());
        final ExceptionsTableBuilder ruiBuilder = new ExceptionsTableBuilder(removeUnusedImportExceptionsTable, project, settingsService.getRuiImportExceptions());

        addMapping.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                builder.getTableModel().addRow(new String[] { addModuleText.getText(), addParameterText.getText()});
            }
        });

        addRUIModule.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                ruiBuilder.getTableModel().addRow(new String[] { addRUIExceptionModuleText.getText(), addRUIExceptionParameterText.getText()});
            }
        });

        removeRUIModule.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                ruiBuilder.getTableModel().removeRow(removeUnusedImportExceptionsTable.getSelectedRow());
            }
        });

        removeMapping.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                builder.getTableModel().removeRow(moduleExceptionsTable.getSelectedRow());
            }
        });

        autoDetectProjectSources.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                autoDetectProjectSources.setEnabled(false);
                addAutoDetectedSource(new SourcesAutoDetector().getPossibleSourceRoots(project));
                autoDetectProjectSources.setEnabled(true);
                updateModifiedState();
            }
        });

        preferRelativePathsWhenCheckBox.setSelected(settingsService.isPreferRelativeImports());
        dojoSourcesIsTheSame.setSelected(settingsService.isDojoSourcesShareProjectSourcesRoot());
        addModulesIfThereAreNoneDetected.setSelected(settingsService.isAddModuleIfThereAreNoneDefined());

        pluginEnabled.setSelected(settingsService.isNeedsMoreDojoEnabled());
        updatePluginEnabledUI();
        initialized = true;

        dojoSourcesText.getTextField().addKeyListener(new TextChangedListener());
        projectSourcesText.getTextField().addKeyListener(new TextChangedListener());

        addModulesIfThereAreNoneDetected.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                updateModifiedState();
            }
        });
        allowCaseInsensitiveSearch.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                updateModifiedState();
            }
        });
        enableRefactoringSupportForCheckBox.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                updateModifiedState();
            }
        });
        displayWarningIfSourcesCheckBox.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent e) {
                updateModifiedState();
            }
        });

        preferRelativePathsWhenCheckBox.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                updateModifiedState();
            }
        });

        supportedFileTypes.addKeyListener(new TextChangedListener());

        pluginEnabled.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                updateModifiedState();
                updatePluginEnabledUI();
            }
        });

        dojoSourcesIsTheSame.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                updateSourcesEnabledState();
                updateModifiedState();
            }
        });

        quotesButtonGroup = new ButtonGroup();
        quotesButtonGroup.add(singleQuotesRadioButton);
        quotesButtonGroup.add(doubleQuotesRadioButton);

        singleQuotesRadioButton.addActionListener( new ActionListener()
        {
            @Override
            public void actionPerformed( ActionEvent e )
            {
                updateModifiedState();
            }
        } );

        doubleQuotesRadioButton.addActionListener( new ActionListener()
        {
            @Override
            public void actionPerformed( ActionEvent e )
            {
                updateModifiedState();
            }
        } );

        return myComponent;
    }

    public Icon getIcon()
    {
        return null;
    }

    private void updateSourcesEnabledState()
    {
        if(dojoSourcesIsTheSame.isSelected())
        {
            dojoSourcesText.setEnabled(false);
        }
        else
        {
            dojoSourcesText.setEnabled(true);
        }
    }

    private void addAutoDetectedSource(Collection<String> possibleSourceRoots)
    {
        String[] choices = possibleSourceRoots.toArray(new String[0]);

        if(choices.length == 0)
        {
            Messages.showInfoMessage("Could not find any source roots via auto-detection", "Auto-detect Project Sources");
            return;
        }

        String result = choices[0];
        if(choices.length > 1)
        {
            result = Messages.showEditableChooseDialog("Found these possible source roots: ", "Auto-detect Project Sources", null, choices, choices[0], null);
            if(result == null || result.equals(""))
            {
                return;
            }

            if(result.contains("(") && result.contains(")"))
            {
                result = result.substring(result.indexOf('(') + 1, result.indexOf(')'));
            }
        }
        else if (choices.length == 1)
        {
            if(result.contains("(") && result.contains(")"))
            {
                result = result.substring(result.indexOf('(') + 1, result.indexOf(')'));
            }
        }

        projectSourceString = result;
        projectSourcesText.setText(result);
    }

    public void apply()
    {
        if(dojoSourcesText.getText() != null)
        {
           settingsService.setDojoSourcesDirectory(dojoSourcesText.getText());
        }

        if(projectSourcesText.getText() != null)
        {
           settingsService.setProjectSourcesDirectory(projectSourcesText.getText());
        }

        settingsService.setPreferRelativeImports(preferRelativePathsWhenCheckBox.isSelected());
        settingsService.setDojoSourcesShareProjectSourcesRoot(dojoSourcesIsTheSame.isSelected());
        settingsService.setNeedsMoreDojoEnabled(pluginEnabled.isSelected());
        settingsService.setAddModuleIfThereAreNoneDefined(addModulesIfThereAreNoneDetected.isSelected());
        settingsService.setAllowCaseInsensitiveSearch(allowCaseInsensitiveSearch.isSelected());
        settingsService.setSupportedFileTypes(supportedFileTypes.getText());
        settingsService.setSetupWarningDisabled(!displayWarningIfSourcesCheckBox.isSelected());
        settingsService.setRefactoringEnabled(enableRefactoringSupportForCheckBox.isSelected());
        settingsService.setSingleQuotedModuleIDs(singleQuotesRadioButton.isSelected());

        modified = false;
    }

    public void disposeUIResources() {

    }

    public String getHelpTopic() {
        return "";
    }

    public void reset()
    {
        dojoSourceString = settingsService.getDojoSourcesDirectory();
        dojoSourcesText.setText(dojoSourceString);
        dojoSourcesText.setEnabled(!settingsService.isDojoSourcesShareProjectSourcesRoot());
        dojoSourcesIsTheSame.setSelected(settingsService.isDojoSourcesShareProjectSourcesRoot());

        projectSourceString =settingsService.getProjectSourcesDirectory();
        projectSourcesText.setText(projectSourceString);
        pluginEnabled.setSelected(settingsService.isNeedsMoreDojoEnabled());

        preferRelativePathsWhenCheckBox.setSelected(settingsService.isPreferRelativeImports());
        addModulesIfThereAreNoneDetected.setSelected(settingsService.isAddModuleIfThereAreNoneDefined());
        allowCaseInsensitiveSearch.setSelected(settingsService.isAllowCaseInsensitiveSearch());
        supportedFileTypes.setText(settingsService.getSupportedFileTypes());
        displayWarningIfSourcesCheckBox.setSelected(!settingsService.isSetupWarningDisabled());
        enableRefactoringSupportForCheckBox.setSelected(settingsService.isRefactoringEnabled());
        if (settingsService.isSingleQuotedModuleIDs()) {
            singleQuotesRadioButton.setSelected(true);
        } else {
            doubleQuotesRadioButton.setSelected(true);
        }

        modified = false;
    }

    private void updatePluginEnabledUI()
    {
        if(!pluginEnabled.isSelected())
        {
            for(Component component : myPanel.getComponents())
            {
                if(!component.equals(pluginEnabled))
                {
                    component.setEnabled(false);
                }
            }
        }
        else
        {
            for(Component component : myPanel.getComponents())
            {
                if(!component.equals(pluginEnabled))
                {
                    component.setEnabled(true);
                }
            }

            // reset the dojo source textbox being enabled/disabled based on whether its checked as being
            // the same as project sources
            updateSourcesEnabledState();
        }
    }
}