/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2007 Bull S.A.S.
 * Contact: jonas-team@ow2.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.webapp.jonasadmin.cmi;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.management.JMRuntimeException;
import javax.management.ObjectName;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.upload.FormFile;
import org.ow2.jonas.lib.management.extensions.base.JonasManagementRepr;
import org.ow2.jonas.lib.management.javaee.J2eeObjectName;
import org.ow2.jonas.lib.util.JonasObjectName;
import org.ow2.jonas.webapp.jonasadmin.JonasAdminJmx;
import org.ow2.jonas.webapp.jonasadmin.JonasBaseAction;

public class CmiObjectAction extends JonasBaseAction {
    /**
     * Size of Buffer
     */
    private static final int BUFFER_SIZE = 1024;
    @SuppressWarnings("unchecked")
    @Override
    public ActionForward executeAction(final ActionMapping p_Mapping, final ActionForm p_Form, final HttpServletRequest p_Request, final HttpServletResponse p_Response) throws IOException, ServletException {
        String sDomainName = m_WhereAreYou.getCurrentDomainName();
        String serverName = m_WhereAreYou.getCurrentJonasServerName();
        String forwardName = "displayCmiObjectInfo";
        String objName = p_Request.getParameter("objName");
        if (objName == null) {
            objName = m_WhereAreYou.getVar("objName");
        }else {
            m_WhereAreYou.addVar("objName", objName);
        }
        CmiObjectForm oForm = (CmiObjectForm) p_Form;
        String action = oForm.getAction();
        //set Text style for html texts.
        p_Request.setAttribute("htmlTextStyleLbPolicy", "htmlTextLbPolicy");
        p_Request.setAttribute("htmlTextStyleLbStrategy", "htmlTextLbPolicy");
        p_Request.setAttribute("htmlTextStyleMinPoolSize", "htmlText");
        p_Request.setAttribute("htmlTextStyleMaxPoolSize", "htmlText");
        try {
            ObjectName cmiOn = JonasObjectName.cmiServer(sDomainName, serverName);
            if (JonasAdminJmx.hasMBeanName(cmiOn, serverName)) {
                oForm.setName(objName);
                // Set clusterList = (Set)JonasManagementRepr.invoke(cmiOn, "getClusterNames", null, null, serverName);
                String[] signature = new String[5];
                signature[0] = "java.lang.String";
                String[] params = new String[5];
                params[0] = objName;

                if (action != null) {
                    if ("changeLBPolicy".equals(action)) {
                        String[] parameters = {objName, oForm.getCurrentLBPolicySelect()};
                        String[] sign = {"java.lang.String", "java.lang.String"};
                        JonasManagementRepr.invoke(cmiOn, "setPolicyClassName", parameters, sign, serverName);
                        p_Request.setAttribute("htmlTextStyleLbPolicy", "htmlTextLbPolicyChanged");
                    }else if ("loadLBPolicy".equals(action)) {
                        //change lbPolicy infos
                        sendFile(oForm, oForm.getNewLbPolicyClass(), "policy", cmiOn, p_Request);
                    }else if (action.equals("loadLBStrategy")) {
                        sendFile(oForm, oForm.getNewLbPolicyClass(), "strategy", cmiOn, p_Request);
                    }else if("changeLBStrategy".equals(action)){
                        String[] parameters = {objName, oForm.getCurrentLBStrategySelect()};
                        String[] sign = {"java.lang.String", "java.lang.String"};
                        JonasManagementRepr.invoke(cmiOn, "setStrategyClassName", parameters, sign, serverName);
                        p_Request.setAttribute("htmlTextStyleLbStrategy", "htmlTextLbPolicyChanged");
                    }else if("updateSimpleProperty".equals(action)){
                        updateSimpleProperty(oForm, cmiOn, serverName);
                    }else if("updateCurrentSimpleProperty".equals(action)) {
                        /**
                         * Update some attribute for presentation purposes.
                         */
                        updateSelectedSimpleProperty(oForm);
                        // Forward to the jsp.
                        return (p_Mapping.findForward(forwardName));
                    }
                }
                String[] parameters = {objName};
                String[] sign = {"java.lang.String"};
                oForm.setName(objName);
                oForm.setServerRefs((List)JonasManagementRepr.invoke(cmiOn, "getServerRefs", parameters, sign, serverName));
                String currentLB = (String)JonasManagementRepr.invoke(cmiOn, "getPolicyClassName", parameters, sign, serverName);
                oForm.setCurrentLBPolicy(new LBAttribute(currentLB, getSimpleClassName(currentLB)));
                currentLB = (String)JonasManagementRepr.invoke(cmiOn, "getStrategyClassName", parameters, sign, serverName);
                oForm.setCurrentLBStrategy(new LBAttribute(currentLB, getSimpleClassName(currentLB)));
                /**
                 * TODO: enable this when pool management will evolve.
                 */
                //oForm.setMinPoolSize(((Integer)JonasManagementRepr.invoke(cmiOn, "getMinPoolSize", parameters, sign, serverName)).intValue());
                oForm.setMaxPoolSize(((Integer)JonasManagementRepr.invoke(cmiOn,
                        "getMaxPoolSize", parameters, sign, serverName)).intValue());
                oForm.setMaxPoolWaiters(((Integer)JonasManagementRepr.invoke(cmiOn,
                        "getMaxPoolWaiters", parameters, sign, serverName)).intValue());
                oForm.setPoolTimeout(((Long)JonasManagementRepr.invoke(cmiOn,
                        "getPoolTimeout", parameters, sign, serverName)).longValue());
                oForm.setItfName((String)JonasManagementRepr.invoke(cmiOn, "getItfName", parameters, sign, serverName));
                oForm.setClusterName(((ClusterAttribute)m_Session.getAttribute("currentCmiCluster")).getName());
                try {
                    getSimpleProperties(objName, cmiOn, oForm, parameters, sign, serverName );
                } catch (Exception e) {
                    //Do nothing if failures occur while getting properties.
                }
                oForm.setAction(null);
            }else {
                //                    	cmi MBean is not registered
                p_Request.setAttribute("newcmi", false);
            }
        }catch (Throwable t) {
            addGlobalError(t);
            saveErrors(p_Request, m_Errors);
            return (p_Mapping.findForward("Global Error"));
        }
        // Forward to the jsp.
        return (p_Mapping.findForward(forwardName));
    }
    /**
     * Update selected simple property. used for presentation purposes.
     * @param form the form bean.
     */
    private void updateSelectedSimpleProperty(final CmiObjectForm form) {
        boolean stop = false;
        Iterator<ClusterPropertyAttribute> it = form.getSimpleProperties().iterator();
        ClusterPropertyAttribute attr = null;
        while(it.hasNext() && !stop) {
            attr = it.next();
            stop = attr.getName().equals(form.getCurrentSimpPropertySelect());
        }
        if(stop) {
            form.setCurrentSimpPropertyValue(attr.getValue().toString());
        }
    }

