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

  $Archive: /njcl_v2rmi/src/com/novell/service/file/nw/calls/DirectorySpaceInfoImpl.java $
  $Revision: 14 $
  $Modtime: 12/08/00 10:17a $
 
  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.calls;

import java.rmi.RemoteException;

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

import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.AttributeModificationException;
import javax.naming.directory.InvalidSearchFilterException;

import com.novell.service.jncp.NSIException;

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

import com.novell.service.session.SessionException;
import com.novell.service.session.xplat.CallsService;

import com.novell.service.file.nw.DirectorySpaceInformation;
import com.novell.service.file.nw.NameSpace;

import com.novell.service.file.nw.naming.FSAttribute;
import com.novell.service.file.nw.naming.SchemaAttrDef;
import com.novell.service.file.nw.naming.SchemaSyntaxDef;
import com.novell.service.file.nw.naming.FSEnvironment;

import com.novell.service.rfc1960.SearchStringComponent;

/**@internal
 * NWCalls implementation of DirectorySpaceInformation
 *
 * <p>Supplies the NWCalls native methods needed to obtain and set the
 * DirectorySpaceInformation state data members.
 * </p>
 *
 * @see com.novell.service.file.
 */

public class DirectorySpaceInfoImpl
   extends DirectorySpaceInformation
   implements StaticAttributeValue
{
   private FSEnvironment environment;
   private String serverName;
   private String fullNodeName;
   private String nameSpace;
   private String volumeName;
   private CallsService callsService;
   private boolean hasMoreElements = true;

/* **************************************************************************
   Public Constructor
****************************************************************************/

   /**
    * Constructs a DirectorySpaceInfoImpl object.
    *
    * @param environment         The JNDI DSContext's environment associated
    *                            with this attribute and this static
    *                            attribute value.
    * @exception NSIException    If an error occurs.
    */
   public DirectorySpaceInfoImpl(FSEnvironment environment)
      throws NSIException
   {
      this.environment = environment;
      fullNodeName = environment.getFullNodeName();
      nameSpace = environment.getNameSpace();
      volumeName = environment.getVolumeName();

      try
      {
         this.callsService = environment.getCallsService();
      } catch (NamingException e)
      {
         throw new NSIException("" + e, e);
      }
   }

/* **************************************************************************
   Enumeration implementation
****************************************************************************/

   /**
    * Tests whether the attribute value has already been returned.
    *
    * <p>Because this directory space information matches directory space
    * one-to-one, there is only ever one value returned from this
    * classes enumeration.
    * </p>
    *
    * @return                    true if nextElement() has never been called,
    *                            otherwise returns false.
    *
    * @see #nextElement
    * @see #buildAttribute
    */
   public boolean hasMoreElements()
   {
      return hasMoreElements;
   }

   /**
    * Retrieves the attribute value, if it has not yet been retrieved.
    *
    * <p>The StaticAttributeValue interface also declares this method for
    * lazy evaluation of jndi attribute values.  The buildAttribute method
    * will return a FSAttribute which will have a reference to this object.
    * The FSAttribute.getValues method will return an enumerator which will
    * forward the hasMoreElements and nextElement calls back into this
    * object.  One, and only one object will ever be returned from this method.
    * </p>
    *
    * @return                    DirectorySpaceInformation object.
    * @exception  NoSuchElementException When the directory space information
    *                            object has already been retrieved.
    * @exception  NSIException   refresh can throw a NSIException.
    *
    * @see #hasMoreElements
    * @see #buildAttribute
    * @see com.novell.service.file.nw.DirectorySpaceInformation
    */
   public Object nextElement()
   {
      if (!hasMoreElements)
         throw new NoSuchElementException();

      hasMoreElements = false;   // only give them one

      refresh();
      return this;
   }

/* **************************************************************************
   StaticAttributeValue implementation
****************************************************************************/

   /**
    * Builds and returns an Attribute object
    *
    * <p>Builds and returns an Attribute Object.  A new instantiation of this
    * class will be obtained, and it's refresh method called, causing the
    * data members to be set.
    * </p>
    *
    * @return                    An Attribute object that reflects the state
    *                            of newly created objects member data.
    *
    * @see com.novell.service.file.nw.naming.DirEntryDirContext#c_getAttributes
    */

   public Attribute buildAttribute()
      throws NamingException
   {
      DirectorySpaceInfoImpl dsi = null;
      try
      {
         dsi = new DirectorySpaceInfoImpl(environment);
      } catch (NSIException nsie)
      {
         NamingException ne = new NamingException(nsie.getMessage());
         ne.setRootCause(nsie);
         throw ne;
      }

      return new 
         FSAttribute(
            ATTRIBUTE_ID,
            dsi,
            new SchemaAttrDef(SchemaAttrDef.DSI_ATTRDEF, environment),
            new SchemaSyntaxDef(SchemaAttrDef.DSI_ATTRDEF, environment));
   }

   /**
    * Adds an Attribute to the Attribute ID's values.
    *
    * <p>There are some dynamic aspects of the static attribute values.
    * examples of these are in the file system name space; Extended
    * Attributes, Trustee lists, and volume restrictions.  All three of these
    * are dynamic lists of information that will be found under a single
    * attribute ID.  The addAttribute will be used by attribute values that
    * have this dynamic aspect to them.  All others will throw an
    * AttributeModificationException.
    * </p>
    *
    * @param                   The attribute to be added.
    *
    * @exception AttributeModificationException
    *
    * @see com.novell.service.file.nw.naming.DirEntryDirContext#c_modifyAttributes
    */

   public void addAttribute(Attribute attr)
      throws NamingException
   {
      throw new AttributeModificationException();
   }


   /**
    * Deletes an Attribute from the Attribute ID's values.
    *
    * <p>There are some dynamic aspects of the static attribute values.
    * examples of these are in the file system name space; Extended
    * Attributes, Trustee lists, and volume restrictions.  All three of these
    * are dynamic lists of information that will be found under a single
    * attribute ID.  The delAttribute will be used by attribute values that
    * have this dynamic aspect to them.  All others will throw an
    * AttributeModificationException.
    * </p>
    *
    * @param                   The attribute to be removed.
    *
    * @exception AttributeModificationException
    *
    * @see com.novell.service.file.nw.naming.DirEntryDirContext#c_modifyAttributes
    */

   public void deleteAttribute(Attribute attr)
      throws NamingException
   {
      throw new AttributeModificationException();
   }

   /**
    * Sets the current state to the Attribute values.
    *
    * <p>The DirectorySpaceInformation's maxAvailable data member will be
    * used as the the limit.
    * </p>
    *
    * @return                    Attribute reflecting current state of the
    *                            value.
    * @exception NamingException
    *
    * @see com.novell.service.file.nw.naming.DirEntryDirContext#c_modifyAttributes
    */

   public void modifyAttribute(Attribute attr)
      throws NamingException
   {
      Enumeration enum = attr.getAll();
      while (enum.hasMoreElements())
      {
         DirectorySpaceInformation info = (DirectorySpaceInformation)
                                             enum.nextElement();

         synchronized(info)
         {
            try
            {
               callsService.setDirSpaceLimit(
                              0,
                              fullNodeName,
                              NameSpace.nameToNumber(nameSpace),
                              info.getMaxAvailable());
            }
            catch (Exception e)
            {
               NamingException ne = new AttributeModificationException(
                                             e.getMessage());
               ne.setRootCause(e);
               throw ne;
            }
         }
      }
   }

   /**
    * Get the Attribute Name.
    *
    * <p>Returns the Attribute name (ATTRIBUTE_ID) of the AttributeInformation
    * implementation object.
    * </p>
    *
    * @return                    The Attribute name (ATTRIBUTE_ID).
    */

   public String getID()
   {
      return(ATTRIBUTE_ID);
   }

   /**
    * Does the specified compare operation and returns the result
    *
    * <p>This method will compare the value object against the attributes
    * current value, in the manner specified in the SearchStringComponent,
    * and return the result of this compare.
    * </p>
    *
    * @param ssc                 The SearchStringComponent to use for the
    *                            compare.
    *
    * @return                    true if the operation compares true, false
    *                            otherwise.
    * @exception InvalidSearchFilterException
    */

   public boolean compare(SearchStringComponent ssc)
      throws NamingException
   {
      try
      {
         return equals(ssc);
      } catch (Exception e)
      {
         InvalidSearchFilterException isfe =
            new InvalidSearchFilterException();

         isfe.setRootCause(e);
         throw isfe;
      }
   }

   /**
    * Does the specified compare operation and returns the result
    *
    * <p>This method will compare the value object against the attributes
    * current value, in the manner specified in the SearchStringComponent,
    * and return the result of this compare.
    * </p>
    *
    * @param ssc                 The SearchStringComponent to use for the
    *                            compare.
    *
    * @return                    true if the operation compares true, false
    *                            otherwise.
    */

   public boolean equals(SearchStringComponent ssc)
   {
      if (ssc == null)
         return false;

      int type = ssc.getOperationType();

      if (type == ssc.PRESENT)
         return true;

      if (type != ssc.EQUALS && type != ssc.SUBSTRING)
         return false;

      DirectorySpaceInformation dsi = null;
      String name = null;
      boolean nameOnly = true;
      if (ssc.operandReplacement())
      {
         dsi = (DirectorySpaceInformation) ssc.getReplacementObject();
         if (dsi == null)
            throw new IllegalArgumentException(ssc.getOperation());
         synchronized(dsi)
         {
            name = dsi.getVolName();
         }
         nameOnly = false;
      }else
         name = ssc.getOperand();

      refresh();
      if (type == ssc.EQUALS)
      {
         if (nameOnly)
            return name.equals(getVolName());

         try
         {
            synchronized(dsi)
            {
               return dsi.equals(this);
            }
         }catch(Exception e)
         {
            return false;
         }
      }

      if (type == ssc.SUBSTRING)
      {
         return SearchStringComponent.compareSubString(name, getVolName(), true);
      }
      return false;
   }

   /**
    * Returns the static interface object.
    *
    * <p>This method returns the appropriate object for the static interface
    * to this attribute value.
    * </p>
    *
    * @return                    DirectorySpaceInformation.
    *
    */
   public Object getStaticInterface()
   {
      DirectorySpaceInfoImpl dsi =
         new DirectorySpaceInfoImpl(environment);

      dsi.refresh();
      return dsi;
   }

   /**
    * Refresh the Attributes data.
    *
    * <p>Causes the Attribute data to be retrieved from the Netware server.
    * </p>
    *
    *
    */

   public void refresh()
      throws NSIException
   {
      int[] volNum = new int[1];
      int[] maxLimit = new int[1];
      int[] currentUse = new int[1];

      try
      {

         callsService.getVolumeNumber(volumeName, volNum);

         callsService.getDirSpaceInfo(
                        volNum[0],
                        fullNodeName,
                        NameSpace.nameToNumber(nameSpace),
                        this);

         callsService.getDirSpaceLimitList(
                        0,
                        fullNodeName,
                        NameSpace.nameToNumber(nameSpace),
                        maxLimit,
                        currentUse);

         setMaxAvailable(maxLimit[0]);
         setCurrentUse(currentUse[0]);
      }
      catch (Exception e)
      {
         throw new NSIException(e.getMessage(), 0, e);
      }
   }
}
