/*
 * Copyright 2006-2007 Queplix Corp.
 *
 * Licensed under the Queplix Public License, Version 1.1.1 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.queplix.com/solutions/commercial-open-source/queplix-public-license/
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 *
 */

package com.queplix.core.modules.services;

import com.queplix.core.error.GenericSystemException;
import com.queplix.core.integrator.security.LogonSession;
import com.queplix.core.modules.services.ejb.ScriptManager;
import com.queplix.core.modules.services.ejb.ScriptManagerHome;
import com.queplix.core.modules.services.jxb.Param;
import com.queplix.core.modules.services.jxb.Script;
import com.queplix.core.modules.services.jxb.Task;
import com.queplix.core.modules.services.jxb.types.ParamTypeSType;
import com.queplix.core.utils.JNDINames;
import com.queplix.core.utils.StringHelper;
import com.queplix.core.utils.cache.CacheObjectManager;
import com.queplix.core.utils.log.AbstractLogger;

import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.Map;

/**
 * Class to start script as a service
 *
 * @author [ALB] Baranov Andrey
 * @version $Revision: 1.1.1.1 $ $Date: 2005/09/12 15:30:58 $
 */

public final class Service
        extends AbstractLogger implements java.io.Serializable {

    // ----------------------------------------------------- Constants

    public final static int UNKNWON_SERVICE_ID = -1;

    // ----------------------------------------------------- Fields

    LogonSession ls;
    ScriptManager scriptManager;

    private Integer scriptId;
    private String scriptName;
    private Task task;

    private Script script;
    private Action action;
    private Map paramMap = new HashMap();

    // ----------------------------------------------------- Constructors

    //
    // Constructor
    //

    public Service(LogonSession ls, int scriptId) {
        this(ls, new Integer(scriptId), null, null);
    }

    //
    // Constructor
    //
    public Service(LogonSession ls, String scriptName) {
        this(ls, null, scriptName, null);
    }

    //
    // Constructor
    //
    Service(LogonSession ls, Task task) {
        this(ls, task.getScriptId(), null, task);
    }

    //
    // Constructor
    //
    private Service(LogonSession ls, Integer scriptId, String scriptName,
                    Task task) {

        if(ls == null) {
            throw new IllegalStateException();
        }

        this.ls = ls;
        this.scriptId = scriptId;
        this.scriptName = scriptName;
        this.task = task;

        try {

            //
            // get ScripManager remote interface
            //
            scriptManager = (ScriptManager) new CacheObjectManager().
                    getRemoteObject(JNDINames.ScriptManagerRemote,
                            ScriptManagerHome.class);

            //
            // get Script object
            //
            if(scriptId != null) {
                script = scriptManager.getScript(scriptId.intValue());
            } else {
                script = scriptManager.getScript(scriptName);
            }

            //
            // get Action object
            //
            String className = script.getClassName();
            try {
                Class cl = Class.forName(className);
                action = (Action) cl.newInstance();

            } catch (Exception ex) {
                ERROR(ex);
                throw new GenericSystemException(
                        "Can't instantiate action '" + className + "'", ex);
            }

            //
            // get script parameters
            //
            Param[] params;
            if(task != null) {
                // ..takes task parameters
                params = task.getParam();
            } else {
                // ..takes default script parameters
                params = script.getParam();
            }

            // put parameters into map of java objects
            int size = (params == null) ? 0:params.length;
            for(int i = 0; i < size; i++) {
                Param param = params[i];
                String paramName = param.getName();
                Object paramObject = paramToJavaObject(param.getValue(),
                        param.getType().getType());

                paramMap.put(paramName, paramObject);
            }

        } catch (RemoteException ex) {
            throw new GenericSystemException(ex);
        }
    }

    // ----------------------------------------------------- API methods

    /**
     * Start service with XA context
     *
     * @return Action result
     */
    public java.io.Serializable performWithXAContext() {

        if(action instanceof XAAction) {
            return performAsXA();
        }

        XAActionContext context = new XAActionContext(ls);
        if(paramMap != null) {
            context.addParameters(paramMap);
        }

        return ActionRunner.run(action, context);
    }

    /**
     * Start service
     *
     * @return Action result
     */
    java.io.Serializable perform() {

        if(action instanceof XAAction) {
            return performAsXA();
        }

        ActionContext context = new ActionContext(ls);
        if(paramMap != null) {
            context.addParameters(paramMap);
        }

        return ActionRunner.run(action, context);
    }

    /**
     * Start service as XA
     *
     * @return Action result
     */
    java.io.Serializable performAsXA() {

        XAActionContext context = new XAActionContext(ls);
        if(paramMap != null) {
            context.addParameters(paramMap);
        }

        return ActionRunner.runAsXA(action, context);
    }

    //
    // Getters/Setters
    //

    // get service ID

    public long getId() {
        if(task != null) {
            return task.getId().longValue();
        } else {
            return UNKNWON_SERVICE_ID;
        }
    }

    // get service name
    public String getName() {
        if(task != null) {
            return task.getName();
        } else {
            return "unknown (" + script.getName() + ")";
        }
    }

    // get script name
    public String getScriptName() {
        return scriptName;
    }

    // get script object
    public Script getScript() {
        return script;
    }

    // get task object
    public Task getTask() {
        return task;
    }

    // add action parameter
    public void addParameter(String paramName, Object paramValue) {
        paramMap.put(paramName, paramValue);
    }

    // get string
    public String toString() {
        return "Service '" + getName() + "[" + getId() + "]'. Parameters: "
                + paramMap;
    }

    // ----------------------------------------------------- private methods

    //
    // Convert script/task parameter to Java object
    //

    private Object paramToJavaObject(String param_value, int param_type) {

        if(StringHelper.isEmpty(param_value)) {
            // parameter is empty -> return null
            return null;
        }

        /** @todo add supporting of arrays */

        try {
            switch(param_type) {
                case ParamTypeSType.INT_TYPE:
                    return new Integer(param_value);
                case ParamTypeSType.LONG_TYPE:
                    return new Long(param_value);
                case ParamTypeSType.FLOAT_TYPE:
                    return new Float(param_value);
                case ParamTypeSType.STRING_TYPE:
                    return param_value;
                default:
                    throw new GenericSystemException(
                            "Unsupported parameter type: " + param_type);
            }
        } catch (NumberFormatException ex) {
            // exception during string to number transformation
            ERROR(ex);
            throw new GenericSystemException("Bad parameter: " + param_value);
        }
    }

} // end of class
