/***************************************************************************
 %name: TextualStatic.java
 %version: 
 %date_modified: 
 %dependencies: StaticAttributeValueInterface.java Textual.java 
 
 Copyright (c) 1998 Novell, Inc. All Rights Reserved.

 THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
 USE AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO THE LICENSE AGREEMENT
 ACCOMPANYING THE SOFTWARE DEVELOPMENT KIT (SDK) THAT CONTAINS THIS WORK.
 PURSUANT TO THE SDK LICENSE AGREEMENT, NOVELL HEREBY GRANTS TO DEVELOPER A
 ROYALTY-FREE, NON-EXCLUSIVE LICENSE TO INCLUDE NOVELL'S SAMPLE CODE IN ITS
 PRODUCT. NOVELL GRANTS DEVELOPER WORLDWIDE DISTRIBUTION RIGHTS TO MARKET,
 DISTRIBUTE, OR SELL NOVELL'S SAMPLE CODE AS A COMPONENT OF DEVELOPER'S
 PRODUCTS. NOVELL SHALL HAVE NO OBLIGATIONS TO DEVELOPER OR DEVELOPER'S
 CUSTOMERS WITH RESPECT TO THIS CODE.
****************************************************************************/

import com.novell.service.file.nw.NetwareVolume;
import com.novell.service.file.nw.NetwareDirectory;
import com.novell.service.file.nw.NetwareFile;

import com.novell.service.file.nw.NetwareVolume;
import com.novell.service.file.nw.NetwareDirectory;
import com.novell.service.file.nw.NetwareFile;
import com.novell.service.file.nw.DirectoryEntryInformation;
import com.novell.service.file.nw.Trustee;
import com.novell.service.file.nw.TrusteeEnumerator;
import com.novell.service.file.nw.EAEnumerator;
import com.novell.service.file.nw.ExtendedAttribute;
import com.novell.service.file.nw.DirectorySpaceInformation;
import com.novell.service.file.nw.VolumeInformation;
import com.novell.service.file.nw.VolumeRestrictionEnumerator;
import com.novell.service.file.nw.VolumeRestriction;
import com.novell.service.file.nw.VolumeUtilization;

import com.novell.java.io.NFile;
import com.novell.java.io.RandomAccess;

import com.novell.service.jncp.NSIException;

import java.io.OutputStream;
import java.io.InputStream;
import java.io.IOException;


/** 
 * Declares methods that would handle the various attribute values
 *
 * <p>This class provides common support for several of the file systems
 * example programs.  It is entended to provide and example of utilizing the
 * static attribute value interfaces.
 * </p>
 *
 * @see DirectoryAttrList
 * @see FileAttrList
 * @see VolumeAttrList
 * @see Schema
 */

public class TextualStatic implements StaticAttributeValueInterface
{
   private boolean verbose;
   private Textual text;

   /*
      The following is a known pattern used for streams 
      and random access testing
   */

   private static String[] contents = 
   {
      "line one (offset 0)\r\n",
      "line two (offset 21)\r\n",
      "line three (offset 43)\r\n",
      "line four (offset 67)\r\n",
      "line five (offset 90)\r\n",
      "line six (offset 113)\r\n",
      "line seven (offset 136)\r\n",
      "line eight (offset 161)\r\n",
      "line nine (offset 186)\r\n",
      "line ten (offset 210)\r\n",
      "345678901234567890123456", // 256 characters to here
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234", 
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234", 
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234", 
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234",
      "1234567890123456789012345678901234567890123456789012345678901234" // 2305 total bytes 
   };
   // random access offsets of the first character of each line
   private static int[] offsets = {0, 21, 43, 67, 90, 113, 136, 161, 186, 210};

   /**
    * Constructor that allows for the verbose flag to be set
    * 
    * @param verbose             be verbose if true
    */
    
   public TextualStatic(boolean verbose)
   {
      this.verbose = verbose;  
      text = new Textual(verbose);
   }

   /**
    * Handles objects of type NFile.
    * 
    * <p>The NFile is the base most type of the Meta-data leg of a file. 
    * This method simply demonstrates a handler for these types of objects.  
    * There are no modifiable fields available in the NFile interface.
    *
    * @param file              The NFile object
    *
    * @see com.novell.java.io.NFile
    */
    
   public void handleNFile(NFile file)
   {
      message("lastModified: " + file.lastModified() + "\n");
      message("length: " + file.length() + "\n");
   }

