/***************************************
 *                                     *
 *  JBoss: The OpenSource J2EE WebOS   *
 *                                     *
 *  Distributable under LGPL license.  *
 *  See terms of license at gnu.org.   *
 *                                     *
 ***************************************/
package org.jboss.console.twiddle.command;

import gnu.getopt.Getopt;
import gnu.getopt.LongOpt;

import java.beans.PropertyEditor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import javax.management.Attribute;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;

import org.jboss.util.Strings;
import org.jboss.util.propertyeditor.PropertyEditors;


/**
 * Set the values of one MBean attribute.
 *
 * @author heiko.rupp@cellent.de
 * @version $Revision: 1.5 $
 */
public class SetCommand 
    extends MBeanServerCommand
{

    private ObjectName objectName;
    private List attributeNames = new ArrayList(5); 
    private boolean prefix = true;  
    private String query;

    public SetCommand()
    {
        super("set", "Set the value of one MBean attribute");
    }


   public void displayHelp()
   {
        PrintWriter out = context.getWriter();

        out.println(desc);
        out.println();
        out.println("usage: " + name + " [options] <name> <attr> <val>");
        out.println("options:");
        out.println("    --noprefix    Do not display attribute name prefixes");
        out.println("    --            Stop processing options");

        out.flush();
   }
   
    private boolean processArguments(final String[] args)
        throws CommandException
    {
        log.debug("processing arguments: " + Strings.join(args, ","));

        if (args.length == 0)
        {
            throw new CommandException("Command requires arguments");
        }

        String sopts = "-:";
        LongOpt[] lopts =
            {
                new LongOpt("noprefix", LongOpt.NO_ARGUMENT, null, 0x1000),
            };

        Getopt getopt = new Getopt(null, args, sopts, lopts);
        getopt.setOpterr(false);

        int code;
        int argidx = 0;

        while ((code = getopt.getopt()) != -1)
        {
            switch (code)
            {
                case ':':
                    throw new CommandException
                        ("Option requires an argument: " + args[getopt.getOptind() - 1]);

                case '?':
                    throw new CommandException
                        ("Invalid (or ambiguous) option: " + args[getopt.getOptind() - 1]);

                case 0x1000:
                    prefix = false;
                    break;
                  
                    // non-option arguments
                case 1:
                    {
                        String arg = getopt.getOptarg();

                        switch (argidx++)
                        {
                            case 0:
                                objectName = createObjectName(arg);
                                log.debug("mbean name: " + objectName);
                                break;

                            default:
                                log.debug("adding attribute name: " + arg);
                                attributeNames.add(arg);
                                break;
                        }
                        break;
                    }
            }
        }

        return true;
    }
   

   public void execute(String[] args) throws Exception
   {

        processArguments(args);
                
        String theAttr = (String)attributeNames.toArray()[0]; 
        String theVal = (String)attributeNames.toArray()[1]; 

        if (objectName == null)
            throw new CommandException("Missing object name");

        log.debug("attribute names: " + attributeNames);
        if (attributeNames.size() != 2 )
        {
            throw new CommandException("Wrong number of arguments");
        }
        MBeanServerConnection server = getMBeanServer();

        MBeanInfo info = server.getMBeanInfo(objectName);
        
        MBeanAttributeInfo[] attrs = info.getAttributes();
        
        MBeanAttributeInfo attr=null;

        boolean found = false;
        for (int i=0;i < attrs.length ; i++ ) 
        {           
            if (attrs[i].getName().equals(theAttr) && 
                attrs[i].isWritable()) {
                
                    found=true;
                    attr= attrs[i];
                    break;
                }
        }
        
        if (found == false)
        {
            
            throw new CommandException("No matching attribute found");
        }
        else 
        {
            Object oVal = convert(theVal,attr.getType());
            Attribute at = new Attribute(theAttr,oVal);
            server.setAttribute(objectName,at);
            
            // read the attribute back from the server
            if (!context.isQuiet())
            {
                PrintWriter out = context.getWriter();
                Object nat = server.getAttribute(objectName,theAttr);
                if (nat==null)
                    out.println("null");
                else 
                    if (prefix)
                        out.print(theAttr+"=");
                    out.println(nat.toString());
            }
        }
        

   }

    /**
     * Convert val into an Object of type type
     * @param val The given value
     * @param oType the wanted return type
     * @return the value in the correct representation
     * @throws Exception various :)
     */
    private Object convert (String val,String oType) throws Exception
    {
        PropertyEditor editor = PropertyEditors.getEditor(oType);
        editor.setAsText(val);
        return editor.getValue();       
    }
}