/*
  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.ArrayList;
import java.util.List;
import java.util.Map;

import org.opengroupware.jope.appserver.publisher.IJoContext;
import org.opengroupware.jope.appserver.publisher.IJoObject;
import org.opengroupware.jope.appserver.publisher.JoClass;
import org.opengroupware.jope.eocontrol.EODataSource;
import org.opengroupware.jope.ofs.fs.IOFSFileInfo;

public class OFSFolder extends OFSBaseObject implements IJoFolderish {
  
  protected OFSFileContainerChildInfo childInfo;
  protected Map<String, Object> cacheNameToObject;
  
  /* directory contents */
  
  public OFSFileContainerChildInfo childInfo() {
    if (this.childInfo == null) {
      this.childInfo = OFSFileContainerChildInfo
        .infoForFile(this.fileManager(), this.fileInfo());
    }
    return this.childInfo;
  }

  /* container */
  
  public boolean isFolderish() {
    return true; /* not strictly necessary, but this is static info anyways */
  }

  /* contents */
  
  protected static final String[] emptyStringArray = new String[0];
  
  protected String[] collectIds(boolean _directories) {
    OFSFileContainerChildInfo ci = this.childInfo();
    if (ci == null) return null;
    
    String[] fileNames = ci.fileNames();
    int      len       = fileNames.length;
    if (len == 0)
      return emptyStringArray;
    
    List<String> ids = new ArrayList<String>(8);
    for (int i = 0; i < len; i++) {
      IOFSFileInfo info =
        this.fileManager.fileInfoForPath(this.storagePath, fileNames[i]);
      if (info.isDirectory() == _directories)
        ids.add(ci.ids[i]);
    }
    len = ids.size();
    return len == 0 ? emptyStringArray : ids.toArray(new String[len]);
  }
  
  public String[] toOneRelationshipKeys() {
    return this.collectIds(false);
  }
  public String[] toManyRelationshipKeys() {
    return this.collectIds(true);
  }
  
  public String[] objectIds() {
    OFSFileContainerChildInfo ci = this.childInfo();
    if (ci == null) return null;
    
    return ci != null ? ci.ids() : null;
  }
  
  /* IJoFolderish */
  
  public EODataSource folderDataSource(IJoContext _ctx) {
    return new OFSFolderDataSource(this, _ctx);
  }
  
  /* stored keys */
  
  public String idFromName(String _name, IJoContext _ctx) {
    if (_name == null)
      return null;
    
    int idx = _name.indexOf('.');
    if (idx == -1) return _name;
    
    return _name.substring(0, idx);
  }
  
  public Object lookupStoredName(String _name, IJoContext _ctx) {
    /* turn lookup name into lookup id (aka: cut off extension */
    
    String lookupId = this.idFromName(_name, _ctx);
    
    /* lookup File object for given id */
    
    OFSFileContainerChildInfo ci = this.childInfo();
    if (ci == null) return null;
    
    String[] files = ci.fileNames();
    int      len   = files.length;
    if (len == 0) return null;
    
    String lfile = null;
    for (int i = 0; i < len; i++) {
      if (lookupId.equals(ci.fileIds[i])) {
        lfile = files[i];
        
        // TODO: DEBUG
        if (!files[i].startsWith(lookupId)) {
          System.err.println("FOUND " + lookupId + " as " + lfile);
          
          for (int j = 0; j < len; j++) { 
            System.err.println("  id: " + ci.fileIds[j]);
            System.err.println("  =>: " + ci.fileNames[j]);
          }
        }
        break;
      }
    }
    if (lfile == null)
      return null;
    
    IOFSFileInfo linfo =
      this.fileManager.fileInfoForPath(this.storagePath, lfile);
    
    /* find factory */
    
    OFSRestorationFactory factory =
      OFSRestorationFactory.restorationFactoryInContext(_ctx);
    if (factory == null)
      return null;
    
    /* attempt to restore object */
    return factory.restoreObjectFromFileInContext
      (this, this.fileManager, linfo, _ctx);
  }
  
  /* IJoObject */
  
  public Object lookupName(String _name, IJoContext _ctx, boolean _acquire) {
    /* first check cache */
    
    if (this.cacheNameToObject != null) {
      Object o = this.cacheNameToObject.get(_name);
      if (o != null) return o;
    }
    
    /* lookup using JoClass */
    
    JoClass cls = this.joClassInContext(_ctx);
    if (cls != null) {
      Object o = cls.lookupName(this, _name, _ctx);
      if (o != null) return o;
    }
    
    /* check children */
    
    OFSFileContainerChildInfo ci = this.childInfo();
    if (ci != null && ci.hasKey(_name)) {
      Object o = this.lookupStoredName(_name, _ctx);
      if (o != null) {
        if (this.cacheNameToObject != null)
          this.cacheNameToObject.put(_name, o);
        
        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;
  }
  
  /* description */

  @Override
  public void appendAttributesToDescription(StringBuilder _d) {
    super.appendAttributesToDescription(_d);
    
    if (this.childInfo != null)
      _d.append(" has-childinfo");
  }
}
