package org.opengroupware.jope.appserver;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public abstract class WORequestHandler {
  
  protected final Log log = LogFactory.getLog("WOApplication");
  
  WOApplication application;
  
  public WORequestHandler(WOApplication _app) {
    this.application = _app;
  }
  
  /* session handling */
  
  public String sessionIDFromRequest(WORequest _rq) {
    // TODO: also check cookie
    return _rq.stringFormValueForKey(WORequest.SessionIDKey);
  }
  
  public boolean restoreSessionsUsingIDs() {
    return true;
  }
  
  public boolean autocreateSession(WOContext _ctx) {
    // TODO: implement
    return false;
  }
  
  /* request handling */
  
  public abstract WOResponse handleRequest
    (WORequest _rq, WOContext _ctx, WOSession _s);
  
  public boolean doesRejectFavicon() {
    return true;
  }

  public WOResponse handleRequest(WORequest _rq) {
    WOContext  ctx;
    WOResponse r = null;
    WOSession  session = null;
    String     sessionId;
    boolean    debugOn = this.log.isDebugEnabled();

    if (debugOn) this.log.debug("handleRequest: " + _rq);
    
    if (this.doesRejectFavicon()) {
      if ("/favicon.ico".equals(_rq.uri()))
        return null;
    }
    
    ctx = this.application.createContextForRequest(_rq);
    if (debugOn) this.log.debug("  created context: " + ctx);
    
    /* prepare session */
    
    if ((sessionId = this.sessionIDFromRequest(_rq)) != null) {
      if (sessionId.length() == 0)
        sessionId = null;
      else if (sessionId.equals("nil"))
        sessionId = null;
    }
    if (debugOn) this.log.debug("  session-id: " + sessionId);
    
    try {
      this.application.awake();
      
      /* restore session */
      
      if (this.restoreSessionsUsingIDs()) {
        if (sessionId != null) {
          if (debugOn) this.log.debug("  restore session: " + sessionId);
        
          session = this.application.restoreSessionWithID(sessionId, ctx);
          if (session == null) {
            r = this.application.handleSessionRestorationError(ctx);
            sessionId = null;
          }
        }
      
        if (r == null /* no error */ && session == null) {
          /* no error, but session is not here */
          if (this.autocreateSession(ctx)) {
            if (debugOn) this.log.debug("  autocreate session: " + sessionId);
            
            if (!this.application.refusesNewSessions()) {
              session = this.application.initializeSession(ctx);
              if (session == null)
                r = this.application.handleSessionRestorationError(ctx);
            }
            else {
              // TODO: this already failed once? will it return null again?
              r = this.application.handleSessionRestorationError(ctx);
            }
          }
        }
        
        if (debugOn) {
          if (session != null)
            this.log.debug("  restored session: " + session);
          else if (sessionId != null)
            this.log.debug("  did not restore session with id: " + sessionId);
        }
      }
    
      /* run handler specific processing */
      
      if (r == null) {
    
        r = this.handleRequest(_rq, ctx, session);
      }
      
      /* save session */
      
      // TODO: store session cookies
      
      if (ctx.hasSession()) {
        // TODO: ensure that session gets a sleep?
        this.application.saveSessionForContext(ctx);
      }
      else
        this.log.debug("no session to store ...");
    }
    catch (Exception e) {
      // TODO: call some handler method
      // TODO: ensure that session gets a sleep?
      if (debugOn) this.log.debug("  handler catched exception", e);
      r = this.application.handleException(e, ctx);
    }
    
    /* deal with missing responses */
    
    if (r == null) {
      this.log.warn("request handler produced no result.");
      r = ctx.response();
    }
    if (r == null)
      r = new WOResponse(_rq);
    
    /* tear down context */
    // TODO: send sleep() or something to tear it down?
    ctx = null;
    
    return r;
  }
}
