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

  $Archive: /njcl_v2/src/com/novell/service/nds/NdsOctetList.java $
  $Revision: 9 $
  $Modtime: 10/15/99 3:35p $
 
  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.nds;


import java.io.Serializable;

import java.util.Enumeration;
import java.util.Vector;

import com.novell.service.schema.SchemaSequence;


/**
 * Provides access to values of the OctetList attribute.
 * It is used for attributes that are ordered sequences of octet
 * strings.
 *
 * <p>A presented octet list matches a stored list if the
 * presented list is a subset of the stored list. Octet strings
 * are so designated because they are not interpreted by NDS.
 * They are simply a series of bits with no Unicode 
 * implications. The Approximate Equals matching rule, as well as
 * the Equallity matching rule, applies because when comparing two
 * octet lists, only one octet string in the list needs to match.
 * 
 * <p>Matching Rules: Equality and Approximate Equals</p>
 *
 * @see NdsSyntaxId
 */
public class NdsOctetList
   implements NdsAttributeValue, SchemaSequence, Cloneable, Serializable
{
   private static final int matchingRules = equality|approximate;

  /**
   * @internal
   */
   protected byte[][] values;

   private String name;

  /**
   * Constructs an NdsOctetList object based on the specified
   * value variable.
   * 
   * @param value  The octet list to be stored as a two-dimensional
   *               byte array.
   */
   public NdsOctetList(byte[][] value)
   {
      this ("", value);
   }

  /**
   * @internal
   */
   protected NdsOctetList ()
   {
      values = null;
   }

  /**
   * @internal
   */
   protected NdsOctetList (
         String name,
         byte[][] value)
   {
      this.values = new byte[value.length][];

      for (int i = 0; i < value.length; i++)
      {
         this.values[i] = (byte []) value[i].clone ();
      }
      this.name = name;
   }

  /**
   * @internal
   */
   protected NdsOctetList (
         NdsOctetList anOctetList)
   {
      this.values = anOctetList.values;
      this.name = anOctetList.name;
   }


   // ******************** SchemaValue Interface ********************

  /**
   * Compares two objects for ordering, or compares two strings
   * lexicographically.
   *
   * The compareTo method does not apply to the NdsOctetList syntax
   * because this syntax does not support the ordering and substrings
   * matching rules.
   */
   public int compareTo (
         Object anObject)
      throws Exception
   {
      throw (new Exception ());
   }

   private boolean compareByteArray (
         byte[] pattern,
         byte[] target)
   {
      if (pattern.length == target.length)
      {
         for (int i = 0; i < pattern.length; i++)
         {
            if (pattern[i] != target[i])
            {
               return false;
            }
         }
         return true;
      }
      return false;
   }

  /**
   * Compares two Objects for equality. The equals method compares
   * this object value with the value of the reference object in
   * the anObject parameter.
   *
   * <p>The equals method implements the most discriminating possible
   * equivalence relation on objects; that is, for any reference values
   * X and Y, this method returns TRUE if and only if X and Y refer to
   * the same object (X==Y has the value TRUE).</p>
   * 
   * @param anObject The reference object with which to compare.
   *
   * @return A boolean set to TRUE if and only if the argument is not
   *         NULL and is an NDS integer object that contains the
   *         same value as this object, otherwise set to FALSE.
   */
   public boolean equals (
         Object anObject)
   {
      if (anObject instanceof NdsOctetList)
      {
         if (values.length == ((NdsOctetList) anObject).count ())
         {
            byte[][] target = ((NdsOctetList) anObject).getOctetList ();
            
            for (int i = 0; i < values.length; i++)
            {
               if (compareByteArray (values[i], target[i]) == false)
               {
                  return false;
               }
            }
            return true;
         }
      }
      return false;
   }

  /**
   * @internal
   */
   public String getName ()
   {
      return (name);
   }

  /**
   * @internal
   */
   public String getSyntaxId ()
   {
      return (NdsSyntaxId.OCTET_LIST);
   }


   // ******************** SchemaSequence Interface ********************

   /**
    * Returns the number of elements in this sequence.
    *
    * @return The number of elements in this sequence as an int.
    */
   public int count ()
   {
      return (values.length);
   }

   /**
    * Returns an enumeration of this sequence's values.
    *
    * @return An enumeration of value elements.
    */
   public Enumeration getValues ()
   {
      Vector vector = new Vector ();

      for (int i = 0; i < values.length; i++)
      {
         vector.addElement (values[i]);
      }
      return (vector.elements ());
   }


   // ******************** NdsAttributeValue Interface ********************

  /**
   * Compares two Objects using the approximate matching rule. It
   * compares this object with the reference object in the anObject
   * parameter.
   *
   * <p>When comparing two Octet lists, only one octet string of the
   * list need match.
   * 
   * @param anObject The reference object with which to compare.
   *
   * @return A Boolean set to TRUE if any argument is not equal to
   *         NULL, otherwise set to FALSE.
   *
   * @exception NsiException The approximate() method is not supported
   *            for this syntax.
   */
   public boolean approximate (
         Object anObject)
   {
      if (anObject instanceof NdsOctetList)
      {
         int patCount = this.values.length;
         int tarCount = ((NdsOctetList)anObject).count ();
         
         byte[][] target = ((NdsOctetList)anObject).getOctetList ();
         
         while (patCount > 0 && tarCount > 0)
         {
            byte[] pat = (byte[]) values[patCount];
            byte[] tar = target[tarCount];
            
            if (compareByteArray(pat, tar))
            {
               --patCount;
            }
            --tarCount;
         }
         return patCount == 0 ? true : false;
      }
      return false;
   }

  /**
   * Returns the int that represents this NDS syntax ID.
   *
   * @return The syntax ID as an int.
   */
   public int getNdsSyntaxId ()
   {
      return (NdsSyntaxId.OCTET_LIST_ID);
   }

  /**
   * Checks to see if this object supports the specified
   * matching rules. The Octet List syntax supports both the
   * Equality and Approximate Equals matching rules.
   *
   * @param matchingRules The set of matching rules to check.
   *
   * @return A Boolean set to TRUE if the matching rules for this
   *         object are equal to the matchingRules parameter.
   */
   public boolean supportsMatchingRules (
         int matchingRules)
   {
      if ((matchingRules & this.matchingRules) == matchingRules)
      {
         return (true);
      }
      return (false);
   }


   // ******************** Object Class ********************

  /**
   * Creates a new object of the same class as this object. It
   * then initializes each of the new object's fields by assigning
   * them the same value as the corresponding fields in this object.
   * No constructor is called.
   *
   * @return A clone of this object instance containing the cloned
   *         syntax.
   */
   public Object clone ()
   {
      try
      {
         NdsOctetList list = (NdsOctetList) super.clone ();

         list.values = (byte[][]) this.values.clone ();

         list.name = this.name;

         return (list);
      }
      catch (CloneNotSupportedException e)
      {
         // this shouldn't happen, since we are Cloneable
         throw (new InternalError ());
      }

   } /* clone () */

  /**
   * Generates a string representation of the object. It
   * returns a string that textually represents the object.
   * The result should be a concise but informative
   * representation that is easy to read.
   *
   * @return The String representation of the object.
   */
   public String toString ()
   {
      return (values.toString ());
   }


   // ******************** NdsOctetList Class ********************

  /**
   * Returns the byte array of Octet List values stored in
   * the NDS attribute.
   *
   * @return A byte array of Octet List values.
   */
   public byte[][] getOctetList ()
   {
      int length = values.length;
      byte[][] list = new byte[length][];

      for (int i = 0; i < length; i++)
      {
         byte[] entry = (byte[]) values[i];

         list[i] = new byte[entry.length];
         System.arraycopy (entry, 0, list[i], 0, entry.length);
      }
      return (list);

   } /* getOctetList () */

} /* NdsOctetList */