   /**
    * Handles objects of type NetwareFile.
    * 
    * <p>The NetwareFile is the base most type of the Meta-data leg of the
    * NetWare specific file system components. This method simply 
    * demonstrates a handler for these types of objects.  
    *
    * @param file              The NetwareFile object
    *
    * @see com.novell.service.file.nw.NetwareFile
    */
    
   public void handleNetwareFile(NetwareFile file)
   {
      try
      {
         // handle DirectoryEntryInformation
         DirectoryEntryInformation dei = 
            file.getDirectoryEntryInformation();

         text.displayDirectoryEntryInformation(dei);

         // handle EAEnumerator
         handleEAEnumerator(file);

         // handle TrusteeEnumerator
         handleTrusteeEnumerator(file);
      } 
      catch (NSIException nsi)
      {
         System.out.println("handler failed: " + nsi);
         nsi.printStackTrace();
         System.exit(-1);
      }
   }

   /**
    * Handles objects of type NetwareDirectory.
    * 
    * <p>The NetwareDirectory interface extends the NetwareFile interface.
    * This method simply demonstrates a handler for these types of objects.  
    *
    * @param directory           The NetwareDirectory object
    *
    * @see com.novell.service.file.nw.NetwareDirectory
    */
    
   public void handleNetwareDirectory(NetwareDirectory directory)
   {
      // handle the file parts of the directory
      handleNetwareFile((NetwareFile) directory);

      try
      {
         // handle DirectorySpaceInformation
         DirectorySpaceInformation dsi = 
            directory.getDirectorySpaceInformation();

         text.displayDirectorySpaceInformation(dsi);

//         directory.setDirectorySpaceInformation()
         
      } catch (NSIException nsi)
      {
         System.out.println("handler failed: " + nsi);
         nsi.printStackTrace();
         System.exit(-1);
      }
   }

   /**
    * Handles objects of type NetwareVolume.
    * 
    * <p>The NetwareVolume interface extends the NetwareDirectory interface.
    * This method simply demonstrates a handler for these types of objects.  
    *
    * @param volume           The NetwareVolume object
    *
    * @see com.novell.service.file.nw.NetwareVolume
    */
    
   public void handleNetwareVolume(
      NetwareVolume volume,
      String objectName)
   {
      // handle the directory parts of the volume
      handleNetwareDirectory((NetwareDirectory) volume);

      try
      {
         // handle VolumeInformation
         handleVolumeInformation(volume);

         // handle TrusteeEnumerator
         handleVolumeRestrictionEnumerator(volume);
//         volume.setVolumeRestriction();
         
         // handle VolumeUtilization
         handleVolumeUtilization(volume, objectName);
      } 
      catch (NSIException nsi)
      {
         System.out.println("handler failed: " + nsi);
         nsi.printStackTrace();
         System.exit(-1);
      }
   }

   /**
    * Handles the DirectoryEntryInformation attribute value
    * 
    * <p>The DirectoryEntryInformation attribute value can be obtained from 
    * the NetwareFile.getDirectoryEntryInformation factory method.  The 
    * NetwareFile.setDirectoryEntryInformation method is available for 
    * modifying the valid settable fields.
    *
    * <p>This attribute value is available for a NetwareVolume, 
    * NetwareDirectory or NetwareFile object.
    * </p>
    *
    * @param file              The NetwareFile object
    *
    * @see com.novell.service.file.nw.NetwareFile
    * @see com.novell.service.file.nw.DirectoryEntryInformation
    */
    
   public void handleDirectoryEntryInformation(NetwareFile file)
   {
      try
      {
         DirectoryEntryInformation value = 
            file.getDirectoryEntryInformation();
         text.displayDirectoryEntryInformation(value);
      } 
      catch (NSIException nsi)
      {
         System.out.println("handler failed: " + nsi);
         nsi.printStackTrace();
         System.exit(-1);
      }
   }

   /**
    * Handles the TrusteeEnumerator attribute value
    * 
    * <p>The TrusteeEnumerator attribute value can be obtained from 
    * the NetwareFile.getTrusteeEnumerator factory method.  The 
    * NetwareFile.setTrustee method is available for 
    * modifying the valid settable fields.
    *
    * <p>This attribute value is available for a NetwareVolume, 
    * NetwareDirectory or NetwareFile object.
    * </p>
    *
    * @param file              The NetwareFile object
    *
    * @see com.novell.service.file.nw.NetwareFile
    * @see com.novell.service.file.nw.TrusteeEnumerator
    */
    
