/*
 * Copyright (C) 2007 Helge Hess
 *
 * This file is part of JOPE.
 *
 * JOPE is free software; you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2, or (at your option) any later version.
 *
 * JOPE is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with JOPE; see the file COPYING. If not, write to the Free Software
 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
package org.opengroupware.jope.jsapp;

import org.mozilla.javascript.Context;
import org.mozilla.javascript.WrapFactory;
import org.opengroupware.jope.appserver.core.WOApplication;
import org.opengroupware.jope.appserver.core.WOContext;
import org.opengroupware.jope.appserver.core.WORequest;

/**
 * JSContext
 * <p>
 * This object enhances WOContext so that it properly sets up and tears down
 * the Rhino JavaScript context for the current thread. Its important that
 * awake() and sleep() are properly called for the transaction, but this is
 * ensured in WOApplication.
 * <p>
 * The JavaScript Context object is available using the 'jsContext' method
 * though I recommend accessing the 'jsContext' value via KVC so that it works
 * with arbitary custom classes. 
 */
public class JSContext extends WOContext {

  protected Context jsContext;

  public JSContext(WOApplication _app, WORequest _rq) {
    super(_app, _rq);
  }
  
  /* notifications */
  
  @Override
  public void awake() {
    if (this.jsContext == null) {
      /* ensure that a JS Context is available */
      this.jsContext = Context.enter();
      
      WrapFactory wf =
        (WrapFactory)this.valueForKeyPath("application.jsWrapFactory");
      if (wf != null)
        this.jsContext.setWrapFactory(wf);
    }
    super.awake();
  }
  
  @Override
  public void sleep() {
    /* ensure that the JS Context is terminated */
    try {
      super.sleep();
    }
    finally {
      if (this.jsContext != null) {
        Context.exit();
        this.jsContext = null;
      }
    }
  }
  
  /* accessors */
  
  /**
   * Method returns the Rhino JavaScript Context object. Instead of calling this
   * method directly its recommended to access the value using KVC, eg:<pre>
   *   Context jscx = (Context)this.context().valueForKey("jsContext");</pre>
   * Its more verbose but it works with arbitary objects able to provide a
   * Rhino Context.
   * 
   * @return the Rhino JavaScript Context of the thread
   */
  public Context jsContext() {
    return this.jsContext;
  }

  /* description */
  
  @Override
  public void appendAttributesToDescription(StringBuilder _d) {
    super.appendAttributesToDescription(_d);
    _d.append(this.jsContext != null ? " ctx" : " no-ctx");
  }
}
