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

  $Archive: /njcl_v2/src/com/novell/service/file/nw/naming/SchemaSyntaxDef.java $
  $Revision: 11 $
  $Modtime: 2/22/00 5:16p $
 
  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.

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

/*
   As you add attribute values (attribute IDs) do the following in this file:

   1. Go to SchemaClassDef and follow the list at the top of that file.

   2. Go to the SchemaSDNCEnumerator class (bottom of this file) and add the
      name of the new schema syntax def node into the name data member.  This
      name should be exactly the same as the name used in step 4 in the
      SchemaAttrDef.java file.

      The syntax definitions are on a one to one bases with the _ATTRDEFs
      defined in SchemaSyntaxDef.java (step 2).  The name data member array
      must be maintained in the same index order as the _ATTRDEFs.  If an
      _ATTRDEF does not have a syntax, put a "" in the appropriate index.

   3. Go to the SchemaSyntaxDef(int) constructor and add the _ATTRDEFs that
      you want.
*/

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

import java.util.Enumeration;
import java.util.NoSuchElementException;
import java.util.Hashtable;

import javax.naming.*;
import javax.naming.Binding;
import javax.naming.NamingEnumeration;
import javax.naming.Context;
import javax.naming.InvalidNameException;
import javax.naming.Name;
import javax.naming.NamingEnumeration;
import javax.naming.NameClassPair;
import javax.naming.NameNotFoundException;
import javax.naming.NameParser;
import javax.naming.NamingException;
import javax.naming.OperationNotSupportedException;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.AttributeModificationException;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;
import javax.naming.directory.SearchControls;

import com.novell.utility.naming.NamingEnumerator;

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

import com.novell.service.file.nw.DirectoryEntryInformation;
import com.novell.service.file.nw.DirectorySpaceInformation;
import com.novell.service.file.nw.ExtendedAttribute;
//import com.novell.service.file.nw.NSInformation;
import com.novell.service.file.nw.Trustee;
import com.novell.service.file.nw.VolumeInformation;
import com.novell.service.file.nw.VolumeRestriction;
import com.novell.service.file.nw.VolumeUtilization;
import com.novell.service.file.nw.EffectiveRights;

import com.novell.service.file.nw.calls.DirectoryEntryInfoImpl;
import com.novell.service.file.nw.calls.DirectorySpaceInfoImpl;
import com.novell.service.file.nw.calls.EAEnumeratorImpl;
//import com.novell.service.file.nw.calls.NSInfoEnumeratorImpl;
import com.novell.service.file.nw.calls.TrusteeEnumeratorImpl;
import com.novell.service.file.nw.calls.VolumeInfoImpl;
import com.novell.service.file.nw.calls.VolumeRestrictionEnumeratorImpl;
import com.novell.service.file.nw.calls.VolumeUtilizationImpl;
import com.novell.service.file.nw.calls.EffectiveRightsImpl;

/**@internal
 * This class is the attribute syntax definition schema context for the
 * file system provider.  This means that the attributes of this context
 * describe or define a particular file system attribute syntax.
 *
 * <p>This is the schema DirContext that is returned from calling
 * getAttributeSyntaxDefinition() on all Attribute instances returned the
 * from the file system DSContexts.
 *
 * @see javax.naming.directory.Attribute#getAttributeSyntaxDefinition
 * @see FSAttribute
 */
public class SchemaSyntaxDef implements DirContext
{
   private String[] nodesAttrIds = null;
   private boolean staticSchemaTree = true;
   private int contextType = -1;
   private String syntaxName = null;
   private String[] customId = null;
   private String[] customValue = null;

   private String distinguishedName;

   private FSEnvironment environment;

   public SchemaSyntaxDef(FSEnvironment environment)
   {
      distinguishedName = FSSchema.SYNTAX_DEFINITIONS;
      this.environment = environment;
   }

   /*
      This is the constructor that should be used by
      Attribute.getAttributeSyntaxDefinition.  The caller should use a valid
      _ATTRDEF value from SchemaAttrDef.java for the type.
   */

