/*
 * The contents of this file are subject to the terms of the Common Development
 * and Distribution License (the License). You may not use this file except in
 * compliance with the License.
 *
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
 * or http://www.netbeans.org/cddl.txt.
 * 
 * When distributing Covered Code, include this CDDL Header Notice in each file
 * and include the License file at http://www.netbeans.org/cddl.txt.
 * If applicable, add the following below the CDDL Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 *
 * The Original Software is NetBeans. The Initial Developer of the Original
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.modules.autoupdate.catalog;

import java.awt.Component;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.netbeans.Module;
import org.openide.DialogDisplayer;
import org.openide.ErrorManager;
import org.openide.NotifyDescriptor;
import org.openide.nodes.Node;
import org.openide.util.NbBundle;
import org.openide.util.RequestProcessor;

/**
 *
 * @author Jiri Rechtacek
 */
class ModuleNodeUtils {
    
    /** Creates a new instance of ModuleNodeUtils */
    private ModuleNodeUtils () {
    }
    
    static private Set/*<ModuleNode.Item>*/ getCategoryModules (Node category) {
        assert ! category.isLeaf () : "Parent " + category + " cannot be leaf.";
        Set modules = new HashSet ();
        Node [] chNodes = category.getChildren ().getNodes (true);
        for (int i = 0; i < chNodes.length; i++) {
            if (chNodes [i] instanceof ModuleNode.Item) {
                modules.add (chNodes [i]);
            }
        }
        return modules;
    }
    
    static Set/*<ModuleNode.Item>*/ getAllSelectedModuleItems (Node [] nodes) {
        Set/*<Module>*/ modules = new HashSet ();
        
        for (int i = 0; i < nodes.length; i++) {
            if (nodes [i] instanceof ModuleNode.Item) {
                modules.add (nodes [i]);
            } else if (! nodes [i].isLeaf ()) {
                modules.addAll (getCategoryModules (nodes [i]));
            }
        }
        
        return modules;
    }    
    
    static Set/*<ModuleBean>*/ getAllSelectedModuleBeans (Node [] nodes) {
        Set/*<ModuleBean>*/ beans = new HashSet ();
        
        for (int i = 0; i < nodes.length; i++) {
            if (nodes [i] instanceof ModuleNode.Item) {
                beans.add (((ModuleNode.Item)nodes [i]).getItem ());
            } else if (! nodes [i].isLeaf ()) {
                beans.addAll (getAllSelectedModuleBeans (nodes [i].getChildren ().getNodes (true)));
            }
        }
        
        return beans;
    }
    
    static Boolean isEnableCandidate (Node [] nodes) {
        Iterator /*<ModuleBeans>*/ beans = getAllSelectedModuleBeans (nodes).iterator ();
        Boolean res = null;
        while (beans.hasNext ()) {
            ModuleBean b = (ModuleBean) beans.next ();
            if (res == null) {
                res = b.isEnabled () ? Boolean.FALSE : Boolean.TRUE;
            } else {
                if (res.booleanValue () == b.isEnabled ()) {
                    // mixed value
                    return null;
                }
            }
        }
        return res;
    }
    
    static boolean isEnableAllowed (Module m) {
        if (! m.isValid ()) return false;
        return ! ( ! (m.getProblems ().isEmpty ()) || m.isAutoload () || m.isEager () || m.getJarFile () == null );
    }
    
    static String getUninstallActionName (Node [] activatedNodes, String oldName) {
        if (activatedNodes == null || activatedNodes.length == 0) {
            return oldName;
        }
        
        String name;
        // special handling of category
        if (activatedNodes.length == 1 && ! (activatedNodes [0] instanceof ModuleNode.Item)) {
            name = NbBundle.getMessage (ModuleNodeActions.class, "CTL_ModuleNodeActions_UninstallAction", // NOI18N
                        activatedNodes [0].getDisplayName ()); // NOI18N
        } else {
            Set/*<ModuleNode.Item>*/ items = ModuleNodeUtils.getAllSelectedModuleItems (activatedNodes);
            name = NbBundle.getMessage (ModuleNodeActions.class, "CTL_ModuleNodeActions_UninstallAction", // NOI18N
                        items.size () > 1 ?
                            NbBundle.getMessage (ModuleNodeActions.class, "CTL_ModuleNodeActions_UninstallAction_many") : // NOI18N
                            ((ModuleNode.Item) items.iterator ().next ()).getDisplayName ());
        }
        
        return name;
    }
    
    static boolean canUninstall (Node[] activatedNodes) {
            if (activatedNodes == null || activatedNodes.length == 0) {
                return false;
            }

            Set/*<ModuleNode.Item>*/ items = ModuleNodeUtils.getAllSelectedModuleItems (activatedNodes);

            boolean res = ! items.isEmpty ();
            Iterator it = items.iterator ();
            String moduleName = null;
            while (res && it.hasNext ()) {
                Object n = it.next ();
                assert n instanceof ModuleNode.Item : "Object " + n + " is instanceof ModuleNode.Item";
                Module m = ((ModuleNode.Item) n).getItem ().getModule ();
                res = res && ((Node) n).canDestroy ();
                moduleName = m.getDisplayName ();
            }

            return res;
    }

    static void doUninstall (final Node[] activatedNodes) {
        if (confirmUninstall (activatedNodes)) {
            ModuleSelectionPanel.getGUI (false).setWaitingState (true, true);
            RequestProcessor.getDefault ().post (new Runnable () {
                public void run () {
                    uninstallNodes (activatedNodes);
                }
            });
        }
    }
    
    static boolean confirmUninstall (Node[] activatedNodes) {
        assert activatedNodes != null : "Any ModuleNode must be selected";

        Set/*<ModuleNode.Item>*/ items = ModuleNodeUtils.getAllSelectedModuleItems (activatedNodes);

        assert ! items.isEmpty () : "Any module must be selected";

        String category = null;
        if (activatedNodes.length == 1 && ! (activatedNodes [0] instanceof ModuleNode.Item)) {
            category = activatedNodes [0].getDisplayName ();
        }

        Iterator/*<ModuleNode.Item>*/ it = items.iterator ();
        Set/*<Module>*/ modules = new HashSet (items.size ());
        while (it.hasNext ()) {
            modules.add (((ModuleNode.Item)it.next ()).getItem ().getModule ());
        }

        Component c = new ModuleUninstallPanel (modules, category);
	c.getAccessibleContext ().setAccessibleDescription (
			NbBundle.getMessage (ModuleSelectionPanel.class, "ACD_ModuleUninstallPanel_form")); // NOI18N

        NotifyDescriptor nd = new NotifyDescriptor.Confirmation (c,
                        NbBundle.getMessage (ModuleSelectionPanel.class, "CTL_ModuleUninstallPanel_UninstallConfirmation"),
                        NotifyDescriptor.YES_NO_OPTION);

        return NotifyDescriptor.YES_OPTION.equals (DialogDisplayer.getDefault ().notify (nd));
    }

    static private void uninstallNodes (Node[] nodes) {
        assert nodes != null : "uninstallNodes cannot be called on null nodes.";
        for (int i = 0; i < nodes.length; i++) {
            if (nodes [i].isLeaf ()) {
                assert nodes [i] instanceof ModuleNode.Item : "Node " + nodes [i] + " instanceof ModuleNode.Item";
                ((ModuleNode.Item) nodes [i]).uninstall ();
            } else {
                uninstallNodes (nodes [i].getChildren ().getNodes (true));
            } 
        }
    }
    
}
