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

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.opengroupware.jope.appserver.publisher.IJoContext;
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.JoClassRegistry;
import org.opengroupware.jope.eoaccess.EOValidation;
import org.opengroupware.jope.foundation.NSObject;
import org.opengroupware.jope.foundation.UString;
import org.opengroupware.jope.ofs.fs.IOFSFileInfo;
import org.opengroupware.jope.ofs.fs.IOFSFileManager;

/*
 * 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 IOFSFileManager fileManager;
  protected String[]        storagePath; /* path in filemanager */
  
  protected Object container;
  protected String nameInContainer;
  
  /* init */
  
  public void setLocation(Object _container, String _name) {
    this.container       = _container;
    this.nameInContainer = _name;
    
    if (this.nameInContainer == null && this.container != null && 
        log().isWarnEnabled())
    {
      log().warn("OFS object created with container but w/o name:" +
                 "\n  file:      " + 
                 UString.componentsJoinedByString(this.storagePath, "/") +
                 "\n  container: " + _container +
                 "\n  class:     " + this.getClass().getSimpleName());
    }
  }
  
  public void setStorageLocation(IOFSFileManager _fm, String[] _storepath) {
    this.fileManager = _fm;
    this.storagePath = _storepath;
  }
  
  /* 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 IOFSFileManager fileManager() {
    return this.fileManager;
  }
  public String[] storagePath() {
    return this.storagePath;
  }
  
  public IOFSFileInfo fileInfo() {
    return this.fileManager != null
      ? this.fileManager.fileInfoForPath(this.storagePath) : null;
  }
  
  public Date lastModified() {
    IOFSFileInfo info = this.fileInfo();
    return info != null ? new Date(info.lastModified()) : null;
  }
  
  public long size() {
    /* Note: this is actually "storageSize", rendering result could be diff */
    IOFSFileInfo info = this.fileInfo();
    return info != null ? info.length() : null;
  }
  
  public String pathExtension() {
    /* Note: this is the path extension in the store */
    IOFSFileInfo info = this.fileInfo();
    return info != null ? info.pathExtension() : null;
  }
  
  /* WebDAV support */
  
  public Object davResourceType() {
    return this.isFolderish() ? "collection" : null;
  }
  
  /* JoClass */
  
  public JoClass joClassInContext(IJoContext _ctx) {
    if (_ctx == null) {
      log.warn("missing context to determine JoClass: " + this);
      return null;
    }
    
    JoClassRegistry reg = _ctx.joClassRegistry();
    if (reg == null) {
      log.warn("context has no class registry: " + _ctx);
      return null;
    }
    
    return reg.joClassForJavaObject(this, _ctx);
  }
  
  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;
    }
    
    /* 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.fileManager == null || this.storagePath == null)
      return null;
    
    if ("NSFileSize".equals(_key))
      return this.storagePath != 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(StringBuilder _d) {
    super.appendAttributesToDescription(_d);
    
    if (this.container == null) {
      _d.append(" ROOT " +
          UString.componentsJoinedByString(this.storagePath, "/"));
    }
    else
      _d.append(" contained=" + this.nameInContainer);
  }
}
