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

  $Archive: /njcl_v2/src/com/novell/service/file/nw/calls/VolumeInfoImpl.java $
  $Revision: 12 $
  $Modtime: 1/28/00 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.file.nw.calls;

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

import java.rmi.RemoteException;
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.jncpv2.net.NetService;

import com.novell.service.file.nw.VolumeInformation;
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 VolumeInformation
 *
 * <p>Supplies the NWCalls native methods needed to obtain and set the
 * VolumeInformation state data members.
 * </p>
 *
 * @see com.novell.service.file.nw.VolumeInformation
 */

public class VolumeInfoImpl
   extends VolumeInformation
   implements StaticAttributeValue, Enumeration
{
   private FSEnvironment environment;
   private String fullNodeName;
   private String nameSpace;
   private String volumeName;
   private CallsService callsService;
   private NetService netService;
   private boolean sessionIsNDS;
   private boolean hasMoreElements = true;

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

   /**
    * Main constructor
    *
    * <p>Constructs a VolumeInfoImpl object.
    * </p>
    *
    * @param environment         The JNDI DSContext's environment associated
    *                            with this attribute and this static
    *                            attribute value.
    *
    * @exception NSIException    If conn.getHandle() fails
    */

   public VolumeInfoImpl(FSEnvironment environment)
      throws NSIException
   {
      this.environment = environment;
      fullNodeName = environment.getFullNodeName();
      nameSpace = environment.getNameSpace();
      volumeName = environment.getVolumeName();

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

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

   /**
    * Enumerator hasMoreElements
    *
    * <p>The StaticAttributeValue interface 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 nextElement.
    * </p>
    *
    * @return                    true if nextElement has never been called,
    *                            otherwise returns false.
    *
    * @see com.novell.service.file.nw.naming.StaticAttributeValue
    * @see com.novell.service.file.nw.naming.FSAttribute
    * @see #nextElement
    * @see #buildAttribute
    */

   public boolean hasMoreElements()
   {
      return hasMoreElements;
   }

   /**
    * Enumerator nextElement
    *
    * <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                    VolumeInformation object
    *
    * @exception                 NoSuchElementException
    * @exception                 NSIException if refresh fails
    *
    * @see com.novell.service.file.nw.naming.StaticAttributeValue
    * @see com.novell.service.file.nw.naming.FSAttribute
    * @see #hasMoreElements
    * @see #buildAttribute
    * @see com.novell.service.file.VolumeInformation
    */

   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
   {
      VolumeInfoImpl vii = null;
      try
      {
         vii = new VolumeInfoImpl(environment);
      } catch (NSIException nsie)
      {
         NamingException ne = new NamingException(nsie.getMessage());
         ne.setRootCause(nsie);
         throw ne;
      }

      return new 
         FSAttribute(
            ATTRIBUTE_ID,
            vii,
            new SchemaAttrDef(SchemaAttrDef.VI_ATTRDEF, environment),
            new SchemaSyntaxDef(SchemaAttrDef.VI_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>If this object is multi-valued (compound Attribute), It is possible
    * for some of the values to be read-only.  Any read-only fields of the
    * attribute value being passed in must match the current state of this
    * object or an AttributeModificationException will be thrown.
    * </p>
    *
    * @return                    Attribute reflecting current state of the
    *                            value.
    *
    * @exception AttributeModificationException
    *
    * @see com.novell.service.file.nw.naming.DirEntryDirContext#c_modifyAttributes
    */

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

   /**
    * 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
    * @exception NSIException
    */

   public boolean compare(SearchStringComponent ssc)
      throws NamingException
   {
      try
      {
         return equals(ssc);
      } catch (IllegalArgumentException 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.
    *
    * @exception NSIException    if refresh fails
    * @exception IllegalArgumentException
    */

   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;

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

      refresh();
      if (type == ssc.EQUALS)
      {
         if (nameOnly)
            return name.equals(getVolName());
         try
         {
            synchronized(vi)
            {
               return vi.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                    VolumeInformation
    *
    */
   public Object getStaticInterface()
   {
      VolumeInfoImpl vii =
         new VolumeInfoImpl(environment);
      vii.refresh();
      return vii;
   }

   /**
    * 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];

      try
      {
         callsService.getVolumeNumber(volumeName, volNum);

         callsService.getVolumeInfoWithNumber(volNum[0], this);

         callsService.getExtendedVolumeInfo(volNum[0], this);

      }
      catch (SessionException e)
      {
         throw new NSIException(e.getMessage(), 0, e);
      }

      /*
         NWGetExtendedVolumeInfo sets the DirectoryServicesObjectID data
         member, convert it to a name and store in the direcotryServicesName
         data member
      */

      ObjectName on = null;
      try
      {
         on = ObjectNameImpl.
                  objectIdToObjectName(
                     directoryServicesObjectId, 
                     callsService,
                     netService,
                     sessionIsNDS);

         setDirectoryServicesName(on.getName());
      } catch (NSIException nsie)
      {
         // this may not be a nds volume, and might fail
         setDirectoryServicesName("");
      }

      DirectorySpaceInformation dsi = new DirectorySpaceInformation();
      try
      {
         callsService.getDirSpaceInfo(
                        volNum[0],
                        null,    // only get the volume information
                        0,       // same for all ns so just do 0
                        dsi);
      }
      catch (SessionException e)
      {
         throw new NSIException(e.getMessage(), 0, e);
      }

      setTotalBlocks(dsi.getTotalBlocks());
      setAvailableBlocks(dsi.getAvailableBlocks());
      setPurgeableBlocks(dsi.getPurgeableBlocks());
      setNotYetPurgeableBlocks(dsi.getNotYetPurgeableBlocks());
      setReserved(dsi.getReserved());
      setSectorsPerBlock(dsi.getSectorsPerBlock());
   }
}