/*
 * The contents of this file are subject to the terms 
 * of the Common Development and Distribution License 
 * (the License).  You may not use this file except in
 * compliance with the License.
 * 
 * You can obtain a copy of the license at 
 * https://glassfish.dev.java.net/public/CDDLv1.0.html or
 * glassfish/bootstrap/legal/CDDLv1.0.txt.
 * See the License for the specific language governing 
 * permissions and limitations under the License.
 * 
 * When distributing Covered Code, include this CDDL 
 * Header Notice in each file and include the License file 
 * at glassfish/bootstrap/legal/CDDLv1.0.txt.  
 * If applicable, add the following below the CDDL Header, 
 * with the fields enclosed by brackets [] replaced by
 * you own identifying information: 
 * "Portions Copyrighted [year] [name of copyright owner]"
 * 
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 */

package com.sun.enterprise.deployment.phasing;

import com.sun.enterprise.deployment.Application;
import com.sun.enterprise.deployment.util.DeploymentProperties;

import com.sun.enterprise.deployment.backend.DeploymentStatus;
import com.sun.enterprise.deployment.backend.DeploymentRequest;
import com.sun.enterprise.deployment.backend.DeployableObjectType;
import com.sun.enterprise.deployment.backend.DeploymentLogger;
import com.sun.enterprise.deployment.backend.IASDeploymentException;

import com.sun.enterprise.util.i18n.StringManager;
import com.sun.enterprise.resource.Resource;
import com.sun.enterprise.admin.common.MBeanServerFactory;
import com.sun.enterprise.admin.common.ObjectNames;

import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.MBeanException;

import java.util.List;
import java.util.ArrayList;
import java.util.logging.Logger;

/**
 * This class is the base class for resource phases
 */
public abstract class ResourcePhase extends DeploymentPhase {

    protected static final String resourcesMBeanName = 
        "com.sun.appserv:type=resources,category=config";
    protected static final String CREATE_RESOURCE = 
        "createResource";
    protected static final String CREATE_RESOURCE_REF = 
        "createResourceReference";
    protected static final String CREATE_RESOURCE_AND_REF = 
        "createResourceAndResourceReference";
    protected static final String DELETE_RESOURCE = 
        "deleteResource";
    protected static final String DELETE_RESOURCE_REF = 
        "deleteResourceReference";
    protected static final String DELETE_RESOURCE_AND_REF = 
        "deleteResourceAndResourceReference";

    protected static final String DOMAIN_TARGET = 
        "domain";

    protected MBeanServer mbs = MBeanServerFactory.getMBeanServer();

    protected void doResourceOperation(DeploymentRequest req) throws Exception {
        String targetListString = req.getResourceTargetList();
        List<String> targetList = DeploymentServiceUtils.getTargetNamesFromTargetString(targetListString);

        String resourceAction = req.getResourceAction();
        if (resourceAction == null || 
            getActualAction(resourceAction).equals(
                DeploymentProperties.RES_NO_OP)) {
            return;
        }

        if (targetList == null || targetList.isEmpty()) {
            return;
        }

        List<Resource> resourceList = null;

        // if resource list is null, it means it needs to 
        // read in sun-configuration.xml and parse it,
        // if resource list is empty, it means it's been processed
        // but no sun-configuration.xml is found
        Application app = DeploymentServiceUtils.getInstanceManager(
            req.getType()).getRegisteredDescriptor(req.getName()); 

        // first try to get the in-memory copy from application
        // always re-set the list from disk for redeployment 
        if (app != null && app.getResourceList() != null && 
            !getForceParsing(resourceAction)) {
            resourceList = (List<Resource>)app.getResourceList();
        // then try to get it from resources.xml
        // and set in the application object
        } else {
            resourceList = DeploymentServiceUtils.getResources(
                req.getName(), req.getType());
            // todo: resolve with the existing resources in the config
            if (app != null) {
                app.setResourceList(resourceList);
            }
        }

        // empty resource list, no resource to process
        if (resourceList.size() == 0) {
            return;
        }

        handleResources(resourceAction, targetList, 
            getRelevantResources(resourceList)); 
    }


