package net.sf.jasperreports.crosstabs.fill.calculation;

import java.util.Comparator;
import net.sf.jasperreports.engine.JRException;
import org.apache.commons.collections.comparators.ReverseComparator;

public class BucketDefinition {
  public static final byte ORDER_ASCENDING = 1;
  
  public static final byte ORDER_DESCENDING = 2;
  
  public static final byte TOTAL_POSITION_NONE = 0;
  
  public static final byte TOTAL_POSITION_START = 1;
  
  public static final byte TOTAL_POSITION_END = 2;
  
  protected static final byte VALUE_TYPE_VALUE = 0;
  
  protected static final byte VALUE_TYPE_NULL = 1;
  
  protected static final byte VALUE_TYPE_TOTAL = 2;
  
  protected final Bucket VALUE_TOTAL = new Bucket((byte)2);
  
  protected final Bucket VALUE_NULL = new Bucket((byte)1);
  
  protected final Comparator comparator;
  
  private final byte totalPosition;
  
  private boolean computeTotal;
  
  public BucketDefinition(Class valueClass, Comparator comparator, byte order, byte totalPosition) throws JRException {
    if (comparator == null && !Comparable.class.isAssignableFrom(valueClass))
      throw new JRException("The bucket expression values are not comparable and no comparator specified."); 
    switch (order) {
      case 2:
        if (comparator == null) {
          this.comparator = (Comparator)new ReverseComparator();
          break;
        } 
        this.comparator = (Comparator)new ReverseComparator(comparator);
        break;
      default:
        this.comparator = comparator;
        break;
    } 
    this.totalPosition = totalPosition;
    this.computeTotal = (totalPosition != 0);
  }
  
  public boolean computeTotal() {
    return this.computeTotal;
  }
  
  public void setComputeTotal() {
    this.computeTotal = true;
  }
  
  public byte getTotalPosition() {
    return this.totalPosition;
  }
  
  public Comparator getComparator() {
    return this.comparator;
  }
  
  public Bucket create(Object value) {
    if (value == null)
      return this.VALUE_NULL; 
    return new Bucket(value);
  }
  
  public class Bucket implements Comparable {
    private final Object value;
    
    private final byte type;
    
    private final BucketDefinition this$0;
    
    protected Bucket(byte type) {
      this.value = null;
      this.type = type;
    }
    
    protected Bucket(Object value) {
      this.value = value;
      this.type = 0;
    }
    
    public Object getValue() {
      return this.value;
    }
    
    public boolean equals(Object o) {
      if (o == null || !(o instanceof Bucket))
        return false; 
      if (o == this)
        return true; 
      Bucket v = (Bucket)o;
      if (this.type != 0)
        return (this.type == v.type); 
      return (v.type == 0 && this.value.equals(v.value));
    }
    
    public int hashCode() {
      int hash = this.type;
      if (this.type == 0)
        hash = 37 * hash + this.value.hashCode(); 
      return hash;
    }
    
    public String toString() {
      switch (this.type) {
        case 1:
          return "NULL";
        case 2:
          return "TOTAL";
      } 
      return String.valueOf(this.value);
    }
    
    public int compareTo(Object o) {
      Bucket val = (Bucket)o;
      if (this.type != val.type)
        return this.type - val.type; 
      if (this.type != 0)
        return 0; 
      if (BucketDefinition.this.comparator != null)
        return BucketDefinition.this.comparator.compare(this.value, val.value); 
      return ((Comparable)this.value).compareTo(val.value);
    }
    
    public boolean isTotal() {
      return (this.type == 2);
    }
  }
}
