/*
 * 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 
 * https://glassfish.dev.java.net/public/CDDLv1.0.html or
 * glassfish/bootstrap/legal/CDDLv1.0.txt.
 * See the License for the specific language governing 
 * permissions and limitations under the License.
 * 
 * When distributing Covered Code, include this CDDL 
 * Header Notice in each file and include the License file 
 * at glassfish/bootstrap/legal/CDDLv1.0.txt.  
 * If applicable, add the following below the CDDL Header, 
 * with the fields enclosed by brackets [] replaced by
 * you own identifying information: 
 * "Portions Copyrighted [year] [name of copyright owner]"
 * 
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 */

package com.sun.enterprise.cli.commands;

import com.sun.enterprise.cli.framework.*;

import javax.management.ObjectName;
import javax.management.MBeanServerConnection;
import com.sun.enterprise.admin.common.ObjectNames;

// jdk imports
import java.io.File;
import java.util.Iterator;

/**
 *  Lists the submodules of a deployed component
 *  @version  $Revision: 1.3 $
 */
public class ListSubComponentsCommand extends S1ASCommand
{
    private static final String GET_MODULE_COMPONENTS = "getModuleComponents";
    private static final String APPNAME_OPTION        = "appname";
    private static final String TYPE_OPTION           = "type";
    private static final String EJBS                  = "ejbs";
    private static final String SERVLETS              = "servlets";
    private static final String EJB_SUB_MODULE        = "EJBModule|SessionBean|StatelessSessionBean|StatefulSessionBean|MessageDrivenBean|EntityBean";
    private static final String SERVLET_SUB_MODULE    = "WebModule|Servlet";
    private static final String TYPE_OPTION_VALUES    = "ejbs|servlets";

    /**
     *  An abstract method that validates the options 
     *  on the specification in the xml properties file
     *  This method verifies for the correctness of number of 
     *  operands and if all the required options are supplied by the client.
     *  @return boolean returns true if success else returns false
     */
    public boolean validateOptions() throws CommandValidationException
    {
        //Check if the type option arguments are valid ejbs|servlets
	final String typeOption = getOption(TYPE_OPTION);
        if ((typeOption != null) && !typeOption.matches(TYPE_OPTION_VALUES))
            throw new CommandValidationException(getLocalizedString(
                                                     "InvalidTypeOption"));
    	return super.validateOptions();
    }

    
    /**
     *  An abstract method that Executes the command
     *  @throws CommandException
     */
    public void runCommand() 
            throws CommandException, CommandValidationException
    {
	validateOptions();

        final String objectName = getObjectName();
	final String appname = getOption(APPNAME_OPTION);
	final String typeOption = getOption(TYPE_OPTION);
	final Object[] params = getParams(appname);
        final String[] types = getTypes(appname);

	//use http connector
	final MBeanServerConnection mbsc = getMBeanServerConnection(getHost(), getPort(), 
                                     getUser(), getPassword());
        try
        { 
	    //	    if (System.getProperty("Debug") != null) printDebug(mbsc, objectName);

	    Object returnValue = mbsc.invoke(new ObjectName(objectName), 
					     GET_MODULE_COMPONENTS, params, types);
	    printObjectName(returnValue, typeOption);
	    CLILogger.getInstance().printDetailMessage(getLocalizedString(
						       "CommandSuccessful",
						       new Object[] {name}));
        }
        catch(Exception e)
        { 
	    if (e.getLocalizedMessage() != null)
		CLILogger.getInstance().printDetailMessage(e.getLocalizedMessage());
            throw new CommandException(getLocalizedString("CommandUnSuccessful",
						     new Object[] {name} ), e);
        }        
    }


