package org.opengroupware.jope.ofs;

import java.io.File;
import java.util.Date;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.opengroupware.jope.appserver.publisher.IJoLocation;
import org.opengroupware.jope.appserver.publisher.IJoObject;
import org.opengroupware.jope.appserver.publisher.JoClass;
import org.opengroupware.jope.appserver.publisher.JoContext;
import org.opengroupware.jope.eoaccess.EOValidation;
import org.opengroupware.jope.foundation.NSObject;
import org.opengroupware.jope.foundation.UString;

/*
 * OFSBaseObject
 * 
 * Base class for the two major branches of OFS objects: OFSFile and OFSFolder.
 */
public abstract class OFSBaseObject extends NSObject
  implements IJoObject, IJoLocation, EOValidation
{
  protected static final Log log = LogFactory.getLog("JoOFS");
  
  protected File   file;
  protected Object container;
  protected String nameInContainer;
  
  public OFSBaseObject(Object _container, String _name, File _file) {
    this.container       = _container;
    this.nameInContainer = _name;
    this.file            = _file;
  }
  
  /* IJoLocation interface */
  
  public Object container() {
    return this.container;
  }
  public String nameInContainer() {
    return this.nameInContainer;
  }
  
  public String[] pathInContainer() {
    return IJoLocation.Utility.pathToRoot(this);
  }
  public String stringPathInContainer() {
    // TODO: not recommended to use this to avoid escaping issues
    // TODO: fix escaping of '/'
    String[] p = this.pathInContainer();
    if (p        == null) return null;
    if (p.length == 0)    return "/";
    return "/" + UString.componentsJoinedByString(this.pathInContainer(), "/");
  }
  
  /* container */
  
  public boolean isFolderish() {
    return this instanceof IJoFolderish;
  }
  
  /* EOValidation interface */

  public Exception validateForSave() {
    // TODO: iterate over properties and send them validateValueForKey
    return null; /* everything is awesome */
  }
  
  public Exception validateForInsert() {
    return this.validateForSave();
  }
  public Exception validateForDelete() {
    return this.validateForSave();
  }
  public Exception validateForUpdate() {
    return this.validateForSave();
  }
  
  /* file attributes */
  
  public Date lastModified() {
    return this.file != null ? new Date(this.file.lastModified()) : null;
  }
  
  public long size() {
    return this.file != null ? this.file.length() : -1;
  }
  
  /* WebDAV support */
  
  public Object davResourceType() {
    return this.isFolderish() ? "collection" : null;
  }
  
  /* JoClass */
  
  public JoClass joClassInContext(JoContext _ctx) {
    return _ctx.joClassRegistry().joClassForJavaObject(this, _ctx);
  }
  
  public Object lookupName(String _name, JoContext _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;
    }
    
    /* if we shall acquire, continue at parent */
    
    if (_acquire && this.container != null)
      return ((IJoObject)this.container).lookupName(_name, _ctx, true /* aq */);
    
    return null;
  }
  
  /* key/value coding */
  
  public Object valueForFileSystemKey(String _key) {
    if ("NSFileType".equals(_key))
      return this.isFolderish() ? "NSFileTypeDirectory" : "NSFileTypeRegular";
    
    if ("NSFileName".equals(_key))
      return this.nameInContainer();
    
    if ("NSFilePath".equals(_key))
      return this.pathInContainer();
    
    if ("NSFileModificationDate".equals(_key))
      return this.lastModified();
    
    if (this.file == null)
      return null;
    
    if ("NSFileSize".equals(_key))
      return this.file != null ? new Long(this.size()) : null;
    
    log().warn("unprocessed NSFile.. KVC key: '" + _key + "': " + this);
    return null;
  }
  
  @Override
  public Object handleQueryWithUnboundKey(String _key) {
    if ("this".equals(_key) || "self".equals(_key))
      return this;
    
    if (_key.startsWith("NSFile"))
      return this.valueForFileSystemKey(_key);
    
    return super.handleQueryWithUnboundKey(_key);
  }
  
  /* logging */
  
  public Log log() {
    return log;
  }
  
  /* description */

  @Override
  public void appendAttributesToDescription(StringBuffer _d) {
    super.appendAttributesToDescription(_d);
    
    if (this.container == null)
      _d.append(" ROOT " + this.file.getAbsolutePath());
    else
      _d.append(" contained");
  }
}
