package org.opengroupware.jope.appserver;

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.NSJavaRuntime;
import org.opengroupware.jope.foundation.NSClassLookupContext;

public class WOComponentDefinition {

  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 WOElement template() {
    // TODO: implement me
    return null;
  }
  
  /* 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;
  }
}
