/*
 * 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.actions;

import com.queplix.core.error.GenericSystemException;
import com.queplix.core.integrator.security.LogonSession;
import com.queplix.core.integrator.security.User;
import com.queplix.core.modules.eql.error.EQLException;
import com.queplix.core.modules.jeo.JEObjectHandler;
import com.queplix.core.modules.jeo.ejb.JEOManagerLocal;
import com.queplix.core.modules.jeo.ejb.JEOManagerLocalHome;
import com.queplix.core.modules.jeo.gen.ScriptObject;
import com.queplix.core.modules.jeo.gen.ScriptObjectHandler;
import com.queplix.core.modules.jeo.gen.ScriptParametersObject;
import com.queplix.core.modules.jeo.gen.ScriptParametersObjectHandler;
import com.queplix.core.modules.services.XAAction;
import com.queplix.core.modules.services.jxb.Param;
import com.queplix.core.modules.services.jxb.Script;
import com.queplix.core.modules.services.jxb.Scripts;
import com.queplix.core.utils.DateHelper;
import com.queplix.core.utils.JNDINames;
import com.queplix.core.utils.StringHelper;
import com.queplix.core.utils.xml.XMLBinding;
import com.queplix.core.utils.xml.XMLFactory;
import com.queplix.core.utils.xml.XMLWrapper;
import org.w3c.dom.Document;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>XA Action wich fills scripts from XML files and calls JEO Manager</p>
 *
 * @author [ALB] Baranov Andrey
 * @version $Revision: 1.1.1.1 $ $Date: 2005/09/12 15:30:59 $
 */