    protected void handleResources(String resourceAction, 
        List<String> targetList, List<Resource> resourceList) 
        throws Exception {

        // empty sub resource list, no resource to process
        if (resourceList.size() == 0) {
            return;
        }

        if (resourceAction.equals(DeploymentProperties.RES_DEPLOYMENT)) {
            handleDeployment(targetList, resourceList);
        } else if (resourceAction.equals(DeploymentProperties.RES_CREATE_REF)){
            handleCreateApplicationRef(targetList, resourceList);
        } else if (resourceAction.equals(DeploymentProperties.RES_DELETE_REF)){
            handleDeleteApplicationRef(targetList, resourceList);
        } else if (resourceAction.equals(
            DeploymentProperties.RES_UNDEPLOYMENT)){
            handleUndeployment(targetList, resourceList);
        } else if (resourceAction.equals(
            DeploymentProperties.RES_REDEPLOYMENT)){
            handleRedeployment(targetList, resourceList);
        }
    }

    // invoke with both resource and resource-ref elements created
    // special case: when target is domain, only create resource element
    protected void handleDeployment(List<String> targetList,
        List<Resource> resourceList) throws Exception {
        ObjectName mbeanName = new ObjectName(resourcesMBeanName);

        // if target is domain, only create resource
        if (targetList.size() == 1 &&
            targetList.get(0).equals(DOMAIN_TARGET)) {
            String[] signature = new String[]{
                "java.util.List", "java.lang.Boolean"};
            Object[] params = new Object[]{resourceList, Boolean.TRUE};
            mbs.invoke(mbeanName, CREATE_RESOURCE, params, signature);
        } else {
            String[] signature = new String[]{
                "java.util.List", "java.util.List", "java.lang.Boolean"};
            Object[] params = new Object[]{resourceList, targetList, 
                Boolean.TRUE};
            mbs.invoke(mbeanName, CREATE_RESOURCE_AND_REF, params, signature);
        }
    }

    // invoke with only resource-ref element created
    protected void handleCreateApplicationRef(List<String> targetList,
        List<Resource> resourceList) throws Exception {
        ObjectName mbeanName = new ObjectName(resourcesMBeanName);
        String[] signature = new String[]{
            "java.util.List", "java.util.List", "java.lang.Boolean"};
        Object[] params = new Object[]{resourceList, targetList, 
            Boolean.TRUE};
        mbs.invoke(mbeanName, CREATE_RESOURCE_REF, params, signature);
    }

    // invoke with both resource and resource-ref elements deleted
    // special case: when target is domain, only delete resource element
    protected void handleUndeployment(List<String> targetList,
        List<Resource> resourceList) throws Exception {
        ObjectName mbeanName = new ObjectName(resourcesMBeanName);

        // if target is domain, only delete resource
        if (targetList.size() == 1 &&
            targetList.get(0).equals(DOMAIN_TARGET)) {
            String[] signature = new String[]{"java.util.List"};
            Object[] params = new Object[]{resourceList};
            mbs.invoke(mbeanName,DELETE_RESOURCE, params, signature);
        } else {
            String[] signature = new String[]{
                "java.util.List", "java.util.List"};
            Object[] params = new Object[]{resourceList, targetList};
            mbs.invoke(mbeanName, DELETE_RESOURCE_AND_REF, params, signature);
        }
    }

    abstract protected void handleRedeployment(List<String> targetList,
        List<Resource> resourceList) throws Exception;

    // invoke with only resource-ref element deleted
    protected void handleDeleteApplicationRef(List<String> targetList,
        List<Resource> resourceList) throws Exception {
        ObjectName mbeanName = new ObjectName(resourcesMBeanName);
        String[] signature = new String[]{
            "java.util.List", "java.util.List"};
        Object[] params = new Object[]{resourceList, targetList};
        mbs.invoke(mbeanName, DELETE_RESOURCE_REF, params, signature);
    }

    protected boolean getForceParsing(String resAction) {
        return false;
    }

    protected String getActualAction(String resAction) {
        return resAction;
    }

    abstract protected List<Resource> getRelevantResources(
        List<Resource> allResources);
}
