/*
 * 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.ofs;

import java.net.URL;

import org.opengroupware.jope.appserver.core.WOComponent;
import org.opengroupware.jope.appserver.core.WOComponentDefinition;
import org.opengroupware.jope.appserver.core.WOContext;
import org.opengroupware.jope.appserver.core.WODirectActionRequestHandler;
import org.opengroupware.jope.appserver.core.WOResourceManager;
import org.opengroupware.jope.appserver.publisher.IJoCallable;
import org.opengroupware.jope.appserver.publisher.IJoComponentDefinition;
import org.opengroupware.jope.appserver.publisher.IJoContext;
import org.opengroupware.jope.appserver.publisher.JoClass;
import org.opengroupware.jope.eocontrol.EODataSource;


/**
 * OFSWOComponent
 * <p>
 * OFS object representing a .wo component wrapper in the filesystem.
 */
public class OFSWOComponent extends OFSFolder
  implements IJoCallable, IJoComponentDefinition
{
  // TBD: This is still incomplete. At least the template/wod URLs must be
  //      generated, which might require an API change in the FSFileInfo thingy.
  //      But subclasses can already use the sucker.
  // TBD: do we really want to inherit OFSFolder? Doesn't seem right, maybe we
  //      want to expose COMPONENT/-m/ as a managed OFSFolder?
  
  /* folderish */

  @Override
  public EODataSource folderDataSource(IJoContext _ctx) {
    return null; /* we are not really a folder */
  }
  
  /* IJoObject */
  
  @Override
  public Object lookupName(String _name, IJoContext _ctx, boolean _acquire) {
    /* lookup using JoClass */
    
    JoClass cls = this.joClassInContext(_ctx);
    if (cls != null) {
      Object o = cls.lookupName(this, _name, _ctx);
      if (o != null) return o;
    }

    /* Eg this is called when we return the WOComponent from the direct action
     * request handler.
     * The contents of the wrapper are our business, and are not exposed to
     * the web.
     * Eg:
     *   /MyStuff/Main/default
     * The 'default' is processed as PATH_INFO. But this is impossible:
     *   /MyStuff/Main/Main.html
     * The OFS contained template is NOT a user path.
     * 
     * However, for the management interface we might want to expose those
     * under a special key which is properly protected, eg
     *   Main/-m/Main.html
     */
    return null; /* we stop here and process the path_info in da call*/
  }

  
  /* IJoCallable */

  /**
   * The implementation of this call method invokes the
   * primaryCallComponentAction() function of WODirectActionRequestHandler
   * to trigger a component action.
   */
  public Object callInContext(Object _object, IJoContext _ctx) {
    WOContext wctx = (WOContext)_ctx;
    String actionName = "default";

    if ((actionName = wctx.request().formAction()) == null) {
      String[] handlerPath = _ctx.joTraversalPath().pathInfo();
      if (handlerPath != null && handlerPath.length > 0)
        actionName = handlerPath[0];
    }
    
    Object jr = WODirectActionRequestHandler.primaryCallComponentAction
      (this.nameInContainer, actionName, wctx);

    return this.postProcessCallResult(_object, jr, _ctx);
  }

  public boolean isCallableInContext(IJoContext _ctx) {
    // TBVD: is this required? I guess so.
    return _ctx instanceof WOContext;
  }

  
  /**
   * Post process the results of callInContext(). This can be useful for
   * subclass which are some kind of bridge which requires unwrapping of the
   * result (eg JSJoComponet).
   * <p>
   * The default implementation just returns the result as-is.
   * 
   * @param _object - the object the method was called on
   * @param _result - the result of the call
   * @param _ctx    - the context in which all this happens
   * @return the unwrapped results
   */
  public Object postProcessCallResult
    (Object _object, Object _result, IJoContext _ctx)
  {
    return _result;
  }

  
  /* being a component definition */
  
  /**
   * This is called by the JoContainerResourceManager to determine the
   * WOComponent class of a contained component. This is only called for
   * WOComponents, not for dynamic elements.
   * 
   * @param _name - the name of the component being instantiated (eg Name)
   * @param _rm   - the resource manager which manages the instantiation
   * @return the WOComponent subclass to be used for the new component
   */
  public Class lookupComponentClass(String _name, WOResourceManager _rm) {
    // this is a candidate for overriding
    // TBD: allow the component to contain instructions where the logic is
    // (eg def of a custom subclass to use)
    Class cls = _rm.lookupClass(_name);
    return WOComponent.class.isAssignableFrom(cls) ? cls : WOComponent.class;
  }
  
  public URL templateURL(String _name) {
    return null; // TBD: implement me
  }
  public URL wodURL(String _name) {
    return null; // TBD: implement me
  }
  
  /**
   * This method is supposed to return an initialized WOComponentDefinition
   * instance, which outlines the 'plan' on how to create the actual component.
   * 
   * @param _name  - the name of the component being instantiated (eg Main)
   * @param _langs - the languages the lookup is for
   * @param _rm    - the resource manager in charge
   * @return the WOComponentDefinition
   */
  public WOComponentDefinition definitionForComponent
    (String _name, String[] _langs, WOResourceManager _rm)
  {
    // TBD: should we make WOComponentDefinition an interface?!
    
    /* find template and wod */
    
    URL templateData = this.templateURL(_name);
    URL wodData      = this.wodURL(_name);
    
    /* def */

    WOComponentDefinition cdef = new WOComponentDefinition
      (_name, this.lookupComponentClass(_name, _rm));

    /* load it */

    if (!cdef.load("WOWrapper", templateData, wodData, _rm)) {
      log.error("failed to load template.");
      return null;
    }
    return cdef;
  }

}
