/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2005 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
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

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

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;

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

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.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;


/**
 * @author Patrick Smith
 * @author Gregory Lapouchnian
 * @author Adriana Danes
 */
public class ApplyDomainDeployConfirmAction extends BaseDeployAction {

    // --------------------------------------------------------- Public Methods

    public ActionForward executeAction(ActionMapping p_Mapping,
            ActionForm p_Form, HttpServletRequest p_Request,
            HttpServletResponse p_Response) throws IOException,
            ServletException {

        String currentServerName = m_WhereAreYou.getCurrentJonasServerName();
        String domainName = m_WhereAreYou.getCurrentDomainName();
        DomainDeployForm oForm = (DomainDeployForm) p_Form;
        boolean deploymentInProgress = false;
        Map reports = new TreeMap();
        try {
            ObjectName domainOn = J2eeObjectName.J2EEDomain(domainName);
            // apps to be deployed on the selected targets
            ArrayList alApps = oForm.getListDeploy();
            for (int i = 0; i < alApps.size(); i++) {
                String app = (String) alApps.get(i);
                String appPath = JonasAdminJmx.findDeployedPath(oForm.getListDeployed(), app);
                if (!oForm.getDeploymentInProgress()) {
                    String selectedAction = oForm.getSelectedAction();
                    boolean replaceExisting = oForm.getReplacementOption();
                    boolean autoload = oForm.isAutoload();
                    ArrayList selectedTargets = oForm.getListTargetsSelected();
                    doSelectedOperation(appPath, selectedAction, replaceExisting, autoload, selectedTargets, domainName, currentServerName);
                }
                Map appReports = new HashMap();
                reports.put(app, appReports);
                // Get effective target server list
                Object[] asParam = {app};
                String[] asSignature = {"java.lang.String"};
                String[] targets = (String[]) JonasManagementRepr.invoke(domainOn
                        , "getDeployServers", asParam, asSignature
                        , currentServerName);
                for (int j = 0; j < targets.length; j++) {
                    String target = targets[j];
                    Object[] as1Param = {app, target};
                    String[] as1Signature = {"java.lang.String", "java.lang.String"};
                    String status = (String) JonasManagementRepr.invoke(domainOn
                            , "getDeployState", as1Param, as1Signature
                            , currentServerName);
                    if (status.startsWith("IN PROGR")) {
                        deploymentInProgress = true;
                    }
                    if (status.startsWith("FAIL")) {
                        String error = getError(app, target, currentServerName);
                        status = status + error;
                    }
                    appReports.put(target, status);
                }
            }
            oForm.setDeploymentInProgress(deploymentInProgress);
            if (!deploymentInProgress) {
                oForm.setDeploymentCompleted(true);
                resetReport(currentServerName);
            }
            oForm.setReports(reports);
        } catch (Throwable t) {
            oForm.setException(true);
            addGlobalError(t);
            saveErrors(p_Request, m_Errors);
        }
        // Forward to the jsp.
        return (p_Mapping.findForward("Domain Deploy Progress"));
    }

    private String getError(String app, String target, String serverName) throws MalformedObjectNameException {
        String domainName = m_WhereAreYou.getCurrentDomainName();
        ObjectName on = J2eeObjectName.J2EEDomain(domainName);
        String opName = "getErrorMessage";
        Object[] params = new Object[] {app, target};
        String[] sig = new String[] {"java.lang.String", "java.lang.String"};
        return (String) JonasManagementRepr.invoke(on, opName, params, sig, serverName);
    }


    /**
     * A custom thread class used for doing the deployment operations.
     */
    protected class DeployThread extends Thread {

        protected ActionMapping p_Mapping;

        protected ActionForm p_Form;

        protected HttpServletRequest p_Request;

        protected HttpServletResponse p_Response;

        public DeployThread(ActionMapping p_Mapping, ActionForm p_Form,
                HttpServletRequest p_Request, HttpServletResponse p_Response) {
            this.p_Mapping = p_Mapping;
            this.p_Form = p_Form;
            this.p_Request = p_Request;
            this.p_Response = p_Response;
        }

    }

