package org.jboss.installer.screens.jsf;

import org.apache.commons.lang3.StringUtils;
import org.jboss.installer.common.FileChooserPanel;
import org.jboss.installer.common.UiResources;
import org.jboss.installer.core.FileUtils;
import org.jboss.installer.core.LanguageUtils;
import org.jboss.installer.core.MnemonicUtils;
import org.jboss.installer.core.ValidationResult;
import org.jboss.installer.postinstall.task.JSFLibraryConfig;
import org.jboss.installer.validators.CombiningValidator;
import org.jboss.installer.validators.MavenRepositoryValidator;
import org.jboss.installer.validators.RepositoryContentValidator;
import org.jboss.installer.validators.Validator;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static javax.swing.JFileChooser.DIRECTORIES_ONLY;
import static org.jboss.installer.screens.DefaultScreen.DESCRIPTION_INSET;

class ExistingChannelPanel extends JPanel {
    public static final String MANIFEST_COORDINATE_LABEL_KEY = "jsf_install.manifest_coordinate.label";
    public static final String ADD_REPOSITORY_KEY = "jsf_install.add_repository.button";
    public static final String REMOVE_REPOSITORY_KEY = "jsf_install.remove_repository.button";
    public static final String SOURCE_REPOSITORY_LABEL_KEY = "jsf_install.source_repository.label";
    private static final String GENERIC_VALIDATION_EMPTY_FIELD = "generic.validation.empty_field";
    public static final String INVALID_COORDINATE_FORMAT = "jsf_install.manifest_coordinate_format";
    protected static final int MAX_REPOSITORY_URLS = 10;
    protected static final int MIN_REPOSITORY_URLS = 1;
    private final JTextField coordinateField;
    private final LanguageUtils langUtils;
    private final JButton addRepository;
    private final JButton removeRepository;
    private int activeRepositoryCounter = MIN_REPOSITORY_URLS;
    private final List<FileChooserPanel> repositoryChoosers = new ArrayList<>(MAX_REPOSITORY_URLS);

    public ExistingChannelPanel(LanguageUtils langUtils, MnemonicUtils mnemonicUtils) {
        super(new GridBagLayout());

        this.langUtils = langUtils;

        this.coordinateField = UiResources.createTextField("");

        addRepository = UiResources.createButton(langUtils.getString(ADD_REPOSITORY_KEY), this::addRepositoryUrlField);
        addRepository.setEnabled(activeRepositoryCounter < MAX_REPOSITORY_URLS);
        mnemonicUtils.findMnemonic(addRepository.getText()).ifPresent(addRepository::setMnemonic);
        removeRepository = UiResources.createButton(langUtils.getString(REMOVE_REPOSITORY_KEY), this::removeRepositoryUrlField);
        removeRepository.setEnabled(activeRepositoryCounter > MIN_REPOSITORY_URLS);
        mnemonicUtils.findMnemonic(removeRepository.getText()).ifPresent(removeRepository::setMnemonic);

        final GridBagConstraints c = UiResources.initializeConstraints();
        c.gridwidth = 2;
        c.weightx = 1;

        c.insets = DESCRIPTION_INSET;
        this.add(UiResources.createFieldLabel(langUtils.getString("jsf_install.existing_channel.desc")), c);

        c.gridy++;
        c.gridx = 0;
        c.gridwidth = 1;
        final JLabel coordinateLabel = UiResources.createFieldLabel(langUtils.getString(MANIFEST_COORDINATE_LABEL_KEY) + ": ");
        coordinateLabel.setToolTipText(langUtils.getString(MANIFEST_COORDINATE_LABEL_KEY + ".tooltip"));
        this.add(coordinateLabel, c);

        c.gridx = 1;
        c.gridwidth = 1;
        coordinateField.setToolTipText(langUtils.getString(MANIFEST_COORDINATE_LABEL_KEY + ".tooltip"));
        this.add(coordinateField, c);

        c.gridx = 0;
        c.gridwidth = 2;
        c.gridy++;
        final JLabel repositoryLabel = UiResources.createFieldLabel(langUtils.getString(SOURCE_REPOSITORY_LABEL_KEY) + ": ");
        repositoryLabel.setToolTipText(langUtils.getString(SOURCE_REPOSITORY_LABEL_KEY + ".tooltip"));
        this.add(repositoryLabel, c);

        c.insets = new Insets(0,0,0,0);
        for (int i = 0; i < MAX_REPOSITORY_URLS; i++) {
            final FileChooserPanel repositoryChooser = FileChooserPanel.builder(langUtils, DIRECTORIES_ONLY, mnemonicUtils).baseFolder("http://").build();
            c.gridy++;
            this.add(repositoryChooser, c);
            repositoryChooser.setToolTipText(langUtils.getString(SOURCE_REPOSITORY_LABEL_KEY + ".tooltip"));
            if (i < activeRepositoryCounter) {
                repositoryChooser.setVisible(true);
                repositoryChooser.setEnabled(true);
            } else {
                repositoryChooser.setVisible(false);
                repositoryChooser.setEnabled(false);
            }
            repositoryChoosers.add(repositoryChooser);
        }

        c.gridwidth = 1;
        c.gridy++;
        c.fill = GridBagConstraints.NONE;
        c.anchor = GridBagConstraints.EAST;

        this.add(addRepository, c);
        c.gridx = 1;
        c.anchor = GridBagConstraints.WEST;
        this.add(removeRepository, c);
        c.gridx = 0;

        this.revalidate();
    }

