/*
 * 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;


import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.Action;

import org.openide.nodes.Node;
import org.openide.nodes.AbstractNode;
import org.openide.util.NbBundle;
import org.openide.util.actions.CallableSystemAction;
import org.openide.util.HelpCtx;

/** The UpdateNode class holds static innerclasses ( Module, Group,
 * Children and wait. This class serves only like a namespace for
 * the innerclasses and defines some usefull constants.
 *
 * @author  Petr Hrebejk
 */
class UpdateNode extends Object {

    /** Iconbase for module Updates with new modules */
    private static final String NEW_MODULE_ICON_BASE = "org/netbeans/modules/autoupdate/resources/newModule"; // NOI18N
    /** Iconbase for module Updates with module updates */
    private static final String UPDATE_MODULE_ICON_BASE = "org/netbeans/modules/autoupdate/resources/updateModule"; // NOI18N
    /** Iconbase for module Updates with module updates */
    private static final String MODULE_GROUP_ICON_BASE = "org/openide/loaders/defaultFolder"; // NOI18N
    /** Iconbase for wait node */
    private static final String WAIT_ICON_BASE = "org/openide/src/resources/wait"; // NOI18N
    /** Iconbase for module purchased modules */
    private static final String PURCHASED_MODULE_ICON_BASE = "org/netbeans/modules/autoupdate/resources/purchasedModule"; // NOI18N
    /** Iconbase for AU servers */
    private static final String SERVER_ICON_BASE = "org/netbeans/modules/autoupdate/resources/updateAction"; // NOI18N
    /** Iconbase for local update */
    private static final String LOCAL_ICON_BASE = "org/openide/resources/localFS"; // NOI18N
    /** Iconbase for module Updates with module updates */
    private static final String LOCALE_MODULE_ICON_BASE = "org/netbeans/modules/autoupdate/resources/localeModule"; // NOI18N
    
    /** Private constructor, the class should have no instances */
    private UpdateNode() {
    }

    private static String getBundle( String key ) {
        return NbBundle.getMessage( UpdateNode.class, key );
    }
    
    /** Class for representing module update in the tree */
    static class Module extends AbstractNode {

        private ModuleUpdate moduleUpdate;
        static CallableSystemAction moduleAction = null;

        Module ( ModuleUpdate moduleUpdate ) {
            super( org.openide.nodes.Children.LEAF );

            this.moduleUpdate = moduleUpdate;

            setDisplayName( moduleUpdate.getName() );
            if ( moduleUpdate.isPurchased() )
                setIconBase( PURCHASED_MODULE_ICON_BASE );
            else if ( moduleUpdate instanceof L10NUpdate )
                setIconBase( LOCALE_MODULE_ICON_BASE );
            else
                setIconBase( moduleUpdate.isNew() ? NEW_MODULE_ICON_BASE : UPDATE_MODULE_ICON_BASE );

            getCookieSet().add( moduleUpdate );
        }
        
        CallableSystemAction getModuleAction() {
            if ( moduleAction == null )
                moduleAction = new ModuleAction();
            return moduleAction;
        }
        
        public Action getPreferredAction () {
            return getModuleAction ();
        }
        
        class ModuleAction extends CallableSystemAction {
            public void performAction() {
                Settings.getShared().fireNodeDefaultAction();
            }

            public HelpCtx getHelpCtx() {
                return null;
            }

            public String getName() {
                return null;
            }
            
            protected boolean asynchronous () {
                return false;
            }
            
        }
    }

    /** Class for representing module wait node */
    static class Wait extends AbstractNode {

        Wait ( ) {
            super( org.openide.nodes.Children.LEAF );

            setDisplayName( getBundle( "CTL_WaitNode" ) );
            setIconBase( WAIT_ICON_BASE );
        }
    }

    abstract static class FolderContent extends org.openide.nodes.Children.Keys {
        abstract void refreshContent(boolean recursive);

        final void refreshSubFolders() {
            Node[] nodes = getNodes();
            for ( int i=0; i < nodes.length; i++ ) {
                if ( nodes[i] instanceof Folder ) 
                    ( (Folder) nodes[i] ).refreshContent( true );
            }
        }
    }
    
    static class Folder extends AbstractNode {
        
        protected FolderContent folderContent;
        
        public Folder( FolderContent fc ) {
            super( fc );
            folderContent = fc;
        }
        
        final void refreshContent(boolean recursive) {
            folderContent.refreshContent( recursive );
        }

    }
    
    /** Class for representing module group in the tree */
    static class Group extends Folder {

        private ModuleGroup group;

        Group( ModuleGroup group ) {
            super( new UpdateNode.Children( group ) );

            this.group = group;

            setDisplayName( group.getName() );
            setIconBase( MODULE_GROUP_ICON_BASE );

            getCookieSet().add( group );
        }

    }

    /** Class for representing module group in the tree */
    static class Server extends Folder {

        Server( AutoupdateType at ) {
            super( new UpdateNode.ATChildren( at ) );

            setDisplayName( at.getName() );
            this.setIconBase( SERVER_ICON_BASE );

        }

    }
    
    /** Class for representing module group in the tree */
    static class LocalServer extends Folder {

        LocalServer( Object obj ) {
            super( new UpdateNode.ATChildren( obj ) );

            setDisplayName( getBundle( "LBL_LocalUpdate" ) );
            this.setIconBase( LOCAL_ICON_BASE );

        }

    }
    
    static AllServers getAllServers() {
        return new AllServers();
    }
    
