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

package org.ow2.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.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.ow2.jonas.lib.management.extensions.base.JonasManagementRepr;
import org.ow2.jonas.lib.util.JonasObjectName;
import org.ow2.jonas.lib.util.JoramObjectName;
import org.ow2.jonas.webapp.jonasadmin.JonasAdminJmx;
import org.ow2.jonas.webapp.jonasadmin.deploy.BaseDeployAction;


/**
 * @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(final Throwable pThrowable, final ActionMapping pMapping, final 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();
    }
    public ObjectName getDmqOn(final String name, final String serverId, final String serverName) throws MalformedObjectNameException {
        ObjectName result = getDestinationOn(name, serverId, serverName);
        if (result != null) {
            return result;
        } else {
            // search on the other servers
            ObjectName joramAdapterOn = JoramObjectName.joramAdapter();
            Short[] serversIds = (Short[]) JonasManagementRepr.getAttribute(joramAdapterOn, "ServersIds", serverName);
            if (serversIds != null) {
                int i = 0;
                for (int index = 0; index < serversIds.length; index++) {
                    Short id = serversIds[index];
                    if (!id.equals(serverId)) {
                        result = getDestinationOn(name, id.toString(), serverName);
                        if (result != null) {
                            return result;
                        }
                    }
                }
            }
        }
        return null;
    }

    /**
     * @param name the destination's admin name or name (agent id based)
     * @param serverName jonas server name being managed
     * @return the ObjectName of the destination's MBean
     * @throws MalformedObjectNameException
     */
    public ObjectName getDestinationOn(final String name, final String serverId, final String serverName) throws MalformedObjectNameException {
        ObjectName result = null;
        ObjectName joramAdapterOn = JoramObjectName.joramAdapter();
        Short id = new Short(serverId);
        Object[] asParam = {
                id
        };
        String[] asSignature = {
                "short"
        };
        String[] destinations = (String[]) JonasManagementRepr.invoke(joramAdapterOn, "getDestinations", asParam, asSignature, serverName);
        for (int i = 0; i < destinations.length; i++) {
            String dest = destinations[i];
            ObjectName destOn = ObjectName.getInstance(dest);
            String destAdminName = (String) JonasManagementRepr.getAttribute(destOn, "AdminName", serverName);
            String destName = (String) JonasManagementRepr.getAttribute(destOn, "Name", serverName);
            if (name.startsWith("#")) {
                // compare name with destName
                if (name.equals(destName)) {
                    // found
                    return destOn;
                }
            } else {
                // compare name with destAdminName
                if (name.equals(destAdminName)) {
                    // found
                    return destOn;
                }
            }
        }

        return result;
    }

    /**
     *
     * @param dmqId id=#x.y.z
     * @return
     */
    protected ObjectName getDmqOn(final String dmqId, final String jonasServerName) throws MalformedObjectNameException {
        if (dmqId == null) {
            return null;
        }
        Set namesSet = JonasManagementRepr.queryNames(JoramObjectName.joramQueues(), jonasServerName);
        for (Iterator it = namesSet.iterator(); it.hasNext(); ) {
            ObjectName itOn = (ObjectName) it.next();
            String itName = (String) JonasManagementRepr.getAttribute(itOn, "Name", jonasServerName);
            if (dmqId.equals(itName)) {
                // found dmq
                return itOn;
            }
        }
        // not found
        return null;
    }

    /**
     * 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(final String joramAdminDestination, final String serverName) throws MalformedObjectNameException {
        ItemDestination destinationItem = new ItemDestination();

        ObjectName destinationOn = ObjectName.getInstance(joramAdminDestination);
        destinationItem.setType(destinationOn.getKeyProperty("type"));
        if (JonasAdminJmx.hasMBeanName(destinationOn, serverName)) {
            destinationItem.setRegistered(true);
            String name = (String) JonasManagementRepr.getAttribute(destinationOn, "AdminName", serverName);
            destinationItem.setName(name);
            String agentName = (String) JonasManagementRepr.getAttribute(destinationOn, "Name", serverName);
            destinationItem.setId(agentName);
            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(final String joramAdminUser, final String serverName) throws MalformedObjectNameException {
        ItemUser userItem = new ItemUser();
        ObjectName on = ObjectName.getInstance(joramAdminUser);
        String name = (String) JonasManagementRepr.getAttribute(on, "Name", serverName);
        userItem.setName(name);
        String id = (String) JonasManagementRepr.getAttribute(on, "ProxyId", serverName);
        userItem.setId(id);
        userItem.setServerId(on.getKeyProperty("location"));
        if (JonasAdminJmx.hasMBeanName(on, serverName)) {
            userItem.setOn(on);
        }
        return userItem;
    }

    /**
     * * Return the ObjectName of the User MBean corresponding to a given user
     * @param userName the user's name
     * @param serverId the JORAM server's Id
     * @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(final String userName, final Short serverId, final String serverName) throws MalformedObjectNameException {
         ObjectName result = null;
         ObjectName joramAdapterOn = JoramObjectName.joramAdapter();
         Object[] asParam = {
                 serverId
         };
         String[] asSignature = {
                 "short"
         };
         String[] users = (String[]) JonasManagementRepr.invoke(joramAdapterOn, "getUsers", asParam, asSignature, serverName);
         for (int i = 0; i < users.length; i++) {
             String user = users[i];
             ObjectName userOn = ObjectName.getInstance(user);
             String userAdminName = (String) JonasManagementRepr.getAttribute(userOn, "Name", serverName);
             if (userName.equals(userAdminName)) {
                 // found
                 return userOn;
             }
         }
         return result;
     }

    /**
     * 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(final String userId, final 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(final ItemDestination dest, final 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(final 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(final String domainName, final String jonasServerName) {
        String[] asParam = new String[1];
        String[] asSignature = new String[1];
        asSignature[0] = "java.lang.String";
        ejbServiceObjectName = JonasObjectName.ejbService(domainName);
        if (!JonasManagementRepr.isRegistered(ejbServiceObjectName,  jonasServerName)) {
            ejbServiceObjectName = null;
        }
    }

    protected boolean hasDeps(final String pDestName, final 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;
    }

    /**
     * Return server Id
     * @param location String having this form : server#id
     * @return id
     */
    protected String getServerId(final String location) {
        return location.substring(location.indexOf("#") + 1);
    }
    /**
     * Determine the server Id of a destination.
     * @param destinationOn the ObjectName destination's MBean. The 'loaction' key has the following structure : server#y. The server id to be returned is "y"
     * @return server id
     */
    public static String currentServerId(final ObjectName destinationOn) {
        String serverId = null;
        String location = destinationOn.getKeyProperty("location");
        serverId = location.substring(location.indexOf('#') + 1);
        return serverId;
    }

    protected void populateDestination(final ObjectName destOn, final DestinationForm oForm, final String serverName) throws MalformedObjectNameException {
        oForm.setName(getStringAttribute(destOn, "AdminName"));
        //testReaderList(oForm);
        /** joramClient destination MBean evolution:
         *  DMQ attribute replaced with DMQId, Type is String.
         */
        String dmqId = getStringAttribute(destOn, "DMQId");
        if (dmqId != null) {
            ObjectName dmqOn = getDestinationOn(dmqId, currentServerId(destOn), serverName);
            String dmqName = (String) JonasManagementRepr.getAttribute(dmqOn, "AdminName", serverName);
            oForm.setDmq(dmqName);
        }
        oForm.setId(getStringAttribute(destOn, "Name"));
        oForm.setType(destOn.getKeyProperty("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, destOn, 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, destOn, serverName));
        }
    }

    /**
     * Treat a list (Vector) of Joram user names
     * @param inputList list of Joram user names
     * @param destOn the ObjectName corresponding to the destination's MBean
     * @return a list of user item objects (ItemUser type)
     * @throws MalformedObjectNameException
     */
    protected ArrayList getBaseItemList(final List inputList, final ObjectName destOn, final 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;
            }
        }
        String serverId = EditJoramBaseAction.currentServerId(destOn);
        if (arrayInput != null) {
            for (int i = 0; i < arrayInput.size(); i++) {
                String item = arrayInput.get(i).toString();
                ItemUser userItem = getUserItem(getUserOn(item, new Short(serverId), serverName).toString(), serverName);
                if (userItem.getName() != null) {
                    arrayResult.add(userItem);
                }
            }

        }
        return arrayResult;
    }
    protected ObjectName getDmq(final String dmqId, final String serverName) {
    	ObjectName dmqOn = null;
    	try {
			ObjectName dmqOns = JoramObjectName.joramDmQueues();
			Iterator it = JonasManagementRepr.queryNames(dmqOns, serverName).iterator();
			while (it.hasNext()) {
				ObjectName a_dmqOn = (ObjectName) it.next();
				String id = (String) JonasManagementRepr.getAttribute(a_dmqOn, "Name", serverName);
				if (id != null && id.equals(dmqId)) {
					dmqOn = a_dmqOn;
					break;
				}
			}
		} catch (MalformedObjectNameException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return dmqOn;
    }
    /**
     * 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(final List inputList, final 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(final 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(final ObjectName destOn, final MonitoringDestForm oMonitForm, final DestinationForm oForm, final String serverName) {
        Hashtable stats = (Hashtable) JonasManagementRepr.getAttribute(destOn, "Statistic", serverName);
        Calendar cal = Calendar.getInstance();
        Long creationDateVale = (Long) stats.get("CreationTimeInMillis");
        cal.setTimeInMillis(creationDateVale.longValue());
        oForm.setCreationDate(cal.getTime().toString());
        Long value = (Long) stats.get("NbMsgsReceiveSinceCreation");
        oMonitForm.setNbMsgsReceiveSinceCreation(value.longValue());
        value = (Long) stats.get("NbMsgsSentToDMQSinceCreation");
        oMonitForm.setNbMsgsSendToDMQSinceCreation(value.longValue());
        value = (Long) stats.get("NbMsgsDeliverSinceCreation");
        oMonitForm.setNbMsgsDeliverSinceCreation(value.longValue());
        oMonitForm.setName(oForm.getName());
        oMonitForm.setType(oForm.getType());
    }

    protected void populate(final 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(final DestinationForm pForm, final 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(final DestinationForm pForm, final 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);
            }
        }
    }
}