    /**
     * Update simple properties
     * @param form form bean
     * @param cmiOn cmi object name.
     */
    private void updateSimpleProperty(final CmiObjectForm form, final ObjectName cmiOn,
            final String serverName) throws JMRuntimeException {
        if(form.getCurrentSimpPropertyValue() != null) {
        String[] parameters = {form.getName(), form.getCurrentSimpPropertySelect(),
                form.getCurrentSimpPropertyValue()};
        String[] sign = {"java.lang.String", "java.lang.String", "java.lang.String"};
        JonasManagementRepr.invoke(cmiOn, "setStaticPropertyForPolicy", parameters, sign, serverName);
        }
    }
    /**
     * Get simple properties for the given clustered object.
     * @param objectName the clustered bean
     * @param cmiOn objecName to be used.
     * @param form the form to fill.
     * @param parameters invocation parameters
     * @param sign invocation signature.
     * @param the server where to invoke.
     */
    private void getSimpleProperties(final String objectName, final ObjectName cmiOn, final CmiObjectForm form,
            final String[] parameters, final String[] sign, final String serverName) throws JMRuntimeException {
        form.getSimpleProperties().clear();
        Set<String> properties = (Set<String>)JonasManagementRepr.invoke(cmiOn,
                "getPropertiesNamesForPolicy", parameters, sign, serverName);
        for (String property : properties) {
            String[] params = {objectName, property};
            String[] signature = {"java.lang.String", "java.lang.String"};
            Object attrValue = JonasManagementRepr.invoke(cmiOn, "getStaticPropertyForPolicy", params, signature, serverName);
            ClusterPropertyAttribute attr = new ClusterPropertyAttribute(property, attrValue);
            form.getSimpleProperties().add(attr);
        }
        /**
         * The first element will be displayed first.
         */
        if (!form.getSimpleProperties().isEmpty()) {
            ClusterPropertyAttribute attr = form.getSimpleProperties().iterator().next();
            form.setCurrentSimpPropertySelect(attr.getName());
            if (attr.getValue() != null) {
                form.setCurrentSimpPropertyValue(attr.getValue().toString());
            }else {
                form.setCurrentSimpPropertyValue(null);
            }

        }

    }

