/* **************************************************************************

  $Archive: /njcl_v2/src/com/novell/service/file/nw/naming/FSAttribute.java $
  $Revision: 7 $
  $Modtime: 1/19/00 12:15p $
 
  Copyright (c) 1998 Novell, Inc.  All Rights Reserved.

  THIS WORK IS  SUBJECT  TO  U.S.  AND  INTERNATIONAL  COPYRIGHT  LAWS  AND
  TREATIES.   NO  PART  OF  THIS  WORK MAY BE  USED,  PRACTICED,  PERFORMED
  COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED,  ABRIDGED, CONDENSED,
  EXPANDED,  COLLECTED,  COMPILED,  LINKED,  RECAST, TRANSFORMED OR ADAPTED
  WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL, INC. ANY USE OR EXPLOITATION
  OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO
  CRIMINAL AND CIVIL LIABILITY.

****************************************************************************/

package com.novell.service.file.nw.naming;

import java.util.Enumeration;
import java.util.Vector;

import javax.naming.NamingException;
import javax.naming.NamingEnumeration;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.DirContext;

import com.novell.utility.naming.directory.StaticAttributeValue;

/**@internal
 * This class extends javax.naming.Attribute in order to handle static
 * attribute values and to handle attribute definitions in the file system
 * schema.
 *
 * <p>The constructor allows two schema contexts to be passed in to allow
 * each instance to return the appropriate schema contexts when
 * getAttributeDefinition() and getAttributeSyntaxDefinition() are called.
 * </p>
 */
public class FSAttribute extends BasicAttribute
{
   private StaticAttributeValue attributeValue = null;
   private DirContext attrDef;
   private DirContext syntaxDef;
   private Enumeration attributeEnumerator = null;
   private boolean avStripped = false;
   private boolean lazyAlreadyReturned = false;

   public FSAttribute(
            String id, StaticAttributeValue attributeValue, 
            DirContext attrDef, DirContext syntaxDef)
   {
      super(id);

      this.attributeValue = attributeValue;
      this.attrDef = attrDef;
      this.syntaxDef = syntaxDef;
      checkState();  // this kills late bind - value is obtained now!
   }

   public Object clone()
   {
      checkState();
      FSAttribute obj = (FSAttribute) super.clone();
      obj.attributeValue = attributeValue;
      obj.attrDef = attrDef;
      obj.syntaxDef = syntaxDef;
      obj.attributeEnumerator = attributeEnumerator;
      obj.avStripped = avStripped;
      obj.lazyAlreadyReturned = lazyAlreadyReturned;
      return obj;
   }

   public boolean contains(Object attrVal)
   {
      checkState();
      return super.contains(attrVal);
   }

   public boolean equals(Object obj)
   {
      checkState();
      if (super.equals(obj))
      {
         if (obj instanceof FSAttribute)   
         {
            FSAttribute fsAttr = (FSAttribute)obj;
            if (fsAttr.getAttributeDefinition() == attrDef &&
                fsAttr.getAttributeSyntaxDefinition() == syntaxDef)
                  return true;
         }
      }
      return false;
   }

   public DirContext getAttributeDefinition()
   {
      return attrDef;
   }

   public DirContext getAttributeSyntaxDefinition ()
   {
      return syntaxDef;
   }

   public int size()
   {
      checkState();
      return super.size();
   }

   public NamingEnumeration getAll()
      throws NamingException
   {
      checkState();
      return super.getAll();
   }

   /**
    * Returns a lazy evaluation enumerator
    * 
    * <p>Returns an enumerator that only hits the wire when the 
    * hasMoreElements and/or the nextElement methods are called.  All 
    * possible attribute values are retrieved one at a time, thereby allowing
    * the user to optimize the wire, if he has found want he wants.
    * </p>
    * <p>This method has the following limitations:  Other Attribute methods
    * which rely on the Attributes value vector can not be used after making 
    * this call, doing so will cause an java.lang.IllegalStateException to
    * be thrown.  Calling any of these methods before calling this method 
    * will cause this method to throw an IllegalStateException.  If this
    * method is called more than once, an IllegalStateException will be 
    * thrown.
    * </p>
    *
    * @return                    Enumeration of attribute values
    * @exception                 java.lang.IllegalStateException
    *
    */
    
   public Enumeration getValuesLazyEvaluation()
   {
      if (lazyAlreadyReturned)
         throw new IllegalStateException();
      
      if (avStripped)
         throw new IllegalStateException();

      lazyAlreadyReturned = true;
      return new FSAttributeValueEnumerator(attributeValue);
   }

   public void clear()
   {
      checkState();
      super.clear();
   }

   public boolean remove(Object attrVal)
   {
      checkState();
      return super.remove(attrVal);
   }

   public boolean add(Object attrVal)
   {
      checkState();
      return super.add(attrVal);
   }

   public String toString()
   {
      checkState();
      String superString = super.toString();
      String myString = attrDef.toString() + ", " + syntaxDef.toString() + ", ";
      return myString + superString;
   }

   private void checkState()
   {
      if (lazyAlreadyReturned)
         throw new IllegalStateException();
      
      if (!avStripped)
      {
         while (attributeValue.hasMoreElements())
            super.add(attributeValue.nextElement());
         avStripped = true;
      }
   }
}

class FSAttributeValueEnumerator implements Enumeration
{
   private StaticAttributeValue attributeValue;

   FSAttributeValueEnumerator(StaticAttributeValue attributeValue)
   {
      this.attributeValue = attributeValue;
   }

   public boolean hasMoreElements()
   {
      return attributeValue.hasMoreElements();
   }

   public Object nextElement()
   {
      return attributeValue.nextElement();
   }
}   