    private void removeRepositoryUrlField(ActionEvent a) {
        if (activeRepositoryCounter > MIN_REPOSITORY_URLS) {
            repositoryChoosers.get(activeRepositoryCounter - 1).setVisible(false);
            repositoryChoosers.get(activeRepositoryCounter - 1).setEnabled(false);
            activeRepositoryCounter--;
            if (!addRepository.isEnabled()) {
                addRepository.setEnabled(true);
            }
        }
        if (activeRepositoryCounter == MIN_REPOSITORY_URLS) {
            removeRepository.setEnabled(false);
        }
        if (removeRepository.isEnabled()) {
            removeRepository.requestFocus();
        } else {
            addRepository.requestFocus();
        }
        this.revalidate();
    }

    private void addRepositoryUrlField(ActionEvent a) {
        if (activeRepositoryCounter < MAX_REPOSITORY_URLS) {
            repositoryChoosers.get(activeRepositoryCounter).setVisible(true);
            repositoryChoosers.get(activeRepositoryCounter).setEnabled(true);
            repositoryChoosers.get(activeRepositoryCounter).requestFocus();

            Rectangle bounds = addRepository.getBounds();
            bounds = new Rectangle(bounds.x, bounds.y + repositoryChoosers.get(0).getHeight(), bounds.width, bounds.height);
            ((JComponent) addRepository.getParent()).scrollRectToVisible(bounds);

            if (!removeRepository.isEnabled()) {
                removeRepository.setEnabled(true);
            }

            activeRepositoryCounter++;
        }
        if (activeRepositoryCounter == MAX_REPOSITORY_URLS) {
            addRepository.setEnabled(false);
        }
        this.revalidate();
    }

    protected List<String> getSourceRepositoryValue() {
        return repositoryChoosers.stream()
                .filter(Component::isVisible)
                .map(UiResources::readTextValue)
                .collect(Collectors.toList());
    }

    protected String getManifestCoordinatesValue() {
        return UiResources.readTextValue(coordinateField);
    }

    public void populateConfig(JSFLibraryConfig config) {
        config.setRemoteMavenRepositoryUrls(getSourceRepositoryValue().stream()
                .filter(s->!StringUtils.isEmpty(s))
                .map(FileUtils::asUrl)
                .collect(Collectors.toList()));

        config.setJsfProject(JSFLibraryConfig.JsfProject.MyFaces);

        config.setManifestCoordinates(getManifestCoordinatesValue());
    }

    public ValidationResult validateInput() {
        final String manifestCoordinatesValue = getManifestCoordinatesValue();
        final List<String> sourceRepositoryValues = getSourceRepositoryValue();

        if (manifestCoordinatesValue == null || manifestCoordinatesValue.trim().isEmpty()) {
            return ValidationResult.error(langUtils.getString(GENERIC_VALIDATION_EMPTY_FIELD,
                    langUtils.getString(MANIFEST_COORDINATE_LABEL_KEY)));
        }
        if (sourceRepositoryValues.isEmpty()) {
            return ValidationResult.error(langUtils.getString(GENERIC_VALIDATION_EMPTY_FIELD,
                    langUtils.getString(SOURCE_REPOSITORY_LABEL_KEY)));
        }
        for (String sourceRepositoryValue : sourceRepositoryValues) {
            if (sourceRepositoryValue == null || sourceRepositoryValue.trim().isEmpty()) {
                return ValidationResult.error(langUtils.getString(GENERIC_VALIDATION_EMPTY_FIELD,
                        langUtils.getString(SOURCE_REPOSITORY_LABEL_KEY)));
            }
        }

        if (manifestCoordinatesValue.indexOf(':') < 0 || manifestCoordinatesValue.split(":").length > 2) {
            return ValidationResult.error(langUtils.getString(INVALID_COORDINATE_FORMAT));
        }

        final List<URL> repositoryUrls = sourceRepositoryValues.stream().map(FileUtils::asUrl).collect(Collectors.toList());
        final MavenRepositoryValidator repositoryValidator = new MavenRepositoryValidator(langUtils);
        return CombiningValidator.of(Stream.concat(
                sourceRepositoryValues.stream().map((repo)-> (Validator) () -> repositoryValidator.validate(repo)),
                Stream.of(()->new RepositoryContentValidator(langUtils).validateManifest(repositoryUrls,
                        manifestCoordinatesValue.split(":")[0], manifestCoordinatesValue.split(":")[1]))
                        ).collect(Collectors.toList())
                ).validate();
    }
}
