// Trivalue.java
// (c) COPYRIGHT MIT and INRIA, 1997.
// Please first read the full copyright statement in file COPYRIGHT.html

// The source code is jointly developed by W3C and some of its members
// participating in the Digital Signature Initiative.  The authors are:
//    Mark Champine, HP, <champine@apollo.hp.com>
//    Yang-hua Chu, MIT/W3C, <yhchu@w3.org>
//    Vasanthan Dasan, Sun, <vasanthan.dasan@central.sun.com>
//    Peter Lipp, University of Technology, Graz <plipp@iaik.tu-graz.ac.at>
//    Andreas Sterbenz, U. of Technology, Graz <sterbenz@iaik.tu-graz.ac.at>

package w3c.www.dsig;

/**
 * A class implementing tri-valued logic.
 * Tri-valued logic is boolean logic extended by a third state called
 * 'unknown.' More information about trivalued logic TBD.
 *
 * Objects of this class are inmutable, once generated they cannot
 * be modified.
 *
 * @author Andreas Sterbenz
 * @version 1.0 (last modified 10-October-1997)
 */
public final class Trivalue
{
  /**
   * Int value defined to indicate the state false.
   */
  public final static int TRI_FALSE = 0;
  /**
   * Int value defined to indicate the state true.
   */
  public final static int TRI_TRUE = 1;
  /**
   * Int value defined to indicate the state unknown.
   */
  public final static int TRI_UNKNOWN = 2;

  /**
   * The value of this trivalue. Always one of TRI_FALSE, TRI_TRUE,
   * and TRI_UNKNOWN.
   */
  private int value;

  /**
   * Instance of this class holding a value of false at all times.
   */
  private static final Trivalue OBJ_FALSE = new Trivalue(TRI_FALSE);
  /**
   * Instance of this class holding a value of true at all times.
   */
  private static final Trivalue OBJ_TRUE = new Trivalue(TRI_TRUE);
  /**
   * Instance of this class holding a value of unknown at all times.
   */
  private static final Trivalue OBJ_UNKNOWN = new Trivalue(TRI_UNKNOWN);

  /**
   * Construct a trivalue from the given int. The constants defined
   * in this class for the int are TRI_FALSE, TRI_TRUE, and TRI_UNKNOWN.
   * TRI_UNKNOWN and any other value will a trivalue with the state
   * unknown.
   */
  public Trivalue(int value)
  {
    switch( value ) {

    case TRI_FALSE:
    case TRI_TRUE:
      this.value = value;
      break;

    case TRI_UNKNOWN:
    default:
      this.value = TRI_UNKNOWN;
      break;
    }
  }

  /**
   * Construct a trivalue from the given int. Of course, this will never
   * lead to a trivalue with the value unknown.
   */
  public Trivalue(boolean value)
  {
    this.value = value ? TRI_TRUE : TRI_FALSE;
  }

  /**
   * Construct a trivalue from the given string. The string "true"
   * is mapped to true, "false" to false, all else to unknown.
   */
  public Trivalue(String value)
  {
    this.value = toTrivalue(value);
  }

  /**
   * Return a trivalue with the state true. This method can be
   * used as a short hand for 'new Trivalue(Trivalue.TRI_TRUE).'
   * Additionally, it is more efficient as no new object needs
   * to be generated.
   */
  public static Trivalue newTrue()
  {
    return OBJ_TRUE;
  }

  /**
   * Return a trivalue with the state true. This method can be
   * used as a short hand for 'new Trivalue(Trivalue.TRI_FALSE).'
   * Additionally, it is more efficient as no new object needs
   * to be generated.
   */
  public static Trivalue newFalse()
  {
    return OBJ_FALSE;
  }

  /**
   * Return a trivalue with the state true. This method can be
   * used as a short hand for 'new Trivalue(Trivalue.TRI_UNKNOWN).'
   * Additionally, it is more efficient as no new object needs
   * to be generated.
   */
  public static Trivalue newUnknown()
  {
    return OBJ_UNKNOWN;
  }