   public SchemaSyntaxDef(int type, FSEnvironment environment)
   {
      this(environment);

      staticSchemaTree = false;
      contextType = type;
      switch (contextType)
      {
         /*
            Maximum possible compares available are set up as follows:

            customId[0] = FSSchema.COMPARE;
            customValue[0] = new String(
               "(" +
               SearchStringComponent.EQUALS_STRING + "," +
               SearchStringComponent.APPROXIMATE_STRING + "," +
               SearchStringComponent.GREATER_OR_EQUAL_STRING + "," +
               SearchStringComponent.LESS_OR_EQUAL_STRING + "," +
               SearchStringComponent.PRESENT_STRING + "," +
               SearchStringComponent.SUBSTRING_STRING +
               ")");

               These strings should be setup in the actual attribute
               values in a static final String COMPARE_SYNTAX_STRING
         */

         case SchemaAttrDef.DEI_ATTRDEF:
            syntaxName = DirectoryEntryInfoImpl.SCHEMA_BINDING_NAME;
            customId = new String[1];
            customValue = new String[1];
            customId[0] = FSSchema.COMPARE;
            customValue[0] = DirectoryEntryInformation.COMPARE_SYNTAX_STRING;
            break;
         case SchemaAttrDef.EA_ATTRDEF:
            syntaxName = EAEnumeratorImpl.SCHEMA_BINDING_NAME;
            customId = new String[1];
            customValue = new String[1];
            customId[0] = FSSchema.COMPARE;
            customValue[0] = ExtendedAttribute.COMPARE_SYNTAX_STRING;
            break;

         case SchemaAttrDef.TL_ATTRDEF:
            syntaxName = TrusteeEnumeratorImpl.SCHEMA_BINDING_NAME;
            customId = new String[1];
            customValue = new String[1];
            customId[0] = FSSchema.COMPARE;
            customValue[0] = Trustee.COMPARE_SYNTAX_STRING;
            break;

         case SchemaAttrDef.DSI_ATTRDEF:
            syntaxName = DirectorySpaceInfoImpl.SCHEMA_BINDING_NAME;
            customId = new String[1];
            customValue = new String[1];
            customId[0] = FSSchema.COMPARE;
            customValue[0] = DirectorySpaceInformation.COMPARE_SYNTAX_STRING;
            break;

         case SchemaAttrDef.VI_ATTRDEF:
            syntaxName = VolumeInfoImpl.SCHEMA_BINDING_NAME;
            customId = new String[1];
            customValue = new String[1];
            customId[0] = FSSchema.COMPARE;
            customValue[0] = VolumeInformation.COMPARE_SYNTAX_STRING;
            break;

         case SchemaAttrDef.VU_ATTRDEF:
            syntaxName = VolumeUtilizationImpl.SCHEMA_BINDING_NAME;
            customId = new String[1];
            customValue = new String[1];
            customId[0] = FSSchema.COMPARE;
            customValue[0] = VolumeUtilization.COMPARE_SYNTAX_STRING;
            break;

         case SchemaAttrDef.VR_ATTRDEF:
            syntaxName = VolumeRestrictionEnumeratorImpl.SCHEMA_BINDING_NAME;
            customId = new String[1];
            customValue = new String[1];
            customId[0] = FSSchema.COMPARE;
            customValue[0] = VolumeRestriction.COMPARE_SYNTAX_STRING;
            break;

         case SchemaAttrDef.EFR_ATTRDEF:
            syntaxName = EffectiveRightsImpl.SCHEMA_BINDING_NAME;
            customId = new String[1];
            customValue = new String[1];
            customId[0] = FSSchema.COMPARE;
            customValue[0] = EffectiveRights.COMPARE_SYNTAX_STRING;
            break;
/*
         case SchemaAttrDef.NSI_ATTRDEF:
            syntaxName = NSInfoEnumeratorImpl.SCHEMA_BINDING_NAME;
            customId = new String[1];
            customValue = new String[1];
            customId[0] = FSSchema.COMPARE;
            customValue[0] = NSInformation.COMPARE_SYNTAX_STRING;
            break;
*/
      }
      distinguishedName = FSSchema.SYNTAX_DEFINITIONS + "/" + syntaxName;
   }

   public int getContextType()
   {
      return contextType;
   }


