package org.opengroupware.jope.eoaccess;

import java.net.URL;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.opengroupware.jope.foundation.NSObject;

/*
 * EOModel
 * 
 * Basically a set of EOEntities ...
 * 
 * TODO: document more.
 * 
 * XML file format:
 *   <model version="1.0">
 *     <entity tableNameLike="subscriber*"> <!-- dynamically load tables -->
 *       <attribute name="subscriber" />
 *     </entity>
 *     
 *     <entity tableName="account">
 *       <!-- dynamically load all attributes -->
 *       <attribute columnNameLike="*" />
 *     </entity>
 *   </model>
 */
public class EOModel extends NSObject {
  protected static final Log log = LogFactory.getLog("EOModel");
  
  /* ivars */

  protected URL        url;
  protected EOEntity[] entities;
  
  /* construction */
  
  public EOModel() {    
  }
  
  public EOModel(EOEntity[] _entities) {
    this(null, _entities);
  }
  
  public EOModel(URL _url, EOEntity[] _entities) {
    this();
    this.url = _url;
    this.entities = _entities;
  }
  
  public static EOModel loadModel(URL _url) throws Exception {
    EOModelLoader loader = new EOModelLoader();
    EOModel model = loader.loadModelFromURL(_url);
    if (model == null)
      throw loader.lastException();
    return model;
  }
  
  /* accessors */
  
  public URL pathURL() {
    return this.url;
  }
  
  /* retrieve model objects */
  
  public EOEntity entityNamed(String _name) {
    if (_name == null) return null;
    if (this.entities == null) return null;
    
    for (int i = 0; i < this.entities.length; i++) {
      if (_name.equals(this.entities[i].name()))
        return this.entities[i];
    }
    return null;
  }
  public EOEntity firstEntityWithExternalName(String _tableName) {
    if (_tableName == null) return null;
    if (this.entities == null) return null;
    
    for (int i = 0; i < this.entities.length; i++) {
      if (_tableName.equals(this.entities[i].externalName()))
        return this.entities[i];
    }
    return null;
  }
  
  public EOEntity[] entities() {
    return this.entities;
  }
  public String[] entityNames() {
    if (this.entities == null) return null;

    String[] names = new String[this.entities.length];
    for (int i = 0; i < this.entities.length; i++)
      names[i] = this.entities[i].name();
    return names;
  }
  
  public EOEntity entityForObject(Object _object) {
    if (_object == null || this.entities == null)
      return null;
    
    /* search for an entity which has the mentioned class name */
    
    String className = _object.getClass().getName();
    String simpleName = _object.getClass().getSimpleName();
    for (int i = 0; i < this.entities.length; i++) {
      String clsname = this.entities[i].className();
      if (clsname == null) continue;
      
      if (clsname.equals(className) || clsname.equals(simpleName))
        return this.entities[i];
    }
    
    return null;
  }
  
  /* connect relationship */
  
  public void connectRelationships() {
    if (this.entities == null)
      return;
    
    for (int i = 0; i < this.entities.length; i++)
      this.entities[i].connectRelationshipsInModel(this);
  }
  
  /* pattern models */
  
  public boolean isPatternModel() {
    if (this.entities == null)
      return true;
    
    for (int i = 0; i < this.entities.length; i++) {
      if (this.entities[i].isPatternEntity())
        return true;
    }
    return false;
  }
  
  public boolean hasEntitiesWithExternalNamePattern() {
    if (this.entities == null) /* yes, fetch all! */
      return true;
    
    for (int i = 0; i < this.entities.length; i++) {
      if (this.entities[i].hasExternalNamePattern())
        return true;
    }
    return false;
  }
  
  /* prototypes */
  
  public EOAttribute prototypeAttributeNamed(String _name) {
    if (_name == null) return null;
    
    EOEntity prototypeEntity = this.entityNamed("EOPrototype");
    if (prototypeEntity == null) return null;
    
    return prototypeEntity.attributeNamed(_name);
  }
  
  public String[] availablePrototypeAttributeNames() {
    EOEntity prototypeEntity = this.entityNamed("EOPrototype");
    if (prototypeEntity == null) return null;

    EOAttribute[] attributes = prototypeEntity.attributes();
    if (attributes == null) return null;
    
    String[] names = new String[attributes.length];
    for (int i = 0; i < attributes.length; i++)
      names[i] = attributes[i].name();
    return names;
  }
  
  /* names */
  
  public void beautifyNames() {
    if (this.entities == null)
      return;
    
    for (int i = 0; i < this.entities.length; i++)
      this.entities[i].beautifyNames();
  }
    
  /* description */
  
  public void appendAttributesToDescription(StringBuffer _d) {
    super.appendAttributesToDescription(_d);

    if (this.isPatternModel())
      _d.append(" pattern");
    
    if (this.entities.length == 0)
      _d.append(" no-entities");
    else {
      _d.append(" entities: {\n");
      for (int i = 0; i < this.entities.length; i++) {
        this.entities[i].appendAttributesToDescription(_d);
        _d.append(i == 0 ? "\n" : ",\n");
      }
      _d.append("}");
    }
  }
}
