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

  $Archive: /njcl_v2rmi/src/com/novell/service/file/nw/calls/VolumeUtilizationImpl.java $
  $Revision: 15 $
  $Modtime: 1/05/01 2:43p $
 
  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.jncpv2r.net.NetService;

import com.novell.service.file.nw.VolumeUtilization;
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
 * Volume Utilization Implementation
 *
 * <p>This class is the NWCalls implementation of the VolumeUtilization.
 * Using the NWCalls interface, this class will supply the hasMoreElements
 * and next (and nextElement) methods, implementing an enumerator of
 * VolumeUtilization Attributes for a given node.
 * </p>
 * <p>This class also implements the StaticAttributeValue interface which is
 * an interface used by jndi DSContexts for obtaining, modifing and searching
 * for attribute values.
 * </p>
 * @see com.novell.service.file.nw.naming.StaticAttributeValue
 * @see com.novell.service.file.nw.naming.DirEntryDirContext
 */

public class VolumeUtilizationImpl
   extends VolumeUtilization
   implements StaticAttributeValue
{
   private FSEnvironment environment;
   private String fullNodeName;
   private String nameSpace;
   private String volumeName;
   private NetService netService;
   private CallsService callsService;
   private boolean sessionIsNDS;

   private boolean hasMoreElements = true;

   /**
    * Main constructor
    *
    * <p>Constructs a VolumeUtilizationImpl object.
    * </p>
    *
    * @param environment         The JNDI DSContext's environment associated
    *                            with this attribute and this static
    *                            attribute value.
    */

   public VolumeUtilizationImpl(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 implementations
****************************************************************************/

   /**
    * 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>This method is used to return the value obtained in the
    * hasMoreElements call.  This method must be called after the
    * hasMoreElements method is called.
    * </p>
    * <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.
    * </p>
    *
    * @return                    The NSInformation (as an Object) that
    *                            the last call to hasMoreElements obtained.
    *
    * @exception                 NoSuchElementException
    *
    * @see com.novell.service.file.nw.naming.StaticAttributeValue
    * @see com.novell.service.file.nw.naming.FSAttribute
    * @see #hasMoreElements
    * @see #next
    * @see #buildAttribute
    * @see com.novell.service.file.nw.NSInformation
    */

   public Object nextElement()
   {
      return next();
   }

   /**
    * Enumerator next (typed nextElement)
    *
    * <p>This method is used to return the value obtained in the
    * hasMoreElements call.  This method must be called after the
    * hasMoreElements method is called.
    * </p>
    *
    * @return                    The VolumeUtilization that the last call to
    *                            hasMoreElements obtained.
    *
    * @exception                 NoSuchElementException
    * @exception                 NSIException
    *
    * @see #hasMoreElements
    * @see com.novell.service.file.nw.VolumeUtilization
    */

   public VolumeUtilization next()
   {
      if (!hasMoreElements)
         throw new NoSuchElementException();

      hasMoreElements = false;   // only give them one

      return(this);
   }

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

   /**
    * Builds and returns a lazy evaluation Attribute object
    *
    * <p>This method returns a FSAttribute object which has a reference to
    * a VolumeUtilizationImpl. The FSAttribute extends
    * javax.naming.directory.Attribute and overrides the getValues method.
    * It's getValues method returns an enumerator that simply forwards the
    * hasMoreElements and nextElement calls back into the
    * VolumeUtilizationImpl reference that the FSAttribute contains.
    * </p>
    *
    * @return                    A FSAttribute object that provides for lazy
    *                            evaluation of all possible
    *                            VolumeUtilization associated with the volume
    *                            associated with.
    *
    * @see com.novell.service.file.nw.naming.FSAttribute
    * @see com.novell.service.file.nw.VolumeUtilization
    * @see com.novell.service.file.nw.naming.StaticAttributeValue
    * @see #hasMoreElements
    * @see #nextElement
    * @see com.novell.service.file.nw.naming.DirEntryDirContext#c_getAttributes
    */

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

      return new 
         FSAttribute(
            ATTRIBUTE_ID,
            vu,
            new SchemaAttrDef(SchemaAttrDef.VU_ATTRDEF, environment),
            new SchemaSyntaxDef(SchemaAttrDef.VU_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.StaticAttributeValue
    * @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, and allow for deletion of items.  All
    * others will throw an AttributeModificationException.
    * </p>
    *
    * @param                   The attribute to be removed.
    *
    * @exception AttributeModificationException
    *
    * @see com.novell.service.file.nw.naming.StaticAttributeValue
    * @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 a 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>
    *
    * @exception AttributeModificationException
    *
    * @see com.novell.service.file.nw.naming.StaticAttributeValue
    * @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 implementation
    * object.
    * </p>
    *
    * @return                    The Attribute name (ATTRIBUTE_ID).
    *
    * @see com.novell.service.file.nw.naming.StaticAttributeValue
    * @see com.novell.service.file.VolumeUtilizationEnumertor
    * @see com.novell.service.file.VolumeUtilization
    */

   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
    *
    * @see com.novell.service.file.nw.naming.StaticAttributeValue
    * @see com.novell.utility.naming.directory.SearchStringComponent
    */

   public boolean compare(SearchStringComponent ssc)
      throws NamingException
   {
      return false;
/*

VolumeUtilization can not hit the wire and obtain information until the user
has set the objectName, this is done with a lazy evaluation, but will not allow
for any search, or modify
      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 IllegalArgumentException
    * @exception NSIException
    *
    * @see com.novell.utility.naming.directory.SearchStringComponent
    */

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

      int type = ssc.getOperationType();

      if (type == ssc.PRESENT)
         return true;      // static attribute values are always present

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

      VolumeUtilization vuInfo = null;
      boolean nameOnly = true;
      if (ssc.operandReplacement())
      {
         vuInfo = (VolumeUtilization)ssc.getReplacementObject();
         nameOnly = false;
         if (vuInfo == null)
            throw new IllegalArgumentException(ssc.getOperation());
      }else
      {
         // just match the Name space name, ignore the data
         vuInfo = new VolumeUtilization(ssc.getOperand());
      }

      /*
         You need to iterate through all VolumeUtilizations and look for the
         right one
      */

      VolumeUtilizationImpl vu = null;
      vu = new VolumeUtilizationImpl(environment);

      while (vu.hasMoreElements())
      {
         VolumeUtilization value = vu.next();

         if (type == ssc.EQUALS)
         {
            if (nameOnly)
            {
               synchronized(vuInfo)
               {
                  if (value.getName().
                        equalsIgnoreCase(vuInfo.getName()))
                     return false;
               }
            }

            try
            {
               synchronized(vuInfo)
               {
                  if (value.equals(vuInfo))
                     return true;
               }
            } catch (Exception e)
            {
               return false;
            }
         }else
         {
            if (type == ssc.SUBSTRING)
            {
               synchronized(vuInfo)
               {
                  if (SearchStringComponent.compareSubString(
                                                vuInfo.getName(),
                                                value.getName(),
                                                true))
                        return false;
               }
            }else
               return false;
         }
      }
      return false;
   }

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

      return vu;
   }

/* **************************************************************************
   Overriden Super class methods
****************************************************************************/

   /**
    * Sets the name of the superclass, and obtains state.
    *
    * <p>This method overrides the setName method in VolumeUtilization.
    * When the user sets the object name that they what information on,
    * we can then calculate the objectId, and then know which objects
    * utilization they want.
    * </p>
    *
    * @param name                The name to set
    *
    * @exception NSIException if any nwcalls calls fail
    */

   public void setName(String name)
   {
      int objectId;

      // first see if the trustee name is in the name+type format
      ObjectName on = null;
      if (BinderyName.isNameType(name))
         on = new BinderyName(name, true);
      else
         on = new ObjectName(name);

      objectId = ObjectNameImpl.nameToObjectId(
                                    on, 
                                    callsService,
                                    netService,
                                    sessionIsNDS);

      int[] volNum = new int[1];

      try
      {
         callsService.getVolumeNumber(volumeName, volNum);
      }
      catch (SessionException e)
      {
         throw new NSIException(e.getMessage(), 0, e);
      }
      catch (RemoteException e)
      {
         throw new NSIException(e.getMessage(), 0, e);
      }

      synchronized(this)
      {
         try
         {
            callsService.getDiskUtilization(
                        objectId,
                        volNum[0],
                        this);
         }
         catch (Exception e)
         {
            throw new NSIException(e.getMessage(), 0, e);
         }
      }
      objectIdSet = true;
      super.setName(name);
   }
}