   // ******************** Context Interface ********************

   /** @internal
    *
    */
   public String getNameInNamespace ()
      throws NamingException
   {
      return (distinguishedName);
   }

   public NamingEnumeration list(String name)
      throws NamingException
   {
      if (name == null || name.length() == 0)
      {
         NamingEnumeration rvalue = null;
         if (staticSchemaTree)
            rvalue = new SchemaSDNCEnumerator();
         else
            rvalue = new NamingEnumerator();
         return rvalue;
      }
      else
         return (NamingEnumeration)
            objectFromName(name, Schema.NCP_OBJECT);
   }

   public NamingEnumeration list(Name name)
      throws NamingException
   {
      return list(name.toString());
   }

   public NamingEnumeration listBindings(String name)
      throws NamingException
   {
      if (name == null || name.length() == 0)
      {
         NamingEnumeration rvalue = null;
         if (staticSchemaTree)
            rvalue = new SchemaSDBindingEnumerator(environment);
         else
            rvalue = new NamingEnumerator();
         return rvalue;
      }
      else
         return (NamingEnumeration)
            objectFromName(name, Schema.BINDING_OBJECT);
   }

   public NamingEnumeration listBindings(Name name)
      throws NamingException
   {
      return listBindings(name.toString());
   }

   public Object lookup(String name) 
      throws NamingException
   {
      if (name == null || name.length() == 0)
         return this;

      return objectFromName(name, Schema.LOOKUP_OBJECT);
   }

   public Object lookup(Name name) 
      throws NamingException
   {
      return lookup(name.toString());
   }

   public NameParser getNameParser(String name) 
      throws NamingException
   {
      if (name == null || name.length() == 0)
         return new FileSystemNameParser(
                        environment.getServerName(), 
                        true);

      return (NameParser)
         objectFromName(name, Schema.NP_OBJECT);
   }

   public NameParser getNameParser(Name name) 
      throws NamingException
   {
      return getNameParser(name.toString());
   }

   public String composeName (
         String name,
         String prefix)
      throws NamingException
   {
      Name fullName;

      fullName = composeName(
                                 new CompositeName(name),
                                 new CompositeName(prefix));
      return fullName.toString();
   }

   public Name composeName (
         Name name,
         Name prefix)
      throws NamingException
   {
      Name res = (Name)prefix.clone();

      if (name == null)
      {
         return res;
      }
      res.addAll(name);

      return res;
   }

   public Hashtable getEnvironment()
      throws NamingException
   {
      return environment.getEnvironment(true);
   }

   public Object addToEnvironment(String propName, Object propVal)
      throws NamingException
   {
      return (environment.addToEnvironment(propName, propVal));
   }

   public Object removeFromEnvironment(String propName)
      throws NamingException
   {
      return (environment.removeFromEnvironment(propName));
   }

   /* methods that don't just throw an exception (but do nothing) */

   /* methods that just throw an exception */

   public void bind(String name, Object obj) 
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public void bind(Name name, Object obj) 
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public void rebind(String name, Object obj) 
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public void rebind(Name name, Object obj) 
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public void unbind(String name) 
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public void unbind(Name name) 
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public void rename(String oldName, String newName)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public void rename(Name oldName, Name newName) 
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public void destroySubcontext(String name) 
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public void destroySubcontext(Name name) 
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public Context createSubcontext(String name) 
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public Context createSubcontext(Name name) 
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public Object lookupLink(String name) 
      throws NamingException
   {
      return (lookup (name));
   }

   public Object lookupLink(Name name) 
      throws NamingException
   {
      return (lookup (name));
   }

   public void close ()
      throws NamingException
   {
      // ... no close necessary
   }

/* **************************************************************************
*  DSContext implementation
****************************************************************************/

   /* methods that actually do something */

   public Attributes getAttributes(String name)
      throws NamingException
   {
      return getAttributes(name, null);
   }

   public Attributes getAttributes(Name name)
      throws NamingException
   {
      return getAttributes(name.toString(), null);
   }