    /**
     *  Returns the paramters to use to pass into GET_MODULE_COMPONENTS method
     *  @param appname - appname  if appname is null then returns the paramter
     *  without appname.
     *  @return the parameter in Object[]
     */
    private Object[] getParams(String appname)
    {
	if (appname == null)
	{
	    return new Object[] {(String)getOperands().get(0)};
	}
	else
	{
	    return new Object[] {appname, (String)getOperands().get(0)};
	}
    }


    /**
     *  Returns the types to use for GET_MODULE_COMPONENTS method
     *  @param appname - appname  if appname is null then returns the type
     *  without appname.
     *  @return the type in String[]
     */
    private String[] getTypes(String appname)
    {
	if (appname == null)
	{
            return new String[] {String.class.getName()};
	}
	else
	{
            return new String[] {String.class.getName(), String.class.getName()};
	}
    }


    /**
     *  This method prints the object name.
     *  @param return value from operation in mbean
     */
    private void printObjectName(Object returnValue, String typeOption) 
                throws CommandException
    {
	if (returnValue == null) 
        {
                    CLILogger.getInstance().printDetailMessage(
                                                getLocalizedString("NoElementsToList"));
        }
	try 
	{
	    if (returnValue.getClass().getName().equals(STRING_ARRAY))
	    {
		final String[] objs = (String[])returnValue;
                boolean nothingToList = true;

		for (int ii=0; ii<objs.length; ii++)
		{
		    CLILogger.getInstance().printDebugMessage("***** " + objs[ii]);
		    final ObjectName on = new ObjectName(objs[ii]);
                    if (typeOption != null)
                    {
                        if ((typeOption.equals(EJBS) && 
                             on.getKeyProperty("j2eeType").matches(EJB_SUB_MODULE)) ||
                            (typeOption.equals(SERVLETS) && 
                             on.getKeyProperty("j2eeType").matches(SERVLET_SUB_MODULE)))
                        {
                            printSubComponent(on); 
                            nothingToList=false;
                        }
                    }
                    else 
                    {
                        printSubComponent(on); 
                        nothingToList=false;
                    }
                }
	        if (nothingToList) 
                {
                    CLILogger.getInstance().printDetailMessage(
                                                getLocalizedString("NoElementsToList"));
                }
            }
        }
	catch (Exception e)
	{
	    throw new CommandException(e);
	}
    }


    /** 
     * This method prints the sub component name 
     */
    private void printSubComponent(ObjectName on)
    {
        CLILogger.getInstance().printMessage(on.getKeyProperty("name") + " <"+
                                             on.getKeyProperty("j2eeType") + ">");
    }


    /** 
     * This method prints the objecName info for debugging purpose
     */
    private void printDebug(MBeanServerConnection mbsc, String objectName)
	throws Exception
    {
	CLILogger.getInstance().printDebugMessage("********** getMBeanInfo **********");
	final javax.management.MBeanInfo mbinfo = mbsc.getMBeanInfo(new ObjectName(objectName));
	CLILogger.getInstance().printDebugMessage("Description = " + mbinfo.getDescription());
	CLILogger.getInstance().printDebugMessage("Classname = " + mbinfo.getClassName());
        final javax.management.MBeanOperationInfo[] mboinfo = mbinfo.getOperations();
	for (int ii=0; ii<mboinfo.length; ii++) 
	{
	    CLILogger.getInstance().printDebugMessage("("+ii+") Description = " + 
						      mboinfo[ii].getDescription());
	    CLILogger.getInstance().printDebugMessage("("+ii+") Name = " + 
						      mboinfo[ii].getName());
	    CLILogger.getInstance().printDebugMessage("****** TYPE *****");
	    final javax.management.MBeanParameterInfo[]  mbpi  = mboinfo[ii].getSignature();
	    for (int kk=0; kk<mbpi.length; kk++)
	    {
		CLILogger.getInstance().printDebugMessage("type = " + mbpi[kk].getType());
	    }
 	    CLILogger.getInstance().printDebugMessage("returnType = " + mboinfo[ii].getReturnType());
	}
    }


}
