/*
 * This software consists of voluntary contributions made by many individuals
 * on behalf of the Apache Software Foundation and was originally created by
 * Sanjiva Weerawarana and others at International Business Machines
 * Corporation. For more information on the Apache Software Foundation,
 * please see <http://www.apache.org/>.
 */

package org.apache.bsf.util;

import java.util.Vector;

import org.apache.bsf.BSFEngine;
import org.apache.bsf.BSFException;
import org.apache.bsf.BSFManager;
import org.apache.bsf.util.event.EventProcessor;

/*
 * Copyright (C) 2001-2006 Rony G. Flatscher
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * <a
 * href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>
 *
 * 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.
 *
 */

/**
 *
 * This is used to support binding scripts to be run when an event occurs,
 * forwarding the arguments supplied to the event listener. It is an adapted
 * version of org.apache.bsf.util.BSFEventProcessor.
 *
 * @author Rony G. Flatscher, but most of the code copied from
 *         org.apache.bsf.util.BSFEventProcessor by Sanjiva Weerawarana
 */
public class BSFEventProcessorReturningEventInfos implements EventProcessor {
    BSFEngine engine;

    BSFManager manager;

    String filter;

    String source;

    int lineNo;

    int columnNo;

    Object script;

    Object dataFromScriptingEngine; // ---rgf, 2006-02-24: data coming from the
                                    // script engine, could be

    // e.g. an object reference to forward event with received arguments to

    /**
     * Package-protected constructor makes this class unavailable for public
     * use.
     *
     * @param dataFromScriptingEngine
     *            this contains any object supplied by the scripting engine and
     *            gets sent back with the supplied script. This could be used
     *            e.g. for indicating which scripting engine object should be
     *            ultimately informed of the event occurrence.
     */
    BSFEventProcessorReturningEventInfos(BSFEngine engine, BSFManager manager,
            String filter, String source, int lineNo, int columnNo,
            Object script, Object dataFromScriptingEngine) throws BSFException {
        this.engine = engine;
        this.manager = manager;
        this.filter = filter;
        this.source = source;
        this.lineNo = lineNo;
        this.columnNo = columnNo;
        this.script = script;
        this.dataFromScriptingEngine = dataFromScriptingEngine;
    }

    // ////////////////////////////////////////////////////////////////////////
    //
    // event is delegated to me by the adapters using this. inFilter is
    // in general the name of the method via which the event was received
    // at the adapter. For prop/veto change events, inFilter is the name
    // of the property. In any case, in the event processor, I only forward
    // those events if for which the filters match (if one is specified).

    public void processEvent(String inFilter, Object[] evtInfo) {
        try {
            processExceptionableEvent(inFilter, evtInfo);
        } catch (RuntimeException re) {
            // rethrow this .. I don't want to intercept run-time stuff
            // that can in fact occur legit
            throw re;
        } catch (Exception e) {
            // should not occur
            System.err.println("BSFError: non-exceptionable event delivery "
                    + "threw exception (that's not nice): " + e);
            e.printStackTrace();
        }
    }

    // ////////////////////////////////////////////////////////////////////////
    //
    // same as above, but used when the method event method may generate
    // an exception which must go all the way back to the source (as in
    // the vetoableChange case)

    public void processExceptionableEvent(String inFilter, Object[] evtInfo)
            throws Exception {

// System.err.print("BSFEventProcessorReturningEventInfos.processExceptionableEvent():"+" inFilter=["+inFilter+"]"+" filter=["+filter+"]"+" -> ");
    //    if ((filter != null) && !filter.equals(inFilter)) {
            if ((filter != null) && !isFilteredEvent(filter, inFilter)) {
            // ignore this event
// System.err.println("IGNORED!");	  // ignore this event
            return;
        }

        // run the script
        // engine.exec (source, lineNo, columnNo, script);

        // create the parameter vectors for engine.apply()
        Vector paramNames = new Vector(), paramValues = new Vector();

        // parameter # 1
        // supply the parameters as an array object as sent to the event object
        // listener
        // (usually the first entry is the sent event object)
        paramNames.add("eventParameters");
        paramValues.add(evtInfo);

        // parameter # 2
        // supply the data object received from the scripting engine to be sent
        // with the event
        paramNames.add("dataFromScriptingEngine");
        paramValues.add(this.dataFromScriptingEngine); // can be null as well

        // parameter # 3
        // event filter in place
        paramNames.add("inFilter");
        paramValues.add(inFilter); // event name that has occurred

        // parameter # 4
        // event filter in place
        paramNames.add("eventFilter");
        paramValues.add(this.filter); // can be null as well

        // parameter # 5
        // BSF manager instance (e.g. allows access to its registry)
        paramNames.add("BSFManager");
        paramValues.add(this.manager);

// System.err.println("about to invoke engine.apply: source=["+source+"], script=["+script+"]");
        engine.apply(source, lineNo, columnNo, this.script, paramNames, paramValues);
// System.err.println("returned from engine.exec.");

    }


    private static boolean isFilteredEvent(final String filter, String inFilter)
    {
        boolean bRes=filter.equalsIgnoreCase(inFilter);
        if (bRes)
        {
            return bRes;
        }

        String chunks[]=filter.replace('+',' ').split(" ");
        for (int i=0;i<chunks.length;i++)
        {
            bRes=chunks[i].equalsIgnoreCase(inFilter);
            if (bRes)
            {
                return bRes;
            }
        }
        return bRes;
    }
}