   public Attributes getAttributes(String name, String[] attrIds)
      throws NamingException
   {
      if (name == null || name.length() == 0)
      {
         Attributes attrSet = new NAttributes(true);

         if (staticSchemaTree)
            return attrSet;         // there are no attributes at this level

         if (attrIds == null)
         {
            // they want the whole attribute set
            if (customId != null)
            {
               for (int i=0; i < customId.length; i++)
               {
                  BasicAttribute attr = new BasicAttribute(customId[i]);
                  attr.add(new String(customValue[i]));
                  attrSet.put(attr);
               }
            }
         }else
         {
            // find which ones they want
            for (int i=0; i < attrIds.length; i++)
            {
               for (int j=0; j < customId.length; j++)
               {
                  if (attrIds[i].equalsIgnoreCase(customId[j]))
                  {
                     BasicAttribute attr = new BasicAttribute(customId[j]);
                     attr.add(new String(customValue[j]));
                     attrSet.put(attr);
                  }
               }
            }
         }
         return attrSet;
      }
      else
         return (Attributes)objectFromName(name, Schema.AS_OBJECT);
   }

   public Attributes getAttributes(Name name, String[] attrIds)
      throws NamingException
   {
      return getAttributes(name.toString(), attrIds);
   }

   /* methods that don't just throw an exception (but do nothing) */

   /* methods that just throw an exception */

   public void modifyAttributes(String name, int mod_op, Attributes attrs)
      throws NamingException
   {
      throw new AttributeModificationException();
   }

   public void modifyAttributes(Name name, int mod_op, Attributes attrs)
      throws NamingException
   {
      throw new AttributeModificationException();
   }

   public void modifyAttributes(String name, ModificationItem[] mods)
      throws NamingException
   {
      throw new AttributeModificationException();
   }

   public void modifyAttributes(Name name, ModificationItem[] mods)
      throws NamingException
   {
      throw new AttributeModificationException();
   }

   public void bind(String name, Object obj, Attributes attrs)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public void bind(Name name, Object obj, Attributes attrs)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public void rebind(String name, Object obj, Attributes attrs)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public void rebind(Name name, Object obj, Attributes attrs)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public DirContext createSubcontext(String name,
                     Attributes attrs)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public DirContext createSubcontext(Name name,
                     Attributes attrs)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public DirContext getSchema(String name)
       throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public DirContext getSchema(Name name)
       throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public DirContext getSchemaClassDefinition(String name)
       throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public DirContext getSchemaClassDefinition(Name name)
       throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   /* *************** searches *************** */

   public NamingEnumeration search(
      String name,
      Attributes matchingAttributes)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public NamingEnumeration search(
      Name name,
      Attributes matchingAttributes)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public NamingEnumeration search(
      String name,
      Attributes matchingAttributes,
      String[] attributesToReturn)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public NamingEnumeration search(
      Name name,
      Attributes matchingAttributes,
      String[] attributesToReturn)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public NamingEnumeration search(
      String name,
      String filter,
      SearchControls cons)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public NamingEnumeration search(
      Name name,
      String filter,
      SearchControls cons)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public NamingEnumeration search(
      String name,
      String filterExpr,
      Object [] filterArgs,
      SearchControls cons)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public NamingEnumeration search(
      Name name,
      String filterExpr,
      Object [] filterArgs,
      SearchControls cons)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

/* **************************************************************************
*  Helper methods
****************************************************************************/

   public static int typeFromName(String attrid)
   {
      for (int i = 0; i < SchemaSDNCEnumerator.names.length; i++)
      {
         if (SchemaSDNCEnumerator.names[i].equalsIgnoreCase(attrid))
            return i;
      }
      return -1;  // not a name that i know about
   }

   public static Object getEnumeration(int type, FSEnvironment environment)
      throws NamingException
   {
      if (type == Schema.NCP_OBJECT)
         return new SchemaSDNCEnumerator();
      if (type == Schema.BINDING_OBJECT)
         return new SchemaSDBindingEnumerator(environment);
      throw new InvalidNameException();
   }