public class ScriptInstallationAction
        extends XAAction {

    private Scripts scripts;
    private String scriptfile;
    private File scriptFile;

    /*
     * No javadoc
     * @see Action#perform
     */
    public java.io.Serializable perform() {

        this.scriptfile = getContext().getParamAsString("scriptfile");

        if(scriptfile == null) {
            throw new NullPointerException("Script file is NULL");
        }

        scriptFile = new File(scriptfile);
        if(!scriptFile.exists() || scriptFile.isDirectory()) {
            throw new IllegalStateException("Bad script config dir: " +
                    scriptFile.getAbsolutePath());
        }

        try {

            // Do process
            INFO("PROCESS STARTED...");
            long time = System.currentTimeMillis();

            parseScripts();
            createScripts(scripts.getScript(), getContext().getLogonSession());

            // Ok.
            INFO("Process last(s): "
                    + (System.currentTimeMillis() - time) / 1000);
            INFO("PROCESS DONE !!!");

        } catch (GenericSystemException ex) {
            ERROR(ex);
            throw ex;

        } catch (Throwable t) {
            ERROR(t);
            throw new GenericSystemException(
                    "Unknown exception: " + t.getMessage(), t);
        }

        return null;
    }

    /**
     * Parse scripts xml config file and create Scripts object
     */
    private void parseScripts() {
        XMLWrapper xmlWrapper = XMLFactory.getXMLWrapper();
        XMLBinding xmlBind = XMLFactory.getXMLBinding();

        Document document = xmlWrapper.getDocument(scriptFile, false);
        scripts = (Scripts) xmlBind.xmlToJava(Scripts.class, document);
    }

    /**
     * Create scripts.
     *
     * @param scripts array of Script object
     * @param ls      user logon session
     * @throws EQLException
     */
    protected void createScripts(Script[] scripts, LogonSession ls)
            throws EQLException {

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

        // get list of exist scripts
        List existScriptHndList = ScriptObjectHandler.selectAll(
                getJEOManagerLocal(), ls);
        int existScriptHndSize = (existScriptHndList == null) ? 0
                :existScriptHndList.size();

        // special list of names of updated scipts
        List existScriptNames = new ArrayList();

        if(scripts != null) {
            for(int i = 0; i < scripts.length; i++) {
                Script script = scripts[i];
                String name = script.getName();

                // Try to find existing handler
                JEObjectHandler scriptObjectHnd = null;
                for(int j = 0; j < existScriptHndSize; j++) {
                    JEObjectHandler hnd = (JEObjectHandler) existScriptHndList
                            .get(j);
                    ScriptObject scriptObject = (ScriptObject) hnd
                            .getJEObject();
                    if(name.equals(scriptObject.getScript_name())) {
                        scriptObjectHnd = hnd;
                        break;
                    }
                }

                // Create/Update script.
                createScript(script, scriptObjectHnd, ls);

                if(scriptObjectHnd != null) {
                    // already exist - add in exist list
                    existScriptNames.add(script.getName());
                }
            }
        }

        // remove obsolete scripts
        for(int i = 0; i < existScriptHndSize; i++) {
            JEObjectHandler scriptHnd = (JEObjectHandler) existScriptHndList
                    .get(i);
            ScriptObject scriptObject = (ScriptObject) scriptHnd.getJEObject();

            if(existScriptNames.contains(scriptObject.getScript_name())) {
                // script exist
                continue;
            }

            scriptHnd.remove();
            scriptHnd.commit();
        }
    }

    /**
     * Create script.
     *
     * @param script          Script object
     * @param scriptObjectHnd existing handler (optional)
     * @param ls              user logon session
     * @throws EQLException
     */
    protected void createScript(Script script,
                                JEObjectHandler scriptObjectHnd,
                                LogonSession ls)
            throws EQLException {

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

        //
        // Initialization.
        //

        int script_id = StringHelper.EMPTY_NUMBER;
        long time = System.currentTimeMillis();
        User user = ls.getUser();
        JEOManagerLocal jeoManager = getJEOManagerLocal();
        boolean isNew = false;

        try {

            //
            // Create or update Script
            //

            ScriptObject scriptObject;
            if(scriptObjectHnd == null) {
                // create new Script
                scriptObjectHnd = jeoManager.create(ls,
                        ScriptObjectHandler.class);
                isNew = true;

                scriptObject = (ScriptObject) scriptObjectHnd.getJEObject();
                scriptObject.setScript_name(script.getName());
                scriptObject.setCreator_id(user.getUserID());
                scriptObject.setCreator_type(user.getAuthenticationType());

            } else {
                // update old Script
                scriptObject = (ScriptObject) scriptObjectHnd.getJEObject();
            }

            scriptObject.setScript_description(script.getDescription());
            scriptObject.setScript_class_name(script.getClassName());
            scriptObject.setDate_modified(DateHelper.getNowDate());
            scriptObjectHnd.commit();

            script_id = scriptObject.getScript_id();

            //
            // create or update script parameters
            //

            // get list of exist parameters
            List existScriptParamHndList = null;
            if(!isNew) {
                existScriptParamHndList = ScriptParametersObjectHandler.
                        selectByScriptId(jeoManager, ls, script_id);
            }
            int existScriptParamHndSize = (existScriptParamHndList == null) ? 0
                    :existScriptParamHndList.size();

            // special list of names of updated scipt parameters
            List existScriptParamNames = new ArrayList();

            // add/update script parameters in cycle
            for(int i = 0; i < script.getParamCount(); i++) {
                Param param = script.getParam(i);
                String name = param.getName();

                // Try to find existing handler
                JEObjectHandler scriptParamHnd = null;
                for(int j = 0; j < existScriptParamHndSize; j++) {
                    JEObjectHandler hnd
                            = (JEObjectHandler) existScriptParamHndList.get(j);
                    ScriptParametersObject scriptParamObject
                            = (ScriptParametersObject) hnd.getJEObject();
                    if(name.equals(scriptParamObject.getScript_param_name())) {
                        scriptParamHnd = hnd;
                        break;
                    }
                }

                // Create/Update script parameter.
                createScriptParameter(script_id, param, scriptParamHnd, ls);

                if(scriptParamHnd != null) {
                    // already exist - add in exist list
                    existScriptParamNames.add(param.getName());
                }
            }

            // remove obsolete script parameters
            for(int i = 0; i < existScriptParamHndSize; i++) {
                JEObjectHandler scriptParamHnd
                        = (JEObjectHandler) existScriptParamHndList.get(i);
                ScriptParametersObject scriptParamObject
                        = (ScriptParametersObject)
                        scriptParamHnd.getJEObject();

                if(existScriptParamNames.contains(
                        scriptParamObject.getScript_param_name())) {
                    // parameter exist
                    continue;
                }

                scriptParamHnd.remove();
                scriptParamHnd.commit();
            }

        } catch (GenericSystemException ex) {
            ERROR(ex);
            throw ex;

        } catch (Exception ex) {
            ERROR(ex);
            throw new GenericSystemException(ex);
        }

        // Ok.
        if(getLogger().isInfoEnabled()) {
            if(isNew) {
                INFO("Script created (ID = " + script_id + ").");
            } else {
                INFO("Script updated (ID = " + script_id + ").");
            }

            INFO("Time (ms) - " + (System.currentTimeMillis() - time));
        }
    }

    //
    // Create/update script parameter
    //
    protected void createScriptParameter(int script_id,
                                         Param param,
                                         JEObjectHandler scriptParamHnd,
                                         LogonSession ls)
            throws EQLException {

        JEOManagerLocal jeoManager = getJEOManagerLocal();

        ScriptParametersObject scriptParamObject = null;
        if(scriptParamHnd != null) {
            // already exist - update it
            scriptParamObject = (ScriptParametersObject) scriptParamHnd
                    .getJEObject();

        } else {
            // create new script parameter
            scriptParamHnd = (ScriptParametersObjectHandler)
                    jeoManager.create(ls, ScriptParametersObjectHandler.class);

            scriptParamObject = (ScriptParametersObject) scriptParamHnd
                    .getJEObject();
            scriptParamObject.setScript_id(new Integer(script_id));
            scriptParamObject.setScript_param_name(param.getName());
        }

        scriptParamObject.setScript_param_type_id(new Integer(
                param.getType().getType()));
        scriptParamObject.setDef_value(param.getValue());
        if(param.getRequired() != null) {
            scriptParamObject.setRequired(param.getRequired().booleanValue()
                    ? new Integer(1):new Integer(0));
        } else {
            scriptParamObject.setRequired(new Integer(0));
        }
        scriptParamObject.setScript_param_description(param.getDescription());

        // save it
        scriptParamHnd.commit();
    }

    /**
     * Get ScriptManager EJB reference
     *
     * @return ScriptManager remote interface
     */
    protected JEOManagerLocal getJEOManagerLocal() {
        return (JEOManagerLocal)
                getContext().getCOM().getLocalObject(JNDINames.JEOManager,
                        JEOManagerLocalHome.class);
    }
}