   public void handleTrusteeEnumerator(NetwareFile file)
   {
      try
      {
         TrusteeEnumerator value = file.getTrusteeEnumerator();
         int count = 0;
         while (value.hasMore())
         {
            text.displayTrustee(value.next());
            ++count;
         }
         message(
            "\t\t" + count + " " + value.ATTRIBUTE_ID + "'s present\n");
      } 
      catch (NSIException nsi)
      {
         System.out.println("handler failed: " + nsi);
         nsi.printStackTrace();
         System.exit(-1);
      }
   }

   /**
    * Handles the EAEnumerator attribute value
    * 
    * <p>The EAEnumerator attribute value can be obtained from 
    * the NetwareFile.getEAEnumerator factory method.  The 
    * NetwareFile.setExtendedAttribute method is available for 
    * modifying the valid settable fields.
    *
    * <p>This attribute value is available for a NetwareVolume, 
    * NetwareDirectory or NetwareFile object.
    * </p>
    *
    * @param file              The NetwareFile object
    *
    * @see com.novell.service.file.nw.NetwareFile
    * @see com.novell.service.file.nw.EAEnumerator
    */
    
   public void handleEAEnumerator(NetwareFile file)
   {
      try
      {
         EAEnumerator value = file.getEAEnumerator();
         int count = 0;
         while (value.hasMore())
         {
            text.displayExtendedAttribute(value.next());
            ++count;
         }
         message(
            "\t\t" + count + " " + value.ATTRIBUTE_ID + "'s present\n");
      } 
      catch (NSIException nsi)
      {
         System.out.println("handler failed: " + nsi);
         nsi.printStackTrace();
         System.exit(-1);
      }
   }

   /**
    * Handles the DirectorySpaceInformation attribute value
    * 
    * <p>The DirectorySpaceInformation attribute value can be obtained from 
    * the NetwareDirectory.getDirectorySpaceInformation factory method.  The 
    * NetwareDirectory.setDirectorySpaceInformation method is available for 
    * modifying the valid settable fields.
    *
    * <p>This attribute value is available for a NetwareVolume or
    * a NetwareDirectory.
    * </p>
    *
    * @param directory              The NetwareDirectory object
    *
    * @see com.novell.service.file.nw.NetwareDirectory
    * @see com.novell.service.file.nw.DirectorySpaceInformation
    */
    
   public void handleDirectorySpaceInformation(
      NetwareDirectory directory)
   {
      try
      {
         DirectorySpaceInformation value = 
            directory.getDirectorySpaceInformation();
         text.displayDirectorySpaceInformation(value);
      } 
      catch (NSIException nsi)
      {
         System.out.println("handler failed: " + nsi);
         nsi.printStackTrace();
         System.exit(-1);
      }
   }

   /**
    * Handles the VolumeInformation attribute value
    * 
    * <p>The VolumeInformation attribute value can be obtained from 
    * the NetwareVolume.getVolumeInformation factory method.  There are no
    * modifiable fields in this attribute value.
    *
    * <p>This attribute value is available for a NetwareVolume.
    * </p>
    *
    * @param volume              The NetwareVolume object
    *
    * @see com.novell.service.file.nw.NetwareVolume
    * @see com.novell.service.file.nw.VolumeInformation
    */
    
   public void handleVolumeInformation(NetwareVolume volume)
   {
      try
      {
         VolumeInformation value = volume.getVolumeInformation();
         text.displayVolumeInformation(value);
      } 
      catch (NSIException nsi)
      {
         System.out.println("handler failed: " + nsi);
         nsi.printStackTrace();
         System.exit(-1);
      }
   }

   /**
    * Handles the volumeRestrictionEnumerator attribute value
    * 
    * <p>The volumeRestrictionEnumerator attribute value can be obtained from 
    * the NetwareVolume.getvolumeRestrictionEnumerator factory method.  The 
    * NetwareVolume.setvolumeRestriction method is available for 
    * modifying the valid settable fields.
    *
    * <p>This attribute value is available for a NetwareVolume.
    * </p>
    *
    * @param volume              The NetwareVolume object
    *
    * @see com.novell.service.file.nw.NetwareVolume
    * @see com.novell.service.file.nw.volumeRestrictionEnumerator
    */
    
   public void handleVolumeRestrictionEnumerator(NetwareVolume volume)
   {
      try
      {
         VolumeRestrictionEnumerator value = 
            volume.getVolumeRestrictionEnumerator();
         int count = 0;
         while (value.hasMore())
         {
            text.displayVolumeRestriction(value.next());
            ++count;
         }
         message(
            "\t\t" + count + " " + value.ATTRIBUTE_ID + "'s present\n");
      } 
      catch (NSIException nsi)
      {
         System.out.println("handler failed: " + nsi);
         nsi.printStackTrace();
         System.exit(-1);
      }
   }

