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

  $Archive: /njcl_v2/src/com/novell/service/nw/NetWareInitialContext.java $
  $Revision: 8 $
  $Modtime: 9/29/99 12:45p $
 
  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.nw;


import java.util.*;

import javax.naming.*;

import  com.sun.jndi.toolkit.ctx.*;


/**
* Provides the root of the NetWare name space. NetWareInitialContext has
* two bindings: NetWareStrings.TREES and NetWareStrings.SERVERS
*
* @see NetWareServersContext
* @see NetWareTreesContext
*/
public class NetWareInitialContext extends AtomicContext
{

  /**
   * @internal
   */
   protected Hashtable environment;
   private static NetWareNameParser parser;
   private Vector bindings;

  /**
   * @internal
   *
   * Hashtable is already cloned in factory. we can use it.
   * @param h                    Parents properties
   */
   protected NetWareInitialContext(
         Hashtable h)
   {
      environment = h;
      if(null == parser)
         parser = new NetWareNameParser();
   }

  /**
   * @internal
   *
   * Constructor used to setup bindings. bindings not used in subclasses
   * calls NetWareInitialContext(Hashtable)
   * @param p                    Parents properties
   * @param setupBindings        Extra parameter to flag this constructor
   */
   protected NetWareInitialContext(
         Hashtable h,
         boolean setupBindings)
   {
      this(h);
      bindings = new Vector();
      bindings.addElement(NetWareStrings.TREES);
      bindings.addElement(NetWareStrings.SERVERS);
   }

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

   /** @internal
    *
    */
   public String getNameInNamespace ()
      throws NamingException
   {
      return (NetWareStrings.ROOT);
   }

   /**
   * @internal
   *
   * Place up to 2 components in the head, rest of name in the tail
   * @param name                 name to parse
   * @param cont                 continuation object
   */
   protected HeadTail p_parseComponent(
         Name name,
         Continuation cont)
      throws NamingException
   {
	   if(name.size() < 3)
	      return new HeadTail(name, null);
	   else
	      return new HeadTail(name.getPrefix(2), name.getSuffix(2));
	}

   /**
   * @internal
   *
   * place first component in the head, rest in the tail
   * @param name                 name to parse
   * @param cont                 continuation object
   */
   protected StringHeadTail c_parseComponent(
         String name,
	      Continuation cont)
   	throws NamingException
	{
      try
      {
         Name n = parser.parse(name);
         if(n.isEmpty() || n.size() == 1)
         {
            return new StringHeadTail(name, null);
         }
         else
         {
            Name head = n.getPrefix(1);
            Name tail = n.getSuffix(1);
            return new StringHeadTail(head.toString(), tail.toString());
         }
      }
      catch (NamingException e)
      {
         throw cont.fillInException(e);
      }
	}

  /**
   * @internal
   */
   protected Object a_lookup(
         String name,
         Continuation cont)
      throws NamingException
   {
      if(isEmpty(name))
      {
         cont.setSuccess();
         return this;
      }

      try
      {
         Object obj = 
            new NetWareObjectFactory().getObjectInstance(
                  name, null, null, environment);
         if(obj == null)
            throw new NameNotFoundException();
         cont.setSuccess();
         return obj;
      }
      catch(Exception e)
      {
         cont.setError(this, name);
         NameNotFoundException ex = new NameNotFoundException();
         ex.setRootCause(e);
         throw cont.fillInException(ex);
      }
   }

  /**
   * @internal
   */
   protected Object a_lookupLink(
         String name,
         Continuation cont)
      throws NamingException
   {
      return a_lookup(name, cont);
   }

  /**
   * @internal
   */
   protected NamingEnumeration a_list(
         Continuation cont)
      throws NamingException
   {
      cont.setSuccess();
      return new NetWareInitialContextNameClassEnumerator(bindings);
   }

  /**
   * @internal
   */
   protected NamingEnumeration a_listBindings(
         Continuation cont)
      throws NamingException
   {
      cont.setSuccess();
      return new NetWareInitialContextBindingEnumerator(
         bindings,
         getEnvironment());
   }

