/*
 * The contents of this file are subject to the Mozilla Public License Version 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.mozilla.org/MPL/>.
 * 
 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
 * language governing rights and limitations under the License.
 * 
 * The Original Code is the Venice Web Communities System.
 * 
 * The Initial Developer of the Original Code is Eric J. Bowersox <erbo@ricochet.com>,
 * for Silverwrist Design Studios.  Portions created by Eric J. Bowersox are
 * Copyright (C) 2002-2004 Eric J. Bowersox/Silverwrist Design Studios.  All Rights Reserved.
 * 
 * Contributor(s): 
 */
package com.silverwrist.venice.ui.servlet;

import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.log4j.*;
import com.silverwrist.venice.core.*;
import com.silverwrist.venice.except.*;
import com.silverwrist.venice.ui.*;
import com.silverwrist.venice.ui.helpers.*;
import com.silverwrist.venice.ui.script.*;

class HttpVeniceUISession implements VeniceUISession, HttpSessionBindingListener
{
  /*--------------------------------------------------------------------------------
   * Static data members
   *--------------------------------------------------------------------------------
   */

  private static final String SESSION_ATTRIBUTE_STEM = "venice.vars.";

  private static Category logger = Category.getInstance(HttpVeniceUISession.class);

  /*--------------------------------------------------------------------------------
   * Attributes
   *--------------------------------------------------------------------------------
   */

  private HttpSession session;         // HTTP session value
  private UserContext user;            // user context associated with this session
  private boolean new_session = true;  // is this a new session?
  private HttpVeniceUISessionList m_session_list = null;

  /*--------------------------------------------------------------------------------
   * Constructor
   *--------------------------------------------------------------------------------
   */

  HttpVeniceUISession(HttpServletRequest request, HttpSession session, VeniceEngine engine)
      throws ServletException
  {
    this.session = session;   // save off the session variable
    try
    { // tell the engine to create us a user context
      user = engine.createUserContext(request.getRemoteAddr());

    } // end try
    catch (DataException e)
    { // context creation failed - remap the exception
      logger.error("Session creation failed: " + e.getMessage(),e);
      throw new ServletException("Session creation failed: " + e.getMessage(),e);

    } // end catch

  } // end constructor

  /*--------------------------------------------------------------------------------
   * Implementations from interface VeniceUISession
   *--------------------------------------------------------------------------------
   */

  public long getCreationTime()
  {
    return session.getCreationTime();

  } // end getCreationTime

  public String getID()
  {
    return session.getId();

  } // end getID

  public long getLastAccessedTime()
  {
    return session.getLastAccessedTime();

  } // end getLastAccessedTime

  public void setMaxInactiveInterval(int interval)
  {
    session.setMaxInactiveInterval(interval);

  } // end setMaxInactiveInterval

  public int getMaxInactiveInterval()
  {
    return session.getMaxInactiveInterval();

  } // end getMaxInactiveInterval

  public Object getAttribute(String name)
  {
    return session.getAttribute(SESSION_ATTRIBUTE_STEM + name);

  } // end getAttribute

  public Enumeration getAttributeNames()
  {
    Enumeration raw = session.getAttributeNames();
    ArrayList rc = new ArrayList();
    while (raw.hasMoreElements())
    { // look for attributes we've added
      String tmp = (String)(raw.nextElement());
      if (tmp.startsWith(SESSION_ATTRIBUTE_STEM))
	rc.add(tmp.substring(SESSION_ATTRIBUTE_STEM.length()));

    } // end while

    return Collections.enumeration(rc);

  } // end getAttributeNames

  public void setAttribute(String name, Object o)
  {
    session.setAttribute(SESSION_ATTRIBUTE_STEM + name,o);

  } // end setAttribute

  public void removeAttribute(String name)
  {
    session.removeAttribute(SESSION_ATTRIBUTE_STEM + name);

  } // end removeAttribute

  public void invalidate()
  {
    session.invalidate();

  } // end invalidate

  public UserContext getUser()
  {
    return user;

  } // end getUser

  public void setUser(UserContext user)
  {
    this.user = user;

  } // end setUser

  public void preprocess(RequestInput ri) throws ServletException
  {
    if (new_session)
    { // new session - we need to run the init script
      String script_name = ri.getConfigProperty("session.init");
      ScriptSupport ssup = (ScriptSupport)(ri.queryService(ScriptSupport.class));
      String script_file = ssup.getScriptName(script_name);
      String logger_name = ssup.getScriptLoggerName(script_name);
      if (logger.isDebugEnabled())
	logger.debug("EXECUTING " + script_file);

      // get the script manager and execute it!
      ScriptManager smgr = (ScriptManager)(ri.queryService(ScriptManager.class));
      smgr.pushContext();
      try
      { // add the session to the bound variables
	smgr.register("session",this);
	try
	{ // execute the script!
	  smgr.exec(new File(script_file),logger_name,new ScriptReturn());

	} // end try
	catch (ScriptingException e)
	{ // there's a script exception here...
	  logger.error("Session init failed: " + e.getMessage(),e);
	  throw new ServletException("Session init failed: " + e.getMessage(),e);

	} // end catch
	catch (ThrowableContent tc)
	{ // ignore this
	  logger.warn("session init script threw a ThrowableContent of type " + tc.getClass().getName());

	} // end catch

      } // end try
      finally
      { // pop the context before we go
	smgr.popContext();
	new_session = false;

      } // end finally

      // add this session to the global list
      m_session_list = HttpVeniceUISessionList.get(ri);
      m_session_list.joinSession(this);

    } // end if

  } // end preprocess

  /*--------------------------------------------------------------------------------
   * Implementations from interface HttpSessionBindingListener
   *--------------------------------------------------------------------------------
   */

  public void valueBound(HttpSessionBindingEvent event)
  { // do nothing
  } // end valueBound

  public void valueUnbound(HttpSessionBindingEvent event)
  {
    if (m_session_list!=null)
      m_session_list.partSession(this);
    m_session_list = null;
    this.session = null;
    this.user = null;

  } // end valueUnbound

} // end class HttpVeniceUISession
