/*
 * @(#) GComparator.java - Class for 'greater-than' comparators.
 * (c) 2000 Ivan Maidanski <ivmai@chat.ru> http://ivmai.chat.ru
 * Freeware class library sources. All rights reserved.
 **
 * Language: Java [pure]
 * Tested with: JDK v1.1.6
 * Last modified: 2000-12-27 18:00:00 GMT+03:00
 */

/*
 * This software is the proprietary information of the author.
 **
 * Permission to use, copy, and distribute this software and its
 * documentation for non-commercial purposes and without fee is
 * hereby granted provided that this copyright notice appears in all
 * copies.
 **
 * This software should not be modified in any way; any found bug
 * should be reported to the author.
 **
 * The author disclaims all warranties with regard to this software,
 * including all implied warranties of merchantability and fitness.
 * In no event shall the author be liable for any special, indirect
 * or consequential damages or any damages whatsoever resulting from
 * loss of use, data or profits, whether in an action of contract,
 * negligence or other tortuous action, arising out of or in
 * connection with the use or performance of this software.
 */

package ivmai.util;

import java.io.Serializable;

/**
 * Class for 'greater-than' comparators.
 **
 * A binary predicate, which tests whether the first its argument is
 * greater than the second one, should extend this adapter class and
 * override <CODE>greater(Object, Object)</CODE>, implementing own
 * comparison rules. <CODE>Immutable</CODE> interface is implemented
 * to underline that such comparators must have constant internal
 * state. The comparators may be used in serializable data
 * structures since <CODE>Serializable</CODE> interface is
 * implemented. In addition, this class provides the default
 * comparator for objects of <CODE>Sortable</CODE> interface, and of
 * <CODE>String</CODE> class and of the standard wrappers for the
 * primitive types.
 **
 * @see Sortable
 * @see StrComparator
 **
 * @version 2.0
 * @author Ivan Maidanski
 **
 * @since 1.8
 */
public class GComparator
 implements Immutable, Serializable
{

/**
 * The class version unique identifier for serialization
 * interoperability.
 **
 * @since 1.8
 */
 private static final long serialVersionUID = 1310911848083016948L;

/**
 * The standard comparator for objects.
 **
 * This constant field is initialized with the instantiation of
 * exactly this comparator. The implemented standard comparator
 * correctly orders any two objects of the class which implements
 * <CODE>Sortable</CODE> interface, or both of <CODE>String</CODE>
 * class, or both of the same primary-type value wrapper.
 **
 * @see #greater(java.lang.Object, java.lang.Object)
 */
 public static final GComparator INSTANCE = new GComparator();

/**
 * Constructs a new comparator.
 **
 * This constructor is made <CODE>public</CODE> to allow custom
 * dynamic instantiation of this class.
 **
 * @see #INSTANCE
 */
 public GComparator() {}

/**
 * The body of 'Greater-Than' comparator.
 **
 * Tests whether or not the first specified object is greater than
 * the second one (according to the semantics). This method should
 * be overridden in the adapter subclasses. If any argument is not
 * instance of the expected type then standard comparison should be
 * performed (which is implemented in this method of this class).
 * The standard comparison of two objects is as follows: if
 * <CODE>objA == objB</CODE> then <CODE>false</CODE> is returned
 * else if <VAR>objA</VAR> is instance of <CODE>Sortable</CODE> then
 * <CODE>greaterThan(objB)</CODE> for <VAR>objA</VAR> is returned
 * else if <VAR>objB</VAR> is instance of <CODE>Sortable</CODE> then
 * <CODE>!greaterThan(objA)</CODE> for <VAR>objB</VAR> is returned,
 * else if <VAR>objA</VAR> is <CODE>null</CODE> then
 * <CODE>true</CODE> is returned, else if <VAR>objA</VAR> and
 * <VAR>objB</VAR> are both of the same class (either
 * <CODE>Boolean</CODE>, <CODE>Byte</CODE>, <CODE>Short</CODE>,
 * <CODE>Integer</CODE>, <CODE>Long</CODE>, <CODE>Float</CODE>,
 * <CODE>Double</CODE>, <CODE>Character</CODE> or
 * <CODE>String</CODE>) and the first (primary) value is greater
 * than the second one then <CODE>true</CODE> else
 * <CODE>false</CODE> is returned. Important notes:
 * <CODE>String</CODE> objects are compared here in the
 * case-sensitive manner; <CODE>Float</CODE> and <CODE>Double</CODE>
 * objects are compared here handling their zero and
 * <CODE>NaN</CODE> values specially (<CODE>0</CODE> is greater than
 * <CODE>-0</CODE> and <CODE>NaN</CODE> is greater than
 * non-<CODE>NaN</CODE>).
 **
 * @param objA
 * the first compared argument (may be <CODE>null</CODE>).
 * @param objB
 * the second compared argument (may be <CODE>null</CODE>).
 * @return
 * <CODE>true</CODE> if and only if <VAR>objA</VAR> is greater than
 * <VAR>objB</VAR>.
 **
 * @see #INSTANCE
 */
 public boolean greater(Object objA, Object objB)
 {
  if (objA != objB)
  {
   if (objA instanceof Sortable)
    return ((Sortable)objA).greaterThan(objB);
   if (objB instanceof Sortable)
    return !((Sortable)objB).greaterThan(objA);
   if (objA == null)
    return true;
   if (objB != null)
   {
    if (objA instanceof String)
     return objB instanceof String &&
      ((String)objA).compareTo((String)objB) > 0;
    if (objA instanceof Integer)
     return objB instanceof Integer &&
      ((Integer)objA).intValue() > ((Integer)objB).intValue();
    if (objA instanceof Long)
     return objB instanceof Long &&
      ((Long)objA).longValue() > ((Long)objB).longValue();
    if (objA instanceof Character)
     return objB instanceof Character &&
      ((Character)objA).charValue() > ((Character)objB).charValue();
    if (objA instanceof Short)
     return objB instanceof Short &&
      ((Short)objA).intValue() > ((Short)objB).intValue();
    if (objA instanceof Byte)
     return objB instanceof Byte &&
      ((Byte)objA).intValue() > ((Byte)objB).intValue();
    if (objA instanceof Boolean)
     return objB instanceof Boolean &&
      ((Boolean)objA).booleanValue() &&
      !((Boolean)objB).booleanValue();
    if (objA instanceof Float && objB instanceof Float)
    {
     float floatB = ((Float)objB).floatValue(), floatA;
     return (floatA = ((Float)objA).floatValue()) > floatB ||
      !(floatA < floatB) && Float.floatToIntBits(floatA) >
      Float.floatToIntBits(floatB);
    }
    if (objA instanceof Double && objB instanceof Double)
    {
     double doubleB = ((Double)objB).doubleValue(), doubleA;
     return (doubleA = ((Double)objA).doubleValue()) > doubleB ||
      !(doubleA < doubleB) && Double.doubleToLongBits(doubleA) >
      Double.doubleToLongBits(doubleB);
    }
   }
  }
  return false;
 }
}
