// DirectoryResource.java
// $Id: DirectoryResource.java,v 1.44 1998/02/13 10:21:36 bmahe Exp $
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html

package org.w3c.jigsaw.resources ;

import java.util.*;
import java.io.*;

import org.w3c.tools.resources.*;
import org.w3c.tools.resources.indexer.*;
import org.w3c.jigsaw.frames.NegotiatedFrame;

public class DirectoryResource 
             extends org.w3c.tools.resources.DirectoryResource 
{

  /**
   * Attribute index - Should this directory support content negotiation.
   */
  protected static int ATTR_NEGOTIABLE = -1 ;

  static {
    Attribute a   = null ;
    Class     cls = null ;
    // Get a pointer to our class.
    try {
      cls = Class.forName("org.w3c.jigsaw.resources.DirectoryResource") ;
    } catch (Exception ex) {
      ex.printStackTrace() ;
      System.exit(1) ;
    }
    // The negotiate flag
    a = new BooleanAttribute("negotiable"
			     , Boolean.FALSE
			     , Attribute.EDITABLE) ;
    ATTR_NEGOTIABLE = AttributeRegistry.registerAttribute(cls, a) ;
  }

  /**
   * Get the negotiable flag for this directory.
   * When turned to <strong>true</strong>, this flag indicates to the
   * directory resource that it should automatically build negotiated 
   * resources ont op of all existing resources.
   * <p>You should know, at least, that turning this flag on has some
   * not so small cost in terms of the size of the index files, and some
   * not so small costs in CPU time when detecting not found documents. 
   * Otherwise, in all other situations its cost is probably negligible.
   * @return A boolean, <strong>true</strong> if the directory is extensible
   * <strong>false</strong> otherwise.
   */
  public boolean getNegotiableFlag() {
    return getBoolean(ATTR_NEGOTIABLE, false) ;
  }

  private String getUnextendedName(String name) {
    int strlen = name.length() ;
    for (int i = 0 ; i < strlen ; i++) {
      // FIXME: Should use the system props to get the right sep
      if ( name.charAt(i) == '.' ) {
	if ( i == 0 )
	  return null ;
	return name.substring(0, i) ;
      }
    }
    return null ;
  }

  /**
   * Update a negotiable resource.
   * Given the name of a resource that exists, create or update the 
   * attributes of a resource that allows to negotiate its content.
   * <p>I hate this part here: it has nothing to do within the directory
   * resource itself, and the indexer shouldn't know that much about
   * directory resource, so I am stuck.
   * @param name The name of the newly created resource.
   */
  public synchronized void updateNegotiableResource(String name) {
    // Does the maintainer really wants us to perform this ugly hack ?
    if ( ! getNegotiableFlag() )
      return ;
    // Check for the corresponding negotiable resource:
    String noext = getUnextendedName(name) ;
    if ( noext == null ) {
      return ;
    } else {
      ResourceReference rr = lookup(noext);
      ResourceReference rr_neg_frame = null;

      if (rr != null) {
	try {
	  FramedResource r = (FramedResource)rr.lock();
	  Class nClass = Class.forName("org.w3c.jigsaw.frames.NegotiatedFrame");
	  rr_neg_frame = r.getFrameReference(nClass);
	  if (rr_neg_frame == null) 
	    return;
	} catch (ClassNotFoundException cex) {
	  return;
	} catch (InvalidResourceException ex) {
	  return;
	} finally {
	  rr.unlock();
	}
      }

      if (rr_neg_frame == null) {
	// we can't add a NegotiatedFrame to an existing resource.
	if (rr == null) {
	  // create the resource.
	  FramedResource resource = new FramedResource();
	  Hashtable defs = new Hashtable(10) ;
	  defs.put("identifier", noext);
	  ResourceContext context = updateDefaultChildAttributes(defs);
	  resource.initialize(defs);
	  addResource(resource, defs);
	  // add a NegotiatedFrame.
	  String variants[] = new String[1] ;
	  variants[0] = name ;
	  NegotiatedFrame negotiated = new NegotiatedFrame();
	  Hashtable f_defs = new Hashtable(10) ;
	  f_defs.put("variants", variants) ;
	  resource.registerFrame(negotiated, f_defs);
	} 
      } else {
	try {
	  NegotiatedFrame negotiated = (NegotiatedFrame) rr_neg_frame.lock();
	  String variants[]  = negotiated.getVariantNames() ;
	  boolean exists = false;
	  for ( int i=0 ; i < variants.length ; i++ ) {
	    if (variants[i].equals(name))
	      exists = true;
	  }
	  if (!exists) {
	    String nvariants[] = new String[variants.length+1] ;
	    System.arraycopy(variants, 0, nvariants, 0, variants.length);
	    nvariants[variants.length] = name ;
	    negotiated.setVariants(nvariants) ;
	  }
	} catch (InvalidResourceException ex) {
	  //FIXME
	} finally {
	  rr_neg_frame.unlock();
	}
      }
    }
  }

  protected Resource index(String name, Hashtable defs) {
    Resource resource = super.index(name, defs);
    if ((resource != null) && ( getNegotiableFlag() )) 
      updateNegotiableResource(name) ;
    return resource;
  }

}
