/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.netbeans.modules.micronaut.newproject;

import java.awt.Insets;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import org.openide.WizardDescriptor;
import org.openide.WizardValidationException;
import org.openide.util.AsyncGUIJob;
import org.openide.util.RequestProcessor;

/**
 * Options panel for Features step in Micronaut project wizard.
 *
 * @author Dusan Balek
 */
public class FeaturesVisual extends JPanel implements AsyncGUIJob {

    private final FeaturesWizardPanel panel;
    private boolean initialized = false;
    private boolean failed = false;
    private Map<String, List<FeatureTogglePanel>> featuresMap;

    public FeaturesVisual(FeaturesWizardPanel panel) {
        this.panel = panel;
        initComponents();
    }

    @Override
    public void addNotify() {
        super.addNotify();
        nestedPanel.requestFocus();
    }

    /** This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of
     * this method is always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        scrollPane = new javax.swing.JScrollPane();
        nestedPanel = new javax.swing.JPanel();

        scrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

        nestedPanel.setLayout(new java.awt.GridBagLayout());
        scrollPane.setViewportView(nestedPanel);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(scrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 556, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(scrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 298, Short.MAX_VALUE)
        );
    }// </editor-fold>//GEN-END:initComponents

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JPanel nestedPanel;
    private javax.swing.JScrollPane scrollPane;
    // End of variables declaration//GEN-END:variables

    boolean valid(WizardDescriptor wizardDescriptor) {
        if (failed) {
            wizardDescriptor.putProperty(WizardDescriptor.PROP_ERROR_MESSAGE, "Problems in contacting service!");
            return false;
        }
        wizardDescriptor.putProperty(WizardDescriptor.PROP_ERROR_MESSAGE, "");
        return initialized;
    }

    void store(WizardDescriptor wd) {
        Set<MicronautLaunchService.Feature> selectedFeatures = new LinkedHashSet<>();
        for (List<FeatureTogglePanel> toggles : featuresMap.values()) {
            for (FeatureTogglePanel toggle : toggles) {
                if (toggle.isSelected()) {
                    selectedFeatures.add(toggle.getFeature());
                }
            }
        }
        wd.putProperty(MicronautProjectWizardIterator.FEATURES, selectedFeatures);
    }

    void read(WizardDescriptor wd) {
        Set<MicronautLaunchService.Feature> selectedFeatures = (Set<MicronautLaunchService.Feature>) wd.getProperty(MicronautProjectWizardIterator.FEATURES);
        if (selectedFeatures != null && !selectedFeatures.isEmpty()) {
            for (List<FeatureTogglePanel> toggles : featuresMap.values()) {
                for (FeatureTogglePanel toggle : toggles) {
                    toggle.setSelected(selectedFeatures.contains(toggle.getFeature()));
                }
            }
        }
    }

    void validate(WizardDescriptor d) throws WizardValidationException {
        // nothing to validate
    }

    @Override
    public void construct() {
        init();
        panel.wizardDescriptor.addPropertyChangeListener((evt) -> {
            if (evt.getPropertyName() == MicronautProjectWizardIterator.SERVICE_URL ||
                    evt.getPropertyName() == MicronautProjectWizardIterator.APPLICATION_TYPE) {
                refresh();
            }
        });
    }

    private void init() {
        try {
            featuresMap = new LinkedHashMap<>();
            panel.wizardDescriptor.putProperty(WizardDescriptor.PROP_INFO_MESSAGE, "Contacting service...");
            String serviceUrl = (String) panel.wizardDescriptor.getProperty(MicronautProjectWizardIterator.SERVICE_URL);
            MicronautLaunchService.ApplicationType appType = (MicronautLaunchService.ApplicationType) panel.wizardDescriptor.getProperty(MicronautProjectWizardIterator.APPLICATION_TYPE);
            for (MicronautLaunchService.Feature feature : MicronautLaunchService.getInstance().getFeatures(serviceUrl, appType)) {
                List<FeatureTogglePanel> toggles = featuresMap.computeIfAbsent(feature.getCategory(), (c) -> new ArrayList<>());
                toggles.add(new FeatureTogglePanel(feature));
            }
            java.awt.GridBagConstraints gridBagConstraints = new java.awt.GridBagConstraints();
            gridBagConstraints.gridx = 0;
            gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
            gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
            gridBagConstraints.weightx = 1.0;
            gridBagConstraints.insets = new Insets(4, 8, 0, 0);
            int i = 0;
            for (Map.Entry<String, List<FeatureTogglePanel>> entry : featuresMap.entrySet()) {
                gridBagConstraints.gridy = i++;
                JLabel label = new JLabel(entry.getKey());
                label.setFont(label.getFont().deriveFont(java.awt.Font.BOLD));
                nestedPanel.add(label, gridBagConstraints);
                for (FeatureTogglePanel toggle : entry.getValue()) {
                    gridBagConstraints.gridy = i++;
                    nestedPanel.add(toggle, gridBagConstraints);
                }
            }
            nestedPanel.revalidate();
            initialized = true;
        } catch (Exception ex) {
            panel.wizardDescriptor.putProperty(WizardDescriptor.PROP_ERROR_MESSAGE, "Could not query Micronaut Launch service");
            failed = true;
        }
    }

    @Override
    public void finished() {
        panel.fireChangeEvent();
    }

    private void refresh() {
        initialized = false;
        failed = false;
        nestedPanel.removeAll();
        RequestProcessor.getDefault().post(() -> {
            init();
            SwingUtilities.invokeLater(() -> {
                finished();
            });
        });
    }
}
