/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999 Bull S.A.
 * Contact: jonas-team@objectweb.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
 */

package org.objectweb.jonas.webapp.jonasadmin.joramplatform;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.servlet.http.HttpServletRequest;

import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.objectweb.jonas.jmx.JonasManagementRepr;
import org.objectweb.jonas.jmx.JonasObjectName;
import org.objectweb.jonas.jmx.JoramObjectName;
import org.objectweb.jonas.webapp.jonasadmin.JonasAdminJmx;
import org.objectweb.jonas.webapp.jonasadmin.deploy.BaseDeployAction;

import org.objectweb.joram.client.jms.admin.DeadMQueue;

/**
 * @author Adriana Danes
 */
public abstract class EditJoramBaseAction extends BaseDeployAction {

    ObjectName ejbServiceObjectName = null;

    /**
     * Treat specific case where Joram RAR was unloaded
     * @param t Exception to treat
     * @param pMapping provided by executeAction
     * @param pRequest provided by executeAction
     * @return
     */
    protected ActionForward treatError(Throwable pThrowable, ActionMapping pMapping, HttpServletRequest pRequest) {
        String throwableClassName = pThrowable.getClass().getName();
        Throwable t = null;
        if (throwableClassName.equals("javax.management.InstanceNotFoundException")) {
            t = new Throwable("No MBeans found for the Joram platform. Try to refresh!", pThrowable);
        } else if (throwableClassName.equals("javax.management.MalformedObjectNameException")) {
            t = new Throwable("This is not a valid name for a Joram MBean (" + pThrowable.getMessage() + ")", pThrowable);
        } else {
            pThrowable.printStackTrace();
            t = new Throwable("Joram platform exception (" + pThrowable.getMessage() + ")", pThrowable);
        }
        addGlobalError(t);
        saveErrors(pRequest, m_Errors);
        return (pMapping.findForward("Global Error"));
    }

    protected String getPathToExportRepository() {
        return m_WhereAreYou.getAdminJonasServerConfDir();
    }

    /**
     * Get the path to the joramAdmin.xml file
     * @return
     */
    protected String getPathToReloadJoramAdmin() {
        return m_WhereAreYou.getAdminJonasServerConfDir();
    }

    /**
     * Create a ItemDestination object from a String structured as follows:
     * type=queue/topic, name=destName, id=#x.y.z
     * @param joramAdminDestination String containing destination description
     * @param serverName the name of the JOnAS server to which the current JORAM server is connected
     * @return ItemDestination containing name, type, id and ObjectName of the MBean associated to the corresponding destination
     * @throws MalformedObjectNameException could not construct destination ObjectName
     */
    public ItemDestination getDestinationItem(String joramAdminDestination, String serverName) throws MalformedObjectNameException {
        ItemDestination destinationItem = new ItemDestination();
        ObjectName destinationOn = null;
        StringTokenizer st = new StringTokenizer(joramAdminDestination, ",");
        String type = null;
        String name = null;
        String id = null;
        String serverId = null;
        while (st.hasMoreTokens()) {
            // A couple has the following structure: key=value
            String couple = st.nextToken().trim();
            int index = couple.indexOf("=");
            String key = couple.substring(0, index);
            String value = couple.substring(index + 1, couple.length());
            if (key.equals("type")) {
                type = value;
                destinationItem.setType(type);
            }
            if (key.equals("name")) {
                name = value;
                destinationItem.setName(name);
            }
            if (key.equals("id")) {
                id = value;
                destinationItem.setId(id);
                int indexBefore = id.indexOf("#");
                int indexAfter = id.indexOf(".", indexBefore);
                serverId = id.substring(indexBefore + 1, indexAfter);
                destinationItem.setServerId(serverId);
            }
        }
        if (name != null && type != null && id != null) {
            if (type.equals("topic")) {
                destinationOn = JoramObjectName.joramTopic(name);
            } else if (type.equals("queue")) {
                destinationOn = JoramObjectName.joramQueue(name);
            }
            if (destinationOn != null
                    &&
                    JonasAdminJmx.hasMBeanName(destinationOn, serverName)) {
                destinationItem.setRegistered(true);
                // exists a destination MBean with the given type and name, check the id
                String foundId = (String) JonasManagementRepr.getAttribute(destinationOn, "Name", serverName);
                if (id.equals(foundId)) {
                    destinationItem.setOn(destinationOn);
                    boolean deps = hasDeps(name, serverName);
                    destinationItem.setUsed(deps);
                    destinationItem.setManageable(true);
                }
            }
        }
        return destinationItem;
    }
    /**
     * Create a ItemUser object from a String structured as follows:
     * User[anonymous]:#0.0.1035
     * @param joramAdminUser String containing user description
     * @param serverName the name of the JOnAS server to which the current JORAM server is connected
     * @return ItemUser containing name and ObjectName of the MBean associated to the corresponding user
     * @throws MalformedObjectNameException
     */
    protected ItemUser getUserItem(String joramAdminUser, String serverName) throws MalformedObjectNameException {
        ItemUser userItem = new ItemUser();
        joramAdminUser.trim();
        int indextBeforeName = joramAdminUser.indexOf("[");
        int indexAfterName = joramAdminUser.indexOf("]", indextBeforeName);
        String name = joramAdminUser.substring(indextBeforeName + 1, indexAfterName);
        if (!name.equals("root")) {
            userItem.setName(name);
            int indexBeforeId = joramAdminUser.indexOf(":", indexAfterName);
            String idString = joramAdminUser.substring(indexBeforeId + 1, joramAdminUser.length());
            userItem.setId(idString);
            userItem.setServerId(currentServerId(idString));
            name = name.concat("[");
            name = name.concat(idString);
            name = name.concat("]");
            ObjectName on = JoramObjectName.joramUser(name);
            if (JonasAdminJmx.hasMBeanName(on, serverName)) {
                userItem.setOn(on);
            }
        }
        return userItem;
    }