  /**
   * @internal
   */
   protected void a_bind(
         String name,
         Object obj,
         Continuation cont)
      throws NamingException
   {
      notSupported(name, cont);
   }

  /**
   * @internal
   */
   protected void a_rebind(
         String name,
         Object obj,
         Continuation cont)
      throws NamingException
   {
      notSupported(name, cont);
   }

  /**
   * @internal
   */
   protected void a_unbind(
         String name,
         Continuation cont)
      throws NamingException
   {
      notSupported(name, cont);
   }

  /**
   * @internal
   */
   protected void a_rename(
         String oldname,
         Name newname,
         Continuation cont)
      throws NamingException
   {
      notSupported(oldname, cont);
   }

  /**
   * @internal
   */
   protected void a_destroySubcontext(
         String name,
         Continuation cont)
      throws NamingException
   {
      notSupported(name, cont);
   }

  /**
   * @internal
   */
   protected Context a_createSubcontext(
         String name,
         Continuation cont)
      throws NamingException
   {
      return (Context)notSupported(name, cont);
   }

  /**
   * @internal
   */
   protected NameParser a_getNameParser(
         Continuation cont)
      throws NamingException
   {
      return parser;
   }

  /**
   * @internal
   */
	public Object addToEnvironment(
   	   String name,
   	   Object value)
   	throws NamingException
	{
      return environment.put(name, value);
	}

  /**
   * @internal
   */
	public Object removeFromEnvironment(
   	   String name)
   	throws NamingException
	{
      return environment.remove(name);
	}

  /**
   * @internal
   */
	public Hashtable getEnvironment() throws NamingException
	{
	   return (Hashtable)environment.clone();
	}

  /**
   * @internal
   */
   public void close() throws NamingException
   {
      //no action necessary
   }

   /*
   *  Common code for setting up and throwing OperationNotSupported Exception.
   */
   private Object notSupported(
         String n,
         Continuation c)
      throws NamingException
   {
      c.setError(this, n);
      throw c.fillInException(new OperationNotSupportedException());
   }
}

/**
 * @internal
 *
********************************************************************
*  Binding Enumeration of the NetWareInitialContext Bindings.
*/
class NetWareInitialContextBindingEnumerator implements NamingEnumeration
{
   private Enumeration names;
   private Hashtable env;

   /**
   * Sets up enumeration of binding names
   */
   public NetWareInitialContextBindingEnumerator(
      Vector binds,
      Hashtable props)
   {
      names = binds.elements();
      env = props;
   }

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

   public boolean hasMore()
   {
      return hasMoreElements();
   }

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

   public Object next()
      throws NamingException
   {
      try
      {
         String name = (String)names.nextElement();
         Object obj = new NetWareObjectFactory().getObjectInstance(
               name, null, null, env);
         if(obj==null)
            throw new NamingException();
         return new Binding(name, obj);
      }
      catch(Exception e)
      {
         NamingException ex = new NamingException();
         ex.setRootCause(e);
         throw ex;
      }
   }

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


/**
 * @internal
 *
********************************************************************
*  NameClassPair Enumeration of the NetWareInitialContext Bindings.
*/
class NetWareInitialContextNameClassEnumerator implements NamingEnumeration
{
   private Enumeration names;

   /**
   * Sets up enumeration of binding names
   */
   public NetWareInitialContextNameClassEnumerator(
      Vector binds)
   {
      names = binds.elements();
   }

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

   public boolean hasMore()
   {
      return hasMoreElements();
   }

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

   public Object next()
      throws NamingException
   {
      try
      {
         String name = (String)names.nextElement();
         Object obj = new NetWareObjectFactory().getObjectInstance(
               name, null, null, new Hashtable());
         if(obj==null)
            throw new NamingException();
         return new NameClassPair(  //make this more efficient later
            name,
            obj.getClass().getName());
      }
      catch(Exception e)
      {
         NamingException ex = new NamingException();
         ex.setRootCause(e);
         throw ex;
      }
   }

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