    /** Class for representing module group in the tree */
    static class AllServers extends Folder {

        AllServers() {
            super( new UpdateNode.ASChildren() );            
        }

    }

    /** Holds children nodes of the module group */
    static class Children extends FolderContent {

        protected ModuleGroup moduleGroup;
        
        // CONSTRUCTORS -----------------------------------------------------------------------

        /** Creates module group children.
         * @param group The group of modules
         */ 

        public Children ( ModuleGroup moduleGroup ) {
            super();
            this.moduleGroup = moduleGroup;
            
            refreshContent( false );
        }
        
        /** Called when the preparation of nodes is needed
         */
        protected void addNotify() {
            //refreshAllKeys ();
        }

        /** Called when all children are garbage collected */
        protected void removeNotify() {
            setKeys( java.util.Collections.EMPTY_SET );
        }

        // IMPLEMENTATION of Children.Keys ------------------------------------------

        /** Creates nodes for given key.
        */
        protected Node[] createNodes( final Object key ) {

            if (key instanceof ModuleUpdate) {
                return new Node[] { new UpdateNode.Module( (ModuleUpdate)key ) };
            }
            else if (key instanceof ModuleGroup ) {
                return new Node[] { new UpdateNode.Group( (ModuleGroup)key ) };
            }
            else {
                // Unknown pattern
                return new Node[0];
            }
        }
        
        void refreshContent(boolean recursive) {
            ArrayList list = new java.util.ArrayList();
            Iterator it = moduleGroup.getItems().iterator();
            while ( it.hasNext() ) {
                Object ob = it.next();
                if (ob instanceof ModuleUpdate) {
                    ModuleUpdate mu = (ModuleUpdate) ob;
                    if (! mu.isSelected () && DependencyChecker.checkPlatformDependency (mu.getRemoteModule ())) {
                        list.add (mu);
                    }
                } else {
                    list.add (ob);
                }
            }
                    
            setKeys( list );
            if ( recursive )
                refreshSubFolders();
        }
        
    }
    
    /** Holds children nodes of the module group */
    static class ATChildren extends FolderContent {

        private Object autoupdateType;
        // CONSTRUCTORS -----------------------------------------------------------------------

        /** Creates module group children.
         * @param group The group of modules
         */ 

        public ATChildren ( Object obj ) {
            super();            
            this.autoupdateType = obj;
            refreshContent( false );
        }

        /** Called when the preparation of nodes is needed
         */
        protected void addNotify() {
            //refreshAllKeys ();
        }

        /** Called when all children are garbage collected */
        protected void removeNotify() {
            setKeys( java.util.Collections.EMPTY_SET );
        }

        // IMPLEMENTATION of Children.Keys ------------------------------------------

        /** Creates nodes for given key.
        */
        protected Node[] createNodes( final Object key ) {
            Node[] result;
            if (key instanceof ModuleUpdate) {
                result = new Node[] { new UpdateNode.Module( (ModuleUpdate)key ) };
            }
            else if (key instanceof ModuleGroup ) {
                result = new Node[] { new UpdateNode.Group( (ModuleGroup)key ) };
                // count the available modules in folder
                int countOfChildren = ((ModuleGroup)key).getItems ().size ();
                // if none available module then don't add empty folder
                if (countOfChildren == 0) result = new Node[0];
            }
            else {
                // Unknown pattern
                result =  new Node[0];
            }
            return result;
        }
        
        void refreshContent(boolean recursive) {
            ArrayList list = new java.util.ArrayList();
            ModuleGroup group = ((Updates)(Wizard.getAllUpdates().get( autoupdateType ))).getRootGroup();
            
            if (group != null) {
                Iterator it = group.getItems().iterator();
                while ( it.hasNext() ) {
                    Object ob = it.next();
                    if (( ob instanceof ModuleGroup ) ||
                            (ob instanceof ModuleUpdate && !((ModuleUpdate)ob).isSelected () &&
                            DependencyChecker.checkPlatformDependency (((ModuleUpdate) ob).getRemoteModule ())) )
                        list.add(ob);                    
                }
            }
                    
            setKeys( list );
            if ( recursive )
                refreshSubFolders();
        }
        
    }
    
    /** Holds children nodes of the module group */
    static class ASChildren extends FolderContent {

        // CONSTRUCTORS -----------------------------------------------------------------------

        /** Creates module group children.
         * @param group The group of modules
         */ 

        public ASChildren () {
            super();
            ArrayList list = new java.util.ArrayList();
            Iterator it = Wizard.getAllUpdates().keySet().iterator();
            while ( it.hasNext() ) {
                Object ob = it.next();
                list.add(ob);
            }
                    
            setKeys( list );
        }

        /** Called when the preparation of nodes is needed
         */
        protected void addNotify() {
            //refreshAllKeys ();
        }

        /** Called when all children are garbage collected */
        protected void removeNotify() {
            setKeys( java.util.Collections.EMPTY_SET );
        }

        // IMPLEMENTATION of Children.Keys ------------------------------------------

        /** Creates nodes for given key.
        */
        protected Node[] createNodes( final Object key ) {

            if (key instanceof AutoupdateType) {
                return new Node[] { new UpdateNode.Server( (AutoupdateType)key ) };
            }
            else {
                return new Node[] { new UpdateNode.LocalServer( key ) };
            }
        }
        
        void refreshContent(boolean recursive) {
            if ( recursive )
                refreshSubFolders();
        }
        
    }
}
