/*
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999-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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */
package org.ow2.jonas.webapp.jonasadmin.monitoring;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable;
import java.util.Iterator;

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.ow2.jonas.lib.management.domain.DomainMonitor;
import org.ow2.jonas.lib.management.domain.J2EEDomain;
import org.ow2.jonas.lib.management.domain.proxy.server.ServerProxy;
import org.ow2.jonas.lib.management.extensions.base.JonasManagementRepr;
import org.ow2.jonas.lib.management.extensions.server.ServerItem;
import org.ow2.jonas.lib.util.JonasObjectName;
import org.ow2.jonas.webapp.jonasadmin.JonasBaseAction;
import org.ow2.jonas.webapp.jonasadmin.common.BeanComparator;

/**
 * @author eyindanga
 *
 */
public class DaemonProxyClusterAction extends JonasBaseAction {



    @Override
    @SuppressWarnings("unchecked")
    public ActionForward executeAction(final ActionMapping p_Mapping,
            final ActionForm p_Form, final HttpServletRequest p_Request,
            final HttpServletResponse p_Response) throws IOException,
            ServletException {
        String isNotMonitoringStr=null;
        String sDomainName = m_WhereAreYou.getCurrentDomainName();
        String serverName = m_WhereAreYou.getAdminJonasServerName();
        DaemonProxyClusterForm oForm = (DaemonProxyClusterForm) p_Form;
        String name=null;
        try {

            //we may come from a
            isNotMonitoringStr = p_Request.getParameter("isNotMonitoring");
            if(isNotMonitoringStr == null) {
                isNotMonitoringStr = (String) p_Request.getAttribute("isNotMonitoring");
            }
            name = (String) p_Request.getAttribute("node");
            if(name==null) {
                //that means the request has been forwarded by another
                //and the current cluster daemon name attribute has already been set
                name = m_WhereAreYou.getCurrentClusterDaemonName();
            }
            if (name == null) {
                //requested by using the parameter attribute
                name = p_Request.getParameter("node");
            }
            ObjectName on = JonasObjectName.clusterDaemonProxy(sDomainName, name);
            m_WhereAreYou.setCurrentClusterDaemon(on);
            m_WhereAreYou.setCurrentClusterDaemonName(name);
            //the array list to contain the server list
            ArrayList al = null;
            //are all the servers already started ?
            boolean allStarted = true;
            //let know if no server is running
            boolean noneStarted = true;
            oForm.setName((String) JonasManagementRepr.getAttribute(on,
                    "Name", serverName));
            oForm.setState((String) JonasManagementRepr.getAttribute(on,
                    "State", serverName));
            oForm.setConServer((ArrayList) JonasManagementRepr.getAttribute(on,
                    "ControlledServersNames", serverName));
            oForm.setJmxUrl((String) JonasManagementRepr.getAttribute(on,
                    "ConnectionUrl", serverName));
            ArrayList<String> srvList=oForm.getConServer();

            oForm.setRunTimeSpecVendor((String) JonasManagementRepr.getAttribute(on,
                    "RunTimeSpecVendor", serverName));
            oForm.setRunTimeSpecVersion((String) JonasManagementRepr.getAttribute(on,
                    "RunTimeSpecVersion", serverName));
            oForm.setRunTimeVmName((String) JonasManagementRepr.getAttribute(on,
                    "RunTimeVmName", serverName));
            oForm.setRunTimeVmVendor((String) JonasManagementRepr.getAttribute(on,
                    "RunTimeVmVendor", serverName));
            oForm.setRunTimeVmVersion((String) JonasManagementRepr.getAttribute(on,
                    "RunTimeVmVersion", serverName));
            oForm.setOperatingSystemAvailableProcessors((String) JonasManagementRepr.getAttribute(on,
                    "OperatingSystemAvailableProcessors", serverName));
            oForm.setOperatingSystemName((String) JonasManagementRepr.getAttribute(on,
                    "OperatingSystemName", serverName));
            oForm.setOperatingSystemVersion((String) JonasManagementRepr.getAttribute(on,
                    "OperatingSystemVersion", serverName));
            oForm.setOperatingSystemArch((String) JonasManagementRepr.getAttribute(on,
                    "OperatingSystemArch", serverName));
            //getting dynamic remote host monitoring infos
            Hashtable<String, String> dynAttr = (Hashtable<String, String>) JonasManagementRepr.invoke(on, "dynamicRemoteHostInfos", null, null, serverName);

            if (srvList == null || dynAttr == null) {
                throw new Throwable("Can't get management information for cluster daemon " + name + ". Please check the domain configuration.");
            }

            buildFormRemoteInfos(dynAttr, oForm);
            DomainMonitor dm = J2EEDomain.getInstance().getDomainMonitor();
            al = new ArrayList();
            //are all the servers already started ?
            allStarted = true;
            //let know if no server is running
            noneStarted = true;
//			getting requested cluster daemon Administrated Jonas servers...
            for (Iterator it = dm.getServerList().iterator(); it.hasNext();) {
                ServerProxy proxy = (ServerProxy) it.next();
                if (srvList.contains(proxy.getName())) {
                    //if the server is in the clusterd.xml but not in the domain.xml
                    if (m_WhereAreYou.isSrvRemovedFromClusterd(name, proxy.getName())) {
                        //the server is no more affected to current clusterd
                        proxy.setClusterdaemon(null);

                    }else {
                        //the server is in clusterd.xml
                        if (proxy.getClusterDaemonName() == null) {
                            //the server is not in domain.xml file
                            proxy.setClusterdaemon(dm.findClusterDaemonProxy(name));
                        }

                    }

                }
                if(proxy.getClusterDaemonName()!=null) {

                    if(proxy.getClusterDaemonName().equals(name)) {
                        ObjectName myOn = ObjectName.getInstance(proxy.getJ2eeObjectName());
                        al.add(new ServerItem(myOn, proxy.getState(), proxy.getClusterDaemonName(),srvList.contains(proxy.getName())));
                        //no server is started we want to disable the startAll operation in the jsp
                        if (noneStarted) {
                            noneStarted=!proxy.getState().equals("RUNNING");
                        }
                        allStarted=(allStarted && proxy.getState().equals("RUNNING"));
                    }
                }
            }
            Collections.sort(al, new BeanComparator(new String[] {"name"}));
            //if a problem has happened while getting jmxUrl then :
            //forward the response to with default values
            p_Request.setAttribute("listServers", al);
            p_Request.setAttribute("allStarted", allStarted);
            p_Request.setAttribute("noneStarted", noneStarted);
            p_Request.setAttribute("isNotMonitoring", isNotMonitoringStr);
            m_Session.setAttribute("isNotMonitoring", isNotMonitoringStr);
        } catch (Throwable t) {
            addGlobalError(t);
            saveErrors(p_Request, m_Errors);
            return (p_Mapping.findForward("Global Error"));
        }
        // Forward to the jsp.
        return (p_Mapping.findForward("DaemonProxyCluster"));
    }