    /**
     * Return the ObjectName of the User MBean corresponding to a given agent id
     * @param userId Agent id for a user (#x.y.z.)
     * @param serverName the name of the JOnAS server to which the current JORAM server is connected
     * @return the Objectname of the User MBean having the ProxyId attribute equal to the userId
     */
    protected ObjectName getUserOn(String userId, String serverName) {
        ObjectName userOn = null; // to be determined
        ObjectName userOns = null; // template for User MBeans
        try {
            userOns = JoramObjectName.joramUsers();
            Iterator it = JonasManagementRepr.queryNames(userOns, serverName).iterator();
            while (it.hasNext()) {
                ObjectName on = (ObjectName) it.next(); // a user MBean
                String proxyId = (String) JonasManagementRepr.getAttribute(on, "ProxyId", serverName);
                if (proxyId.equals(userId)) {
                    // found the user
                    userOn = on;
                    break;
                }
            }
        } catch (MalformedObjectNameException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return userOn;
    }

    /**
     * Return the name of the User corresponding to a given agent id
     * @param userId Agent id for a user (#x.y.z.)
     * @param jonasServerName the name of the JOnAS server to which the current JORAM server is connected
     * @return the value of the name attribute of the User MBean having the ProxyId attribute equal to the userId
     */
    protected String getUserName(String userId, String jonasServerName) {
        String name = null; // to be determined
        ObjectName userOns = null; // template for User MBeans
        try {
            userOns = JoramObjectName.joramUsers();
            Iterator it = JonasManagementRepr.queryNames(userOns, jonasServerName).iterator();
            while (it.hasNext()) {
                ObjectName on = (ObjectName) it.next(); // a user MBean
                String proxyId = (String) JonasManagementRepr.getAttribute(on, "ProxyId", jonasServerName);
                if (proxyId.equals(userId)) {
                    // found the user
                    name = (String) JonasManagementRepr.getAttribute(on, "Name", jonasServerName);
                    break;
                }
            }
        } catch (MalformedObjectNameException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return name;
    }

    public void printDestination(ItemDestination dest, String serverName) {
        System.out.println("Destination in server JOnAS " + serverName + " :");
        System.out.println("- name " + dest.getName());
        System.out.println("- type " + dest.getType());
        System.out.println("- id " + dest.getId());
        System.out.println("- servrId " + dest.getServerId());
        System.out.println("- on " + dest.getOn());
    }

    void printUser(ItemUser user) {
        System.out.println("User:");
        System.out.println("- name " + user.getName());
        System.out.println("- id " + user.getId());
        System.out.println("- on " + user.getOn());
    }
    protected void initRefs(String jonasServerName) {
        String[] asParam = new String[1];
        String[] asSignature = new String[1];
        asSignature[0] = "java.lang.String";
        ejbServiceObjectName = JonasObjectName.ejbService();
        if (!JonasManagementRepr.isRegistered(ejbServiceObjectName,  jonasServerName)) {
            ejbServiceObjectName = null;
        }
    }

    protected boolean hasDeps(String pDestName, String jonasServerName) {
        boolean ret = false;
        String[] asParam = new String[1];
        String[] asSignature = new String[1];
        if (ejbServiceObjectName != null) {
            asParam[0] = pDestName;
            asSignature[0] = "java.lang.String";
            Set deps = (Set) JonasManagementRepr.invoke(
                    ejbServiceObjectName, "getJmsDestinationDependence",
                    asParam, asSignature, jonasServerName);
            if (!deps.isEmpty()) {
                ret = true;
            }
        }
        return ret;
    }

    /**
     * Determine the server Id from a String structure as follows:
     * id=#x.y.z. The serrver id to be returned is "y"
     * @param id #x.y.z
     * @return y
     */
    public static String currentServerId(String id) {
        String serverId = null;
        int indexBefore = id.indexOf(".");// first dod
        int indexAfter = id.indexOf(".", indexBefore + 1);// second dot
        serverId = id.substring(indexBefore + 1, indexAfter);
        return serverId;
    }

    protected void populateDestination(ObjectName destOn, DestinationForm oForm, String serverName) throws MalformedObjectNameException {
        oForm.setName(getStringAttribute(destOn, "AdminName"));
        //testReaderList(oForm);
        DeadMQueue dmq = (DeadMQueue) JonasManagementRepr.getAttribute(destOn, "DMQ", serverName);
        if (dmq != null) {
            // should be getAdminName() but not set in joram
            oForm.setDmq(dmq.getName());
        }
        oForm.setId(getStringAttribute(destOn, "Name"));
        oForm.setType(getStringAttribute(destOn, "Type"));
        boolean readable = getBooleanAttribute(destOn, "FreelyReadable");
        oForm.setFreelyReadable(readable);
        if (readable) {
            oForm.setReaderList(null);
        } else {
            List readerList = getListAttribute(destOn, "ReaderList");
            //oForm.setReaderList(getStringAttributeFromList(readerList));
            oForm.setReaderList(getBaseItemList(readerList, serverName));
        }
        boolean writeable = getBooleanAttribute(destOn, "FreelyWriteable");
        oForm.setFreelyWriteable(writeable);
        if (writeable) {
            oForm.setWriterList(null);
        } else {
            List writerList = getListAttribute(destOn, "WriterList");
            //oForm.setWriterList(getStringAttributeFromList(writerList));
            oForm.setWriterList(getBaseItemList(writerList, serverName));
        }
    }

    /**
     * Treat a list (Vector) of Joram user items (example: User[anonymous]:#0.0.1035)
     * @param inputList list of Joram user items
     * @return a list of user item objects (ItemUser type)
     * @throws MalformedObjectNameException
     */
    protected ArrayList getBaseItemList(List inputList, String serverName) throws MalformedObjectNameException {
        ArrayList arrayResult = new ArrayList();
        ArrayList arrayInput = null;
        try {
            arrayInput = (ArrayList) inputList;
        } catch (ClassCastException ce) {
            try {
                Vector vInputList = (Vector) inputList;
                arrayInput = new ArrayList(vInputList);
            } catch (ClassCastException cee) {
                // TO DO, could be a LinkedList
                throw cee;
            }
        }
        if (arrayInput != null) {
            for (int i = 0; i < arrayInput.size(); i++) {
                String item = arrayInput.get(i).toString();
                //System.out.println("In getBaseItem, treat item=" + item);
                ItemUser userItem = getUserItem(item, serverName);
                if (userItem.getName() != null) {
                    arrayResult.add(userItem);
                }
            }

        }
        return arrayResult;
    }
    /**
     * Used to treat the ReaderList and the WriterList currently implemented
     * by a Vector of Ids
     * @param inputList list of elemements
     * @return String containing the concateneted elements
     */
    private String getStringAttributeFromList(List inputList) {
        StringBuffer buf = new StringBuffer();
        /* check for choosen List implem in
         * - ArrayList
         * - Vector
         */
        ArrayList arrayInput = null;
        try {
            arrayInput = (ArrayList) inputList;
        } catch (ClassCastException ce) {
            try {
                Vector vInputList = (Vector) inputList;
                arrayInput = new ArrayList(vInputList);
            } catch (ClassCastException cee) {
                // TO DO, could be a LinkedList
                throw cee;
            }
        }
        if (arrayInput != null) {
            for (int i = 0; i < arrayInput.size(); i++) {
                buf.append(arrayInput.get(i).toString());
                buf.append("\n");
            }
            return new String(buf);
        } else {
            return null;
        }
    }
    protected void getStatistics(ObjectName destOn, MonitoringDestForm oMonitForm, DestinationForm oForm, String serverName) {
        Hashtable stats = (Hashtable) JonasManagementRepr.getAttribute(destOn, "Statistic", serverName);
        Calendar cal = Calendar.getInstance();
        Long creationDateVale = (Long) stats.get("creationDate");
        cal.setTimeInMillis(creationDateVale.longValue());
        oForm.setCreationDate(cal.getTime().toString());
        Long value = (Long) stats.get("nbMsgsReceiveSinceCreation");
        oMonitForm.setNbMsgsReceiveSinceCreation(value.longValue());
        value = (Long) stats.get("nbMsgsSendToDMQSinceCreation");
        oMonitForm.setNbMsgsSendToDMQSinceCreation(value.longValue());
        value = (Long) stats.get("nbMsgsDeliverSinceCreation");
        oMonitForm.setNbMsgsDeliverSinceCreation(value.longValue());
        oMonitForm.setName(getStringAttribute(destOn, "AdminName"));
        oMonitForm.setType(getStringAttribute(destOn, "Type"));
    }

    protected void populate(DestinationForm p_Form)
    throws Exception {
        // Object name used
        ObjectName oObjectName = p_Form.getOName();
        // Populate
        setBooleanAttribute(oObjectName, "FreelyReadable", p_Form.getFreelyReadable());
        setBooleanAttribute(oObjectName, "FreelyWriteable", p_Form.getFreelyWriteable());
    }

    protected void updateReadablesWriteables(DestinationForm pForm, String jonasServerName) {
        boolean freelyReadable = pForm.getFreelyReadable();
        boolean freelyWriteable = pForm.getFreelyWriteable();
        ObjectName on = pForm.getOName();
        JonasManagementRepr.setAttribute(on, "FreelyReadable", new Boolean(freelyReadable), jonasServerName);
        JonasManagementRepr.setAttribute(on, "FreelyWriteable", new Boolean(freelyWriteable), jonasServerName);
        if (!freelyReadable || !freelyWriteable) {
            // register in the session the currently managed destination id
            m_Session.setAttribute("currentDestination", on.toString());
        }
    }

    void testReaderList(DestinationForm pForm, String jonasServerName) {
        String name = pForm.getName();
        ObjectName queueOn = pForm.getOName();
        if (name.equals("mdbQueue")) {
            ObjectName userOn = null;
            // Look for user's toto MBean
            try {
                ObjectName userOns = JoramObjectName.joramUsers();
                Iterator it = JonasManagementRepr.queryNames(userOns, jonasServerName).iterator();
                while (it.hasNext()) {
                    ObjectName item = (ObjectName) it.next();
                    String itemName = (String) JonasManagementRepr.getAttribute(item, "Name", jonasServerName);
                    if (itemName.equals("toto")) {
                        // found MBean for user toto
                        userOn = item;
                        break;
                    }
                }
            } catch (MalformedObjectNameException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            // Add user as reader for mdbQueue
            if (userOn != null) {
                String userId = (String) JonasManagementRepr.getAttribute(userOn, "ProxyId", jonasServerName);
                String[] asParams = {userId };
                String[] asSignature = {"java.lang.String" };
                JonasManagementRepr.invoke(queueOn, "addReader", asParams, asSignature, jonasServerName);
            }
        }
    }
}