    /**
     * Deploy the module with name 'appName' on the target
     * The operation to invoke has the same name: 'deployModule' for both
     * ServerProxy or LogicalCluster.
     * @param appName the name of the application
     * @param on the ObjectNamer of the target (ServerProxy if server, LogicalCluster if cluster)
     * rejected
     */
    private void doDeployOperation(String appName, ObjectName on, String serverName) {
        String opName = "deployModule";
        Object[] params = new Object[] {appName};
        String[] sig = new String[] {"java.lang.String"};
        JonasManagementRepr.invoke(on, opName, params, sig, serverName);
    }
    /**
     * Undeploy the module with name 'appName' from the target
     * The operation to invoke has the same name: 'undeployModule' for both
     * ServerProxy or LogicalCluster.
     * @param appName the name of the application
     * @param on the ObjectNamer of the target (ServerProxy if server, LogicalCluster if cluster)
     * rejected
     */
    private void doUndeployOperation(String appName, ObjectName on, String serverName) {
        String opName = "undeployModule";
        Object[] params = new Object[] {appName};
        String[] sig = new String[] {"java.lang.String"};
        JonasManagementRepr.invoke(on, opName, params, sig, serverName);
    }

    /**
     * Upload the module with name 'appName' on the target
     * The operation to invoke has the same name: 'uploadFile' for both
     * ServerProxy or LogicalCluster.
     * @param appName the name of the application
     * @param on the ObjectNamer of the target (ServerProxy if server, LogicalCluster if cluster)
     * rejected
     */
    private void doUploadOperation(String appName, boolean replaceExisting, boolean autoload, ObjectName on, String serverName) {
        if (autoload) {
            //System.out.println("Should call uploadFile with autoload option");
        }
        String opName = "uploadFile";
        Object[] params = new Object[] {appName, new Boolean(replaceExisting)};
        String[] sig = new String[] {"java.lang.String", "boolean"};
        JonasManagementRepr.invoke(on, opName, params, sig, serverName);
    }
    /**
     * Upload and deploy the module with name 'appName' on the target
     * The operation to invoke has the same name: 'uploadDeployModule' for both
     * ServerProxy or LogicalCluster.
     * @param appName the name of the application
     * @param on the ObjectNamer of the target (ServerProxy if server, LogicalCluster if cluster)
     * rejected
     */
    private void doUploadDeployOperation(String appName, boolean replaceExisting, boolean autoload, ObjectName on, String serverName) {
         String opName = "uploadDeployModule";
        Object[] params = new Object[] {appName, new Boolean(replaceExisting)};
        String[] sig = new String[] {"java.lang.String", "boolean"};
        JonasManagementRepr.invoke(on, opName, params, sig, serverName);
    }

    private void resetReport(String serverName) throws MalformedObjectNameException {
        String domainName = m_WhereAreYou.getCurrentDomainName();
        ObjectName on = J2eeObjectName.J2EEDomain(domainName);
        String opName = "forgetAllDeploy";
        JonasManagementRepr.invoke(on, opName, null, null, serverName);
    }

    /**
     * Do selected deployment action with the application named 'appName' on the selected targets
     * @param appName the name of the application
     * @param action action to do
     * @param replaceExisting true if must replace the file in case of a 'distribute' operation
     * @param targets the targets to deployment on
     * @param currentServerName the currently managed server
     */
    private void doSelectedOperation(String appName, String action, boolean replaceExisting, boolean autoload, ArrayList targets,
    		String domainName, String currentServerName)
    throws Exception {
        Iterator it = targets.iterator();
        while (it.hasNext()) {
            ObjectName targetOn = ObjectName.getInstance((String) it.next());
            String j2eeType = targetOn.getKeyProperty("j2eeType");
            String serverName = null;
            if ("J2EEServer".equals(j2eeType)) {
                // The target server
                serverName = targetOn.getKeyProperty("name");
                targetOn = JonasObjectName.serverProxy(domainName, serverName);
            }
            if (action.equals(DomainDeployForm.DEPLOY)) {
                /*result = */doDeployOperation(appName, targetOn, currentServerName);
            } else if (action.equals(DomainDeployForm.UPLOAD)) {
                /*result = */doUploadOperation(appName, replaceExisting, autoload, targetOn, currentServerName);
            } else if (action.equals(DomainDeployForm.UPLOADDEPLOY)) {
                /*result = */doUploadDeployOperation(appName, replaceExisting, autoload, targetOn, currentServerName);
            } else if (action.equals(DomainDeployForm.UNDEPLOY)) {
                /*result = */doUndeployOperation(appName, targetOn, currentServerName);
            }
        }
    }
}
