/*
 * Helma License Notice
 *
 * The contents of this file are subject to the Helma License
 * Version 2.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://adele.helma.org/download/helma/license.txt
 *
 * Copyright 2005 Hannes Wallnoefer. All Rights Reserved.
 */
package org.helma.javascript;

import org.mozilla.javascript.*;
import org.helma.repository.Trackable;
import org.helma.tools.HelmaConfiguration;

import java.util.HashMap;

public class HelmaContextFactory extends ContextFactory {

    RhinoEngine engine;

    int languageVersion = Context.VERSION_1_8;
    boolean strictMode = false;
    boolean warningAsError = false;
    boolean parentProtoProperties = true;
    int optimizationLevel = 0;
    boolean generatingDebug = true;
    ErrorReporter errorReporter;
    ClassShutter classShutter;


    public HelmaContextFactory(RhinoEngine engine, HelmaConfiguration config) {
        this.engine = engine;
        optimizationLevel = config.getOptLevel();
        languageVersion = config.getLanguageVersion();
        parentProtoProperties = config.hasParentProtoProperties();
        classShutter = config.getClassShutter();
    }

    @Override
    protected boolean hasFeature(Context cx, int featureIndex) {
        switch (featureIndex) {
          case Context.FEATURE_STRICT_VARS:
          case Context.FEATURE_STRICT_EVAL:
          case Context.FEATURE_STRICT_MODE:
            return strictMode;

          case Context.FEATURE_RESERVED_KEYWORD_AS_IDENTIFIER:
            return true;

          case Context.FEATURE_WARNING_AS_ERROR:
            return warningAsError;

          case Context.FEATURE_PARENT_PROTO_PROPERTIES:
            return parentProtoProperties;
        }

        return super.hasFeature(cx, featureIndex);
    }

    @Override
    protected void onContextCreated(Context cx) {
        super.onContextCreated(cx);
        cx.putThreadLocal("engine", engine);
        cx.putThreadLocal("modules", new HashMap<Trackable, Scriptable>());
        cx.setApplicationClassLoader(engine.getClassLoader());
        cx.setWrapFactory(engine.getWrapFactory());
        cx.setLanguageVersion(languageVersion);
        cx.setOptimizationLevel(optimizationLevel);
        if (classShutter != null) {
            cx.setClassShutter(classShutter);
        }
        if (engine.isPolicyEnabled()) {
            cx.setSecurityController(new PolicySecurityController());
        }
        if (errorReporter != null) {
            cx.setErrorReporter(errorReporter);
        }
        cx.setGeneratingDebug(generatingDebug);
    }

    @Override
    protected void onContextReleased(Context cx) {
        super.onContextReleased(cx);
        cx.removeThreadLocal("engine");
        cx.removeThreadLocal("modules");
    }

    public void setStrictMode(boolean flag) {
        checkNotSealed();
        this.strictMode = flag;
    }

    public void setParentProtoProperties(boolean flag) {
        checkNotSealed();
        this.parentProtoProperties = flag;
    }

    public void setWarningAsError(boolean flag) {
        checkNotSealed();
        this.warningAsError = flag;
    }

    public void setLanguageVersion(int version) {
        Context.checkLanguageVersion(version);
        checkNotSealed();
        this.languageVersion = version;
    }

    public void setOptimizationLevel(int optimizationLevel) {
        Context.checkOptimizationLevel(optimizationLevel);
        checkNotSealed();
        this.optimizationLevel = optimizationLevel;
    }

    public void setErrorReporter(ErrorReporter errorReporter) {
        if (errorReporter == null) throw new IllegalArgumentException();
        this.errorReporter = errorReporter;
    }

    public void setGeneratingDebug(boolean generatingDebug) {
        this.generatingDebug = generatingDebug;
    }

}

@@ -888,16 +888,61 @@
 utter;%0A%0A
+    static int instructionLimit = 0xfffffff;%0A
 %0A    pub
@@ -2452,24 +2452,90 @@
 nabled()) %7B%0A
+            cx.setInstructionObserverThreshold(instructionLimit);%0A
             
@@ -2934,32 +2934,520 @@
 dules%22);%0A    %7D%0A%0A
+    /**%0A     * Implementation of%0A     * %7B@link org.mozilla.javascript.Context#observeInstructionCount(int instructionCount)%7D.%0A     * This can be used to customize %7B@link org.mozilla.javascript.Context%7D without introducing%0A     * additional subclasses.%0A     */%0A    @Override%0A    protected void observeInstructionCount(Context cx, int instructionCount) %7B%0A        if (instructionCount %3E instructionLimit) %7B%0A            throw new Error(%22Maximum instruction count exceeded%22);%0A        %7D%0A    %7D%0A%0A
     public void 

Set instruction count limit if running in secure mode.