    /** Sends a file to the cmi server instance.
     * @param p_form current form
     * @param file The file to send
     * @param remoteMethodName The remote method name to invoke.
     * @param cmiOn
     * @param request
     */
    private void sendFile(final CmiObjectForm p_form, final FormFile file, final String remoteAttributeName,
            final ObjectName cmiOn, final HttpServletRequest request) {

        String serverName = m_WhereAreYou.getCurrentJonasServerName();
        // retrieve the file name
        String fileName = file.getFileName();

        // retrieve the content type
        String contentType = file.getContentType();

        // retrieve the file size
        String size = (file.getFileSize() + " bytes");


        // J2EE server MBean
        ObjectName j2eeServer = J2eeObjectName.J2EEServer(m_WhereAreYou.getCurrentDomainName(), serverName);

        // invoke method on the MBean
        String sentFile = null;
        InputStream inputStream = null;
        ByteArrayOutputStream baos = null;
        int len;
        try {
            inputStream = file.getInputStream();
            baos = new ByteArrayOutputStream();
            byte[] buf = new byte[BUFFER_SIZE];
            // Read bytes
            while ((len = inputStream.read(buf)) > 0) {
                baos.write(buf, 0, len);
            }
            byte[] bytesOfFile = baos.toByteArray();
            Object[] param = new Object[] {p_form.getName(),bytesOfFile, fileName, remoteAttributeName};
            String[] signature = {"java.lang.String", "[B", "java.lang.String", "java.lang.String"};
            sentFile = (String) JonasManagementRepr.invoke(j2eeServer, "receiveFile", param, signature, serverName);
        } catch (Exception e) {
            addGlobalError(e);
            saveErrors(request, m_Errors);
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (baos != null) {
                    baos.close();
                }
            } catch (Exception e) {
                getServlet().log("Cannot close streams", e);
            }

        }
        //destroy temporary file.
        file.destroy();
    }

    /**
     * get simple class name from a full class name. e.g org.toto.Titi --> Titi
     * @param fullClassName
     * @return
     */
    private String getSimpleClassName(final String fullClassName) {
        // TODO Auto-generated method stub
        for (int i = fullClassName.length() - 1; i >= 0; i--) {
            if (String.valueOf(fullClassName.charAt(i)).equals(".")) {
                return fullClassName.substring(i + 1, fullClassName.length());
            }
        }
        return fullClassName;
    }
}