   /**
    * Handles the VolumeUtilization attribute value
    * 
    * <p>The VolumeUtilization attribute value can be obtained from 
    * the NetwareVolume.getVolumeUtilization factory method.  There are no
    * modifiable fields in this attribute value.
    *
    * <p>Volume Utilization is unique in that you must set the object name
    * before you can access any of the other setter or getter methods.  This 
    * is because the utilization information is obtained for the user that 
    * you specify at this time.
    *
    * <p>The JNDI dynamic attribute interface does not allow for the passing
    * of any parameters into the getAttributes interface.  This attribute 
    * value is designed to support the JNDI interface, that is why this
    * is the way it is.
    *
    * <p>This attribute value is available for a NetwareVolume.
    * </p>
    *
    * @param volume              The NetwareVolume object
    * @param objectName          The object name to obtain data on
    *
    * @see com.novell.service.file.nw.NetwareVolume
    * @see com.novell.service.file.nw.VolumeUtilization
    */
    
   public void handleVolumeUtilization(
      NetwareVolume volume,
      String objectName)
   {
      try
      {
         VolumeUtilization value = volume.getVolumeUtilization();

         value.setName(objectName);
         text.displayVolumeUtilization(value);
      } 
      catch (NSIException nsi)
      {
         System.out.println("handler failed: " + nsi);
         nsi.printStackTrace();
         System.exit(-1);
      }
   }

   /**
    * Display a message to the user.  Displaying the value might be 
    * surpressed via a verbose flag in the actual implementation
    * 
    * @param value               value to display to the user
    */
    
   public void message(String value)
   {
      if (verbose)
      {
         System.out.print(value);
      }
   }

   /**
    * Common method to write a known pattern to an output stream.
    * 
    * @param os                  The OutputStream to write the pattern to.
    *
    * @exception IOException if os.write fails.
    */
    
   public void writeStream(OutputStream os)
      throws IOException
   {
      for (int i=0; i < contents.length; i++)
      {
         byte[] data = contents[i].getBytes();
         os.write(data);
      }
   }

   /**
    * Common method to read and verify a known pattern from an input stream.
    * 
    * @param is                  The InputStream to read and verify the
    *                            pattern from.
    *
    * @exception IOException if is.read fails.
    * @exception RuntimeException if pattern does not match.
    */
    
   public void readStream(InputStream is)
      throws IOException, RuntimeException
   {
      for (int i=0; i < contents.length; i++)
      {
         byte[] expected = contents[i].getBytes();
         byte[] received = new byte[expected.length];

         int count = is.read(received);
         if (count != received.length)
         {
            throw new RuntimeException(
               "readStream, read wrong number of characters: exp:" +
               expected.length + " rec: " + count + " value: " + 
               new String(received));
         }
         for (int j=0; j < expected.length; j++)
         {
            if (received[j] != expected[j])
            {
               throw new RuntimeException(
                  "readStream, unexpected character read - exp: " + 
                  expected[j] + " rec: " + received[j] + " at: " + j);
            }
         }
      }
      // see if there is more than expected
      byte[] received = new byte[80]; 
      int count = is.read(received);

      if (count != -1)
      {
         throw new RuntimeException(
            "readStream, stream had data beyond pattern: " +
            new String(received));
      }
   }

   /**
    * Common method to verify a known pattern by random access.
    * 
    * @param ra                  The RandomAccess to read and verify the
    *                            pattern from.
    *
    * @exception IOException if is.read fails.
    * @exception RuntimeException if pattern does not match.
    */
    
   public void readRandom(RandomAccess ra)
      throws IOException, RuntimeException
   {
      for (int i=9; i >= 0; i--)
      {
         byte[] expected = contents[i].getBytes();
         byte[] received = new byte[expected.length];

         ra.setPosition(offsets[i]);
         int count = ra.read(received);
         if (count != received.length)
         {
            throw new RuntimeException(
               "readRandom, read wrong number of characters: exp:" +
               expected.length + " rec: " + count + " value: " + 
               new String(received));
         }

         for (int j=0; j < expected.length; j++)
         {
            if (received[j] != expected[j]){
               throw new RuntimeException(
                  "readRandom, unexpected character read - exp: " + 
                  expected[j] + " rec: " + received[j] + " at: " + j);
            }
         }
      }
   }
}