/*
  Copyright (C) 2006 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.appserver.core;

import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.opengroupware.jope.appserver.templates.WOSubcomponentInfo;
import org.opengroupware.jope.appserver.templates.WOTemplate;
import org.opengroupware.jope.appserver.templates.WOTemplateBuilder;
import org.opengroupware.jope.foundation.NSClassLookupContext;
import org.opengroupware.jope.foundation.NSJavaRuntime;
import org.opengroupware.jope.foundation.NSObject;

/*
 * WOComponentDefinition
 * 
 * The component definition contains the information required to construct
 * a WOComponent object. That is, the component class and its template.
 */
public class WOComponentDefinition extends NSObject {

  protected final Log log = LogFactory.getLog("WOResourceManager");
  
  protected String     name;
  protected Class      componentClass;
  protected WOTemplate template;
  
  public WOComponentDefinition(String _name, Class _compClass) {
    this.name = _name;
    this.componentClass = _compClass;
  }
  
  /* create the component */
  
  public WOComponent instantiateComponent
    (NSClassLookupContext _rm, WOContext _ctx)
  {
    /* Allocate component. We do not use a specific constructor because
     * this would require all subclasses to implement it. Which is clumsy Java
     * crap.
     */
    WOComponent component = (WOComponent)
      NSJavaRuntime.NSAllocateObject(this.componentClass);
    
    /* Set the name of the component. This is important because not all
     * components need to have a strictly associated class (eg templates w/o
     * a class or scripted components)
     */
    if (this.name != null) component._setName(this.name);
    
    /* Initialize component for a given context. Note that the component may
     * choose to return a replacement.
     */
    component = component.initWithContext(_ctx);
    
    /* Setup subcomponents. */
    if (this.template != null) {
      Map<String,WOComponent> childComponents =
        this.instantiateChildComponentsInTemplate(this.template, _ctx);
      
      component._setSubcomponents(childComponents);
      component.setTemplate(this.template);
    }
    
    /* return new component */
    return component;
  }
  
  public Map<String,WOComponent> instantiateChildComponentsInTemplate
    (WOTemplate _template, WOContext _ctx)
  {
    Map<String, WOSubcomponentInfo> childInfos = _template.subcomponentInfos();
    if (childInfos == null)
      return null;
    
    Map<String,WOComponent> childComponents =
      new HashMap<String, WOComponent>(childInfos.size());
    
    for (String k: childInfos.keySet()) {
      WOSubcomponentInfo childInfo = childInfos.get(k);
      
      // TODO: create fault
      WOComponentFault child = new WOComponentFault();
      child = (WOComponentFault)child.initWithContext(_ctx);
      child.setName(childInfo.componentName());
      child.setBindings(childInfo.bindings());
      childComponents.put(k, child);
    }
    
    return childComponents;
  }
  
  /* accessors */
  
  public void setTemplate(WOTemplate _template) {
    this.template = _template;
  }
  public WOTemplate template() {
    // TODO: load on demand?
    return this.template;
  }
  
  /* cache */
  
  public void touch() {
    // TODO: add a timestamp
  }
  
  /* loading */
  
  protected static final String builderPkgName =
    "org.opengroupware.jope.appserver.templates";
  
  public boolean load(String _type, URL _templateURL, URL _wodURL,
                      NSClassLookupContext _clsctx)
  {
    if (this.template != null) /* already loaded */
      return true;
    if (_templateURL == null)
      return false;
    
    this.log.debug("load template: " + _templateURL);
    
    /* find class used to build the template */
    
    Class builderClass;
    builderClass = NSJavaRuntime.NSClassFromString
                     (builderPkgName + "." + _type + "TemplateBuilder");
    if (builderClass == null) {
      this.log.error("did not find template builder for type: " + _type);
      return false;
    }
    
    /* instantiate object used to build the template */
    
    WOTemplateBuilder builder;
    builder = (WOTemplateBuilder)NSJavaRuntime.NSAllocateObject(builderClass);
    if (builder == null) {
      this.log.error("could not instantiate builder for type: " + _type);
      return false;
    }
    
    /* ... build the template */
    
    this.template = builder.buildTemplate(_templateURL, _wodURL, _clsctx);
    return this.template != null ? true : false;
  }
  
  public WOTemplateBuilder templateBuilderForURL(URL _url) {
    // TODO: implement me
    return null;
  }
  
  /* description */

  @Override
  public void appendAttributesToDescription(StringBuffer _d) {
    super.appendAttributesToDescription(_d);
    
    if (this.name != null)
      _d.append(" name=" + this.name);
    if (this.componentClass != null)
      _d.append(" class=" + this.componentClass.getSimpleName());
    if (this.template != null)
      _d.append(" template=" + this.template);
  }
}