   private Object objectFromName(String name, int returnType)
      throws NamingException
   {
      int type = typeFromName(name);
      if (type == -1)                        // no attrid of this name
         throw new NameNotFoundException();

      switch (returnType)
      {
         case Schema.NCP_OBJECT:     // name class pair enumeration
            return new NamingEnumerator();
         case Schema.BINDING_OBJECT: // binding enumeration
            return new NamingEnumerator();
         case Schema.LOOKUP_OBJECT:
         case Schema.AS_OBJECT:
            DirContext ctx = new SchemaSyntaxDef(type, environment);

            if (returnType == Schema.LOOKUP_OBJECT)
               return ctx;
            return ctx.getAttributes("");
         case Schema.NP_OBJECT:     // nameparser
            return new FileSystemNameParser(
                           environment.getServerName(), 
                           true);
         default:
            throw new InvalidNameException();
      }
   }
}

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

class SchemaSDNCEnumerator implements NamingEnumeration
{
   private final String classDef =
         "com.novell.service.file.nw.naming.SchemaSyntaxDef";

   public final static String[] names =
      {
         DirectoryEntryInfoImpl.SCHEMA_BINDING_NAME,
         EAEnumeratorImpl.SCHEMA_BINDING_NAME,
         TrusteeEnumeratorImpl.SCHEMA_BINDING_NAME,
         DirectorySpaceInfoImpl.SCHEMA_BINDING_NAME,
         VolumeInfoImpl.SCHEMA_BINDING_NAME,
         VolumeUtilizationImpl.SCHEMA_BINDING_NAME,
         VolumeRestrictionEnumeratorImpl.SCHEMA_BINDING_NAME,
         EffectiveRightsImpl.SCHEMA_BINDING_NAME,
//         NSInfoEnumeratorImpl.SCHEMA_BINDING_NAME,
      };

   private int index = 0;
   private boolean moreElements = true;
   private boolean lastHit = false;

   public SchemaSDNCEnumerator()
   {
      setNextIndex();
   }

   public boolean hasMoreElements()
   {
      return moreElements;
   }

   public Object nextElement()
   {
      try
      {
         return next();
      } catch (NamingException ne)
      {
         throw new RuntimeException(ne.getMessage());
      }
   }

   public boolean hasMore()
      throws NamingException
   {
      return moreElements;
   }

   public Object next()
      throws NamingException
   {
      if (!moreElements)
         throw new NoSuchElementException();

      NameClassPair rvalue = new NameClassPair(names[index], classDef, true);

      setNextIndex();
      return rvalue;
   }

   private void setNextIndex()
   {
      if (lastHit)
      {
         index++;
         lastHit = false;
      }

      for (int i = index; i < names.length; i++)
      {
         if (names[i].length() > 0)
         {
            index = i;
            lastHit = true;
            return ;
         }
      }
      moreElements = false;
   }

   /**
    *
    */
   public void close ()
      throws NamingException
   {
   }

}


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

class SchemaSDBindingEnumerator implements NamingEnumeration
{
   private int index = 0;
   private boolean moreElements = true;
   private boolean lastHit = false;

   private FSEnvironment environment;

   public SchemaSDBindingEnumerator(FSEnvironment environment)
   {
      this.environment = environment;
      setNextIndex();
   }

   public boolean hasMoreElements()
   {
      return moreElements;
   }

   public boolean hasMore()
      throws NamingException
   {
      return moreElements;
   }

   public Object nextElement()
   {
      try
      {
         return next();
      } catch (NamingException ne)
      {
         throw new RuntimeException(ne.getMessage());
      }
   }

   public Object next()
      throws NamingException
   {
      if (moreElements)
         throw new NoSuchElementException();

      Binding rvalue = new Binding(
                              SchemaSDNCEnumerator.names[index],
                              new SchemaSyntaxDef(index, environment),
                              true);
      setNextIndex();
      return rvalue;
   }

   private void setNextIndex()
   {
      if (lastHit)
      {
         index++;
         lastHit = false;
      }

      for (int i = index; i < SchemaSDNCEnumerator.names.length; i++)
      {
         if (SchemaSDNCEnumerator.names[i].length() > 0)
         {
            index = i;
            lastHit = true;
            return ;
         }
      }
      moreElements = false;
   }

   /**
    *
    */
   public void close ()
      throws NamingException
   {
   }

}