  /**
   * Return a trivalue encoded in an int for the string value.
   * The string "true" maps to true, "false" to false, all else
   * to unknown.
   */
  public int toTrivalue(String value)
  {
    if( value == "true" ) {
      return TRI_TRUE;
    } else {
      if( value == "false" ) {
        return TRI_FALSE;
      } else {
        return TRI_UNKNOWN;
      }
    }
  }

  /**
   * Return the trivalue as an int. Possible values for the int are the final
   * variables TRI_TRUE, TRI_FALSE, and TRI_UNKNOWN defined in this
   * class.
   */
  public int getValue()
  {
    return value;
  }

  /**
   * Return the boolean true if this trivalue is true.
   */
  public boolean isTrue()
  {
    return value == TRI_TRUE;
  }

  /**
   * Return the boolean true if this trivalue is false.
   */
  public boolean isFalse()
  {
    return value == TRI_FALSE;
  }

  /**
   * Return the boolean true if this trivalue is unknown.
   */
  public boolean isUnknown()
  {
    return value == TRI_UNKNOWN;
  }

  /**
   * 'Convert' the Trivalue to boolean treating
   * unknown as true. That is, return true if this trivalue
   * is true or unknown, and false if it is false.
   */
  public boolean UnknownToTrue()
  {
    return isTrue() || isUnknown();
  }

  /**
   * 'Convert' the Trivalue to boolean treating
   * unknown as false. That is, return true is this trivalue
   * is true, and false if it is unknown or false.
   */
  public boolean UnknownToFalse()
  {
    return isTrue();
  }

  /**
   * Return the logic not of this trivalue in trivalued logic.
   * true maps to false, false to true, and unknown to unknown.
   */
  public Trivalue not()
  {
    if( isTrue() ) return OBJ_FALSE;
    if( isFalse() ) return OBJ_TRUE;
    return OBJ_UNKNOWN;
  }

  /**
   * Return the logic and of this trivalue and the given trivalue
   * in trivalued logic. That is, return false if any of the two
   * is false, true if both are true, and unknown otherwise.
   */
  public Trivalue and(Trivalue tvalue)
  {
    if( this.isFalse() || tvalue.isFalse() ) {
      return OBJ_FALSE;
    } else if( this.isTrue() && tvalue.isTrue() ) {
      return OBJ_TRUE;
    } else {
      return OBJ_UNKNOWN;
    }
  }

  /**
   * Return the logic and of this trivalue and the given trivalue
   * in trivalued logic. That is, return true if any of the two
   * are true, false if both are false, and unknown otherwise.
   */
  public Trivalue or(Trivalue tvalue)
  {
    if( this.isTrue() || tvalue.isTrue() ) {
      return OBJ_TRUE;
    } else if( this.isFalse() && tvalue.isFalse() ) {
      return OBJ_FALSE;
    } else {
      return OBJ_UNKNOWN;
    }
  }

  /**
   * Test this trivalue and the given object for equality. If the
   * given object is not null, an instance of the trivalue class
   * and it represents the same logic state, return true. Otherwise
   * return false.
   */
  public boolean equals(Object obj)
  {
    if ((obj != null) && (obj instanceof Trivalue)) {
      return value == ((Trivalue)obj).getValue();
    }
    return false;
  }
  
  /**
   * Return a hash code for this trivalue. Using trivalues as keys in a 
   * hashtable does not make much sense as there are only three distinct
   * ones, but this method is included anyway just in case someone needs it.
   */
  public int hashCode()
  {
    return value;
  }

  /**
   * Return a string representation of this trivalue. The state
   * true is represented by the string "true", false by "false," and
   * unknown by "unknown."
   */
  public String toString()
  {
    if( isTrue() ) return "true";
    if( isFalse() ) return "false";
    return "unknown";
  }
}