    private void buildFormRemoteInfos(final Hashtable<String,String> myHash, final DaemonProxyClusterForm oform) throws Exception {
//		Allocate memory to the Form objects that will contain the dynamic infos
        initDynFormObjects(oform);
        ClusterdAttribute attr = null;
        for (String str : myHash.keySet()) {
            Long val = new Long(myHash.get(str));
            String title = fromKey2Title(str);
            //converting the key into a title(word separated by spaces)
            attr = new ClusterdAttribute(title, val, null);
            if (str.contains("mory")&&(str.contains("Vm"))) {
                //it's a memory attribute
                oform.vmDynMemory.add(convertAttribValueFromByte(attr));
            } else if (str.contains("hread")){
//				it's a threading attribute
                oform.dynThread.add(attr);
            } else if (str.contains("oad")) {
//				it's a loading attribute
                oform.dynLoading.add(attr);
            }else if (str.contains("mory")) {
//				OS Dynamic memory attribute
                oform.osDynMemory.add(convertAttribValueFromByte(attr));
            }else {
//				Other Operating system(OS) attribute
                oform.dynOperatingSystem.add(attr);
            }


        }

    }

    /**
     * Convert a string representing a hastable key into a title (words separated bys spaces)
     * @param key the string key to convert
     * @return key converted in title
     */
    private String fromKey2Title(final String fkey) {
        if (fkey == null) {
            return "Key is null";
        }
        String key = null;
        try {
            key = formatKey(fkey);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        String ret = new String();
        for (int i = 0; i < key.length(); i++) {
            Character car = key.charAt(i);
            if (i == 0) {
//				upperCase for the first letter
                ret = ret.concat(car.toString().toUpperCase());
            } else if (!Character.isLowerCase(car)) {
//				beginning a new Word in the key
                // so we add a space character
                ret = ret.concat(" ");
                ret = ret.concat(car.toString());
            } else {
                ret = ret.concat(car.toString());
            }

        }
        return ret;
    }

    /**
     * used to delete 2 last characters of a key.
     * these characters were added on memory key to differenciate "VM" and "OS"
     * Memory Attributes.
     * @param key the key to format
     * @return formatted key
     * @throws Exception
     */
    @SuppressWarnings("unused")
    private String formatKey(final String key) throws Exception {
        String myStr = null;
        try {
            myStr = key.substring(0, key.length());
        } catch (NullPointerException e) {
            throw new Exception("String to Format is null");
        }
        return myStr;
    }
    /**
     * Allocate memory for the clusterd Form objects that will conatin
     * dynamic infos for remote host of current cluterd
     * @param oform The Cluster Daemon Form
     */
    private  void initDynFormObjects(final DaemonProxyClusterForm oform) {
        if (oform.dynLoading == null) {
            oform.dynLoading = new ArrayList<ClusterdAttribute>();
        }else {
            oform.dynLoading.clear();
        }
        if (oform.vmDynMemory == null) {
            oform.vmDynMemory = new ArrayList<ClusterdAttribute>();
        }else {
            oform.vmDynMemory.clear();
        }
        if ( oform.dynOperatingSystem == null) {
            oform.dynOperatingSystem = new ArrayList<ClusterdAttribute>();
        }else {
            oform.dynOperatingSystem.clear();
        }
        if ( oform.dynThread == null) {
            oform.dynThread = new ArrayList<ClusterdAttribute>();
        }else {
            oform.dynThread.clear();
        }
        if (oform.osDynMemory == null) {
            oform.osDynMemory = new ArrayList<ClusterdAttribute>();
        }else {
            oform.osDynMemory.clear();
        }


    }
    /**
     *
     * @param attr convert value fo this attribute
     * @return a clusterd attribute with correct converted value
     */
    private ClusterdAttribute convertAttribValueFromByte(final ClusterdAttribute attr)throws Exception{
        ClusterdAttribute attrib = null;
        try {
            attrib = new ClusterdAttribute(attr.name, null, null);
            if (attr.value >= 1024) {
                if (attr.value >= (1024 * 1024)) {
                    if (attr.value >= (1024 * 1024 * 1024)) {
//						Giga
attrib.setValue(attr.value /(1024 * 1024 * 1024));
attrib.setUnit("GB");
                    }else {
//						mega
                        attrib.setValue(attr.value /(1024 * 1024));
                        attrib.setUnit("MB");
                    }

                }else {
                    //Kb
                    attrib.setValue(attr.value /1024);
                    attrib.setUnit("KB");
                }

            } else {
                //B
                attrib.setValue(attr.value);
                attrib.setUnit("B");
            }

        }
        catch (final NullPointerException e) {
            throw new Exception("The attribute cannot be null "+e);
        }
        return attrib;
    }

